Turfwar/html/apperance.js
2026-02-12 11:58:03 +00:00

385 lines
9.7 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

console.log("[ATM UI] atm.js loaded");
console.log("[NUI] loaded");
// =====================
// DOM refs
// =====================
const wrap = document.getElementById("wrap");
const cashEl = document.getElementById("cash");
const bankEl = document.getElementById("bank");
const amountEl = document.getElementById("amount");
const btnDeposit = document.getElementById("btnDeposit");
const btnWithdraw = document.getElementById("btnWithdraw");
const btnClose = document.getElementById("btnClose");
// Gang Bank HUD
const gbHud = document.getElementById("gangbankHud");
const gbAmount = document.getElementById("gbAmount");
const gbLabel = document.getElementById("gbLabel");
// Capture HUD
const capHud = document.getElementById("captureHud");
const capTitle = document.getElementById("capTitle");
const capFill = document.getElementById("capFill");
const capSub = document.getElementById("capSub");
const capBar = document.getElementById("capBar");
// Leaderboard HUD
const lbHud = document.getElementById("leaderboardHud");
const lbTitle = document.getElementById("lbTitle");
const lbRows = document.getElementById("lbRows");
const lbError = document.getElementById("lbError");
// =====================
// State
// =====================
let lastGangBank = null;
// =====================
// Helpers
// =====================
function fmt(n) {
n = Number(n || 0);
if (!Number.isFinite(n)) n = 0;
return "$" + Math.floor(n).toLocaleString();
}
function post(name, data = {}) {
try {
fetch(`https://${GetParentResourceName()}/${name}`, {
method: "POST",
headers: { "Content-Type": "application/json; charset=UTF-8" },
body: JSON.stringify(data)
}).catch(() => {});
} catch (e) {
console.log("[ATM UI] post failed:", name, e);
}
}
function getAmount() {
const v = Number(amountEl?.value || 0);
if (!Number.isFinite(v)) return 0;
return Math.floor(v);
}
// =====================
// ATM UI
// =====================
function hideATM() {
wrap?.classList.add("hidden");
}
function showATM() {
wrap?.classList.remove("hidden");
setTimeout(() => amountEl?.focus(), 0);
}
// ========================
// Turf Capture HUD (fixed)
// ========================
function capShow() {
capHud?.classList.remove("cap-hidden");
}
function capHide() {
capHud?.classList.add("cap-hidden");
if (capFill) capFill.style.width = "0%";
if (capSub) capSub.textContent = "0%";
}
function capStart(titleText) {
capShow();
if (capTitle) capTitle.textContent = titleText || "Capturing…";
capSet(0);
}
function capSet(t) {
t = Math.max(0, Math.min(1, Number(t || 0)));
const pct = Math.round(t * 100);
if (capFill) capFill.style.width = pct + "%";
if (capSub) capSub.textContent = pct + "%";
}
/**
* Capture styling:
* - fillCss = contesting/capturing gang
* - bgCss = outgoing/current owner gang
*/
function capStyle(fillCss, bgCss) {
if (capFill && fillCss) capFill.style.background = fillCss;
if (capBar && bgCss) capBar.style.background = bgCss;
}
function capPaused(isPaused) {
if (!capSub) return;
if (isPaused) capSub.textContent = "PAUSED";
}
// ========================
// Leaderboard HUD
// ========================
function lbShow() {
lbHud?.classList.remove("lb-hidden");
}
function lbHide() {
lbHud?.classList.add("lb-hidden");
}
function lbRender(payload) {
if (!payload) return;
lbShow();
if (lbTitle) lbTitle.textContent = String(payload.title || "Most influence");
// Error display (optional)
if (payload.error) {
if (lbError) {
lbError.textContent = String(payload.error);
lbError.classList.remove("lb-hidden");
}
} else {
lbError?.classList.add("lb-hidden");
if (lbError) lbError.textContent = "";
}
if (!lbRows) return;
lbRows.innerHTML = "";
const rows = Array.isArray(payload.rows) ? payload.rows : [];
rows.forEach((r) => {
const gangId = Number(r.gangId);
const name = String(r.name ?? "Unknown");
const val = Number(r.value ?? 0);
// 🚫 Skip Police
if (gangId === 3) return;
// --- Color handling ---
const rgb = Array.isArray(r.rgb) ? r.rgb : [255, 255, 255];
let R = Number(rgb[0]);
let G = Number(rgb[1]);
let B = Number(rgb[2]);
// Fallback safety
if (!Number.isFinite(R)) R = 255;
if (!Number.isFinite(G)) G = 255;
if (!Number.isFinite(B)) B = 255;
// Brighten very dark colors only (Lost Gang)
if (R < 80 && G < 80 && B < 80) {
R = Math.min(255, R + 80);
G = Math.min(255, G + 80);
B = Math.min(255, B + 80);
}
const div = document.createElement("div");
div.className = "lb-row";
div.innerHTML = `
<span class="lb-name" style="color: rgb(${R}, ${G}, ${B});">
${escapeHtml(name)}
</span>
<span class="lb-val">${Number.isFinite(val) ? val : 0}</span>
`;
lbRows.appendChild(div);
});
}
function escapeHtml(s) {
return String(s)
.replaceAll("&", "&amp;")
.replaceAll("<", "&lt;")
.replaceAll(">", "&gt;")
.replaceAll('"', "&quot;")
.replaceAll("'", "&#039;");
}
function setGangBankColor(rgb) {
if (!gbLabel) return;
const arr = Array.isArray(rgb) ? rgb : [255, 255, 255];
let R = Number(arr[0]);
let G = Number(arr[1]);
let B = Number(arr[2]);
if (!Number.isFinite(R)) R = 255;
if (!Number.isFinite(G)) G = 255;
if (!Number.isFinite(B)) B = 255;
// Brighten very dark colors (e.g. Lost Gang)
if (R < 80 && G < 80 && B < 80) {
R = Math.min(255, R + 80);
G = Math.min(255, G + 80);
B = Math.min(255, B + 80);
}
const css = `rgb(${R}, ${G}, ${B})`;
// Apply to label (and optionally amount if you want later)
gbLabel.style.setProperty("--gang-color", css);
gbLabel.style.color = "var(--gang-color)"; // ensures it shows even if CSS missing
}
// =====================
// Boot
// =====================
document.addEventListener("DOMContentLoaded", () => {
hideATM();
capHide(); // ✅ was capStop() in your file (but didnt exist)
lbHide(); // start hidden until first update
console.log("[ATM UI] DOMContentLoaded -> posting atm:ready");
post("atm:ready");
});
// =====================
// Button wiring
// =====================
btnDeposit?.addEventListener("click", () => {
const amount = getAmount();
if (amount > 0) post("atm:deposit", { amount });
});
btnWithdraw?.addEventListener("click", () => {
const amount = getAmount();
if (amount > 0) post("atm:withdraw", { amount });
});
btnClose?.addEventListener("click", () => post("atm:close"));
document.addEventListener("keydown", (e) => {
if (e.key === "Escape") post("atm:close");
});
// =====================
// NUI messages (single listener)
// =====================
window.addEventListener("message", (event) => {
const data = event.data || {};
const type = data.type;
if (!type) return;
// Capture debug (optional)
if (type.startsWith("capture:")) {
// console.log("[NUI] capture msg", data);
}
switch (type) {
// -------- ATM --------
case "atm:open":
showATM();
break;
case "atm:close":
hideATM();
break;
case "atm:balances":
if (cashEl) cashEl.textContent = fmt(data.cash);
if (bankEl) bankEl.textContent = fmt(data.bank);
break;
// ---- Gang Bank HUD ----
case "gangbank:show":
gbHud?.classList.remove("gb-hidden");
break;
case "gangbank:hide":
gbHud?.classList.add("gb-hidden");
break;
case "gangbank:label": {
if (gbLabel) gbLabel.textContent = String(data.label || "Gang Bank");
// ✅ set color if provided
if (data.rgb) setGangBankColor(data.rgb);
break;
}
case "gangbank:update": {
if (!gbAmount) break;
const amt = Number(data.balance ?? data.amount ?? 0);
gbAmount.textContent = fmt(amt);
// ✅ also accept rgb here (in case update is the only message carrying it)
if (data.rgb) setGangBankColor(data.rgb);
// pulse only if changed
if (lastGangBank !== null && amt !== lastGangBank) {
gbAmount.classList.remove("gb-pulse");
void gbAmount.offsetWidth; // restart animation
gbAmount.classList.add("gb-pulse");
}
lastGangBank = amt;
break;
}
// ---- Turf Capture HUD ----
case "capture:start":
capStart(data.turfName || data.title || "Capturing…");
if (data.t !== undefined) capSet(data.t);
if (data.fill || data.bg) capStyle(data.fill, data.bg);
break;
case "capture:set":
capShow();
capSet(data.t);
break;
case "capture:style":
capStyle(data.fill, data.bg);
break;
case "capture:paused":
capPaused(!!data.paused);
break;
case "capture:hint":
if (capSub && data.text) {
capSub.textContent = String(data.text);
setTimeout(() => {
// only clear if still showing the same hint-like text
if (capSub && capSub.textContent === String(data.text)) {
capSub.textContent = "";
}
}, 1500);
}
break;
case "capture:stop":
capHide();
break;
// ---- ✅ Leaderboard ----
// We accept either name:
// - "leaderboard:update" (client might send this)
// - "turfwar:leaderboard:update" (recommended)
case "leaderboard:update":
case "turfwar:leaderboard:update":
lbRender(data.payload || data);
break;
case "leaderboard:hide":
lbHide();
break;
case "leaderboard:show":
lbShow();
break;
default:
break;
}
});