@open-slot-ui/pixi 0.8.3 → 0.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/art.js +1 -1
- package/dist/{chunk-PYXZIGXG.js → chunk-Z7X5JH7H.js} +7 -4
- package/dist/chunk-Z7X5JH7H.js.map +1 -0
- package/dist/index.cjs +85 -13
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +84 -15
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
- package/dist/chunk-PYXZIGXG.js.map +0 -1
package/dist/index.cjs
CHANGED
|
@@ -208,6 +208,9 @@ var SpinView = class extends ControlView {
|
|
|
208
208
|
}),
|
|
209
209
|
// re-dim if slam-stop is toggled at runtime (e.g. applyJurisdiction)
|
|
210
210
|
this.spin.allowSlamStop.subscribe(() => this.updateInteractive()),
|
|
211
|
+
// the ref-counted HUD lock (menu / buy modal / blocking notice) gates
|
|
212
|
+
// `spin.interactable` — refresh eventMode/cursor when it flips
|
|
213
|
+
this.ui.locked.subscribe(() => this.updateInteractive()),
|
|
211
214
|
this.spin.onTransition((t) => this.play(t)),
|
|
212
215
|
// free-spins face: switch between the normal skin and the "N FS" counter
|
|
213
216
|
this.spin.freeSpins.subscribe(() => this.updateFaces()),
|
|
@@ -3104,7 +3107,7 @@ var ReadoutView = class extends ControlView {
|
|
|
3104
3107
|
let text;
|
|
3105
3108
|
switch (this.ro.kind) {
|
|
3106
3109
|
case "currency":
|
|
3107
|
-
text = this.ro.currency ? core.
|
|
3110
|
+
text = this.ro.currency ? core.formatAmountPrecise(v, this.ro.currency.get(), { signed: this.ro.signed }) : String(v);
|
|
3108
3111
|
break;
|
|
3109
3112
|
case "percent":
|
|
3110
3113
|
text = `${v.toFixed(this.ro.decimals)}%`;
|
|
@@ -3987,7 +3990,11 @@ var PanelBodyView = class extends ControlView {
|
|
|
3987
3990
|
};
|
|
3988
3991
|
var esc = (s) => s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
3989
3992
|
var rich = (s) => esc(s).replace(/\*\*(.+?)\*\*/g, "<b>$1</b>");
|
|
3990
|
-
function
|
|
3993
|
+
function statGridHtml(items, tr) {
|
|
3994
|
+
const rows = items.map((it) => `<div><dt>${esc(tr(it.label))}</dt><dd>${esc(tr(it.value))}</dd></div>`).join("");
|
|
3995
|
+
return `<dl class="ohm-stats">${rows}</dl>`;
|
|
3996
|
+
}
|
|
3997
|
+
function renderBlocks(blocks, tr, facts) {
|
|
3991
3998
|
const out = [];
|
|
3992
3999
|
for (const b of blocks) {
|
|
3993
4000
|
switch (b.kind) {
|
|
@@ -4029,9 +4036,16 @@ function renderBlocks(blocks, tr) {
|
|
|
4029
4036
|
out.push(`<table class="ohm-table">${head}<tbody>${body}</tbody></table>`);
|
|
4030
4037
|
break;
|
|
4031
4038
|
}
|
|
4032
|
-
case "stat-grid":
|
|
4033
|
-
|
|
4034
|
-
|
|
4039
|
+
case "stat-grid":
|
|
4040
|
+
out.push(statGridHtml(b.items, tr));
|
|
4041
|
+
break;
|
|
4042
|
+
// The AUTO per-mode RTP / Max-win grid — rendered straight from the declared
|
|
4043
|
+
// game facts (+ any host extras), so the table can never drift from the config.
|
|
4044
|
+
// `modeStatsItems` localizes the label PARTS itself ("Max win" · the mode name),
|
|
4045
|
+
// so the grid renderer gets identity-tr — no double translation.
|
|
4046
|
+
case "mode-stats": {
|
|
4047
|
+
const extras = (b.extras ?? []).map((e) => ({ label: tr(e.label), value: tr(e.value) }));
|
|
4048
|
+
out.push(statGridHtml([...core.modeStatsItems(facts, tr), ...extras], (s) => s));
|
|
4035
4049
|
break;
|
|
4036
4050
|
}
|
|
4037
4051
|
case "steps": {
|
|
@@ -4101,8 +4115,30 @@ function mountInfoMenu(app, ui) {
|
|
|
4101
4115
|
const soundMode = menu.sound ?? "sliders";
|
|
4102
4116
|
const volRow = (id, label, hint, val) => `<div class="ohm-setting"><label class="ohm-row"><span>${esc(tr(label))}</span><input class="ohm-slider" data-vol="${id}" type="range" min="0" max="1" step="0.01" value="${val}"></label><div class="ohm-hint">${esc(tr(hint))}</div></div>`;
|
|
4103
4117
|
const soundSliders = soundMode === "master" ? volRow("master", "Volume", "Adjust the overall game volume.", ui.sfxSlider.value.get()) : soundMode === "sliders" ? volRow("music", "Music", "Adjust the background music volume.", ui.musicSlider.value.get()) + volRow("sfx", "Effects", "Adjust the sound-effects volume.", ui.sfxSlider.value.get()) : "";
|
|
4104
|
-
const
|
|
4105
|
-
|
|
4118
|
+
const rulesTr = () => {
|
|
4119
|
+
const vars2 = core.factsVars(ui.facts.get(), { "game.name": ui.gameInfo.name ?? "", "game.version": ui.gameInfo.version ?? "" });
|
|
4120
|
+
return (s) => ui.t(s, vars2);
|
|
4121
|
+
};
|
|
4122
|
+
const auditCardHtml = (trr) => {
|
|
4123
|
+
if (!menu.rules?.length) return "";
|
|
4124
|
+
const issues = core.auditRules(ui.facts.get(), menu.rules, { resolve: trr });
|
|
4125
|
+
if (!issues.length) return "";
|
|
4126
|
+
const req = issues.filter((i) => i.level === "required");
|
|
4127
|
+
const rec = issues.filter((i) => i.level === "recommended");
|
|
4128
|
+
const list = (items) => `<ul>${items.map((i) => `<li>${esc(tr(i.message))}</li>`).join("")}</ul>`;
|
|
4129
|
+
return `<div class="ohm-audit" role="alert">
|
|
4130
|
+
<div class="ohm-audit-title">\u26A0 ${esc(tr("openui.rulesAudit.title"))}</div>
|
|
4131
|
+
${req.length ? `<div class="ohm-audit-sub">${esc(tr("openui.rulesAudit.required"))}</div>${list(req)}` : ""}
|
|
4132
|
+
${rec.length ? `<div class="ohm-audit-sub ohm-audit-sub--rec">${esc(tr("openui.rulesAudit.recommended"))}</div><div class="ohm-audit-rec">${list(rec)}</div>` : ""}
|
|
4133
|
+
</div>`;
|
|
4134
|
+
};
|
|
4135
|
+
const rulesInnerHtml = () => {
|
|
4136
|
+
if (!menu.rules) return "";
|
|
4137
|
+
const trr = rulesTr();
|
|
4138
|
+
return auditCardHtml(trr) + renderBlocks(menu.rules, trr, ui.facts.get());
|
|
4139
|
+
};
|
|
4140
|
+
const paytableHtml = menu.paytable ? renderBlocks(menu.paytable, tr, ui.facts.get()) : "";
|
|
4141
|
+
const rulesHtml = rulesInnerHtml();
|
|
4106
4142
|
const banner = menu.banner ? `<img class="ohm-logo" alt="" src="${menu.banner.src}"${menu.banner.width ? ` width="${menu.banner.width}"` : ""}${menu.banner.height ? ` height="${menu.banner.height}"` : ""}>` : ui.gameInfo.name ? `<h1 class="ohm-logo-text">${esc(ui.gameInfo.name)}</h1>` : "";
|
|
4107
4143
|
host2.innerHTML = `
|
|
4108
4144
|
<div class="ohm-backdrop" data-close></div>
|
|
@@ -4174,19 +4210,40 @@ function mountInfoMenu(app, ui) {
|
|
|
4174
4210
|
else if (el instanceof HTMLSelectElement) el.addEventListener("change", () => ui.bus.emit("optionSelected", { id, value: el.value, index: el.selectedIndex }));
|
|
4175
4211
|
});
|
|
4176
4212
|
host2.querySelectorAll("[data-close]").forEach((b) => b.addEventListener("click", () => ui.settingsPanel.closePanel()));
|
|
4213
|
+
const refreshRules = () => {
|
|
4214
|
+
const rulesEl = host2.querySelector("#ohm-rules");
|
|
4215
|
+
if (rulesEl && menu.rules) rulesEl.innerHTML = rulesInnerHtml();
|
|
4216
|
+
};
|
|
4177
4217
|
disposers.push(
|
|
4178
4218
|
ui.locale.subscribe(() => {
|
|
4179
4219
|
const body = host2.querySelector(".ohm-body");
|
|
4180
4220
|
if (body) {
|
|
4181
|
-
|
|
4182
|
-
if (rulesEl && menu.rules) rulesEl.innerHTML = renderBlocks(menu.rules, tr);
|
|
4221
|
+
refreshRules();
|
|
4183
4222
|
if (lang) lang.value = ui.locale.get();
|
|
4184
4223
|
}
|
|
4224
|
+
}),
|
|
4225
|
+
ui.facts.subscribe(refreshRules)
|
|
4226
|
+
);
|
|
4227
|
+
let menuLocked = false;
|
|
4228
|
+
disposers.push(
|
|
4229
|
+
ui.settingsPanel.state.subscribe(() => {
|
|
4230
|
+
const isOpen = ui.settingsPanel.isOpen;
|
|
4231
|
+
host2.classList.toggle("open", isOpen);
|
|
4232
|
+
if (isOpen && !menuLocked) {
|
|
4233
|
+
ui.lock();
|
|
4234
|
+
menuLocked = true;
|
|
4235
|
+
} else if (!isOpen && menuLocked) {
|
|
4236
|
+
ui.unlock();
|
|
4237
|
+
menuLocked = false;
|
|
4238
|
+
}
|
|
4185
4239
|
})
|
|
4186
4240
|
);
|
|
4187
|
-
disposers.push(ui.settingsPanel.state.subscribe(() => host2.classList.toggle("open", ui.settingsPanel.isOpen)));
|
|
4188
4241
|
return () => {
|
|
4189
4242
|
for (const d of disposers.splice(0)) d();
|
|
4243
|
+
if (menuLocked) {
|
|
4244
|
+
ui.unlock();
|
|
4245
|
+
menuLocked = false;
|
|
4246
|
+
}
|
|
4190
4247
|
host2.remove();
|
|
4191
4248
|
};
|
|
4192
4249
|
}
|
|
@@ -4240,6 +4297,13 @@ var OHM_CSS = `
|
|
|
4240
4297
|
.ohm-stats { margin: 12px 0; display: grid; grid-template-columns: 1fr 1fr; gap: 0 28px; }
|
|
4241
4298
|
.ohm-stats > div { display: flex; justify-content: space-between; padding: 9px 0; border-bottom: 1px solid color-mix(in srgb, var(--text-dim) 20%, transparent); }
|
|
4242
4299
|
.ohm-stats dt { color: var(--text-dim); margin: 0; } .ohm-stats dd { margin: 0; font-weight: 700; }
|
|
4300
|
+
.ohm-audit { margin: 12px 0 18px; padding: 14px 16px; border-radius: 12px; border: 2px solid #d03131; background: color-mix(in srgb, #d03131 8%, transparent); }
|
|
4301
|
+
.ohm-audit-title { font-weight: 900; letter-spacing: .5px; color: #b31d1d; }
|
|
4302
|
+
.ohm-audit-sub { margin-top: 8px; font-size: 13px; font-weight: 800; color: #b31d1d; }
|
|
4303
|
+
.ohm-audit-sub--rec { color: #b07d09; }
|
|
4304
|
+
.ohm-audit ul { margin: 6px 0 0; padding-left: 20px; color: var(--text); font-size: 13.5px; line-height: 1.55; }
|
|
4305
|
+
.ohm-audit li { margin: 3px 0; }
|
|
4306
|
+
.ohm-audit-rec ul { color: var(--text-dim); }
|
|
4243
4307
|
.ohm-callout { margin: 16px 0 4px; padding: 14px 16px; border-radius: 12px; border-left: 4px solid var(--accent); background: color-mix(in srgb, var(--accent) 9%, transparent); }
|
|
4244
4308
|
.ohm-callout b { color: var(--accent); } .ohm-callout p { margin: 4px 0 0; color: var(--text); }
|
|
4245
4309
|
.ohm-callout--warning { border-left-color: #e0a106; background: color-mix(in srgb, #e0a106 10%, transparent); }
|
|
@@ -4329,7 +4393,7 @@ var CONFIRM_CSS = `
|
|
|
4329
4393
|
// src/mountHud.ts
|
|
4330
4394
|
function showReplayModal(ui, info, buttonKey, onSelect) {
|
|
4331
4395
|
const cur = info.currency ?? ui.balance.currency.get();
|
|
4332
|
-
const money2 = (n) => core.
|
|
4396
|
+
const money2 = (n) => core.formatAmountPrecise(n, cur);
|
|
4333
4397
|
ui.showNotice(
|
|
4334
4398
|
[
|
|
4335
4399
|
{ kind: "heading", id: "openui-replay-h", text: "openui.replay.title" },
|
|
@@ -4467,13 +4531,14 @@ function mountHud(app, spec = {}, opts = {}) {
|
|
|
4467
4531
|
};
|
|
4468
4532
|
}
|
|
4469
4533
|
function money(amount, cur) {
|
|
4470
|
-
return core.
|
|
4534
|
+
return core.formatAmountPrecise(amount, cur);
|
|
4471
4535
|
}
|
|
4472
4536
|
var esc3 = (s) => s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
4473
4537
|
function mountBuyFeatureModal(_app, hud, features, opts = {}) {
|
|
4474
4538
|
const ui = hud.ui;
|
|
4475
4539
|
const tr = (k) => ui.t(k);
|
|
4476
4540
|
const list = features.slice(0, 4);
|
|
4541
|
+
ui.declareFacts({ modes: list.map((f) => ({ id: f.id, name: f.name, kind: f.variant, cost: f.cost })) });
|
|
4477
4542
|
const boosts = /* @__PURE__ */ new Set();
|
|
4478
4543
|
const activation = opts.activation ?? "multi";
|
|
4479
4544
|
const blocksBuy = opts.activationBlocksBuy ?? false;
|
|
@@ -4596,10 +4661,16 @@ function mountBuyFeatureModal(_app, hud, features, opts = {}) {
|
|
|
4596
4661
|
$("#bfm-plus").addEventListener("click", () => ui.betStepper.inc());
|
|
4597
4662
|
disposers.push(ui.bet.value.subscribe(() => renderCards()));
|
|
4598
4663
|
const open = () => {
|
|
4664
|
+
if (host2.classList.contains("open")) return;
|
|
4599
4665
|
renderCards();
|
|
4600
4666
|
host2.classList.add("open");
|
|
4667
|
+
ui.lock();
|
|
4668
|
+
};
|
|
4669
|
+
const close = () => {
|
|
4670
|
+
if (!host2.classList.contains("open")) return;
|
|
4671
|
+
host2.classList.remove("open");
|
|
4672
|
+
ui.unlock();
|
|
4601
4673
|
};
|
|
4602
|
-
const close = () => host2.classList.remove("open");
|
|
4603
4674
|
host2.querySelectorAll("[data-close]").forEach((b) => b.addEventListener("click", close));
|
|
4604
4675
|
disposers.push(ui.on("buttonActivated", ({ id }) => {
|
|
4605
4676
|
if (id === "bonus") open();
|
|
@@ -4617,6 +4688,7 @@ function mountBuyFeatureModal(_app, hud, features, opts = {}) {
|
|
|
4617
4688
|
renderCards();
|
|
4618
4689
|
return () => {
|
|
4619
4690
|
window.removeEventListener("resize", onResize);
|
|
4691
|
+
if (host2.classList.contains("open")) ui.unlock();
|
|
4620
4692
|
for (const d of disposers.splice(0)) d();
|
|
4621
4693
|
host2.remove();
|
|
4622
4694
|
};
|