minor optimizations and weapon sim

This commit is contained in:
Kamal Tufekcic 2026-07-07 20:23:39 +03:00
commit fc7887ce11
10 changed files with 419 additions and 11 deletions

View file

@ -135,10 +135,45 @@
function fmt(v) { return "×" + v.toFixed(2); }
// The server's own 201-point arrays — displayed VERBATIM whenever the knobs are unedited (load + reset), so in
// the default state the page shows server truth, never our reimplementation of it. JS curves take over on edit.
function restoreServerCurves() {
curves.deal = seed.Curves.Deal.slice();
curves.take = seed.Curves.Take.slice();
curves.xp = seed.Curves.Xp.slice();
}
// Drift oracle: with server-seeded knobs, resample() must reproduce the seed's server-computed arrays. The seed
// ships everything needed to check that, so drift SELF-REPORTS instead of relying on a careful reader comparing
// the crosshair to the key-points table. Tolerance is relative 1e-9 (libm pow may differ by ULPs across
// runtimes; a real formula change is orders of magnitude larger). Leaves `curves` = server arrays either way.
function verifyParity() {
resample(); // JS-computed curves from the untouched server knobs
const server = { deal: seed.Curves.Deal, take: seed.Curves.Take, xp: seed.Curves.Xp };
let ok = true;
outer: for (const k in server) {
for (let i = 0; i < N; i++) {
const a = curves[k][i], b = server[k][i];
if (Math.abs(a - b) > 1e-9 * Math.max(1, Math.abs(b))) {
console.warn("theory.js drift vs server:", k, "at t=" + seed.Curves.T[i].toFixed(2), "js=" + a, "server=" + b);
const banner = $("sim-drift");
if (banner) banner.hidden = false;
ok = false;
break outer;
}
}
}
restoreServerCurves();
return ok;
}
function recompute() {
resample();
redrawPanels();
updateReadouts();
}
function updateReadouts() {
const rawT = computeRawT(h, player);
const tm = teamMults();
let b = bands(ease(rawT, h.Curve), h, tm.deal, tm.take);
@ -149,9 +184,14 @@
$("sim-take").textContent = fmt(b.take);
$("sim-xpband").textContent = fmt(b.xp);
// Hud.EffectiveMultipliers parity (headshot:false, crit:false, no actives):
$("sim-out").textContent = fmt((1 + effRun("damage") / 100) * b.deal);
const out = (1 + effRun("damage") / 100) * b.deal;
const hsx = 1 + effRun("hs_damage") / 100;
$("sim-out").textContent = fmt(out);
$("sim-in").textContent = fmt(b.take);
$("sim-hs").textContent = fmt(1 + effRun("hs_damage") / 100);
$("sim-hs").textContent = fmt(hsx);
// Published for weapons.js ("apply my build & handicap"): the same base-readout multipliers.
window.OGSim = { out: out, hs: hsx };
document.dispatchEvent(new CustomEvent("og:sim"));
// ProgressionModel.PrestigeXpMultiplier: 1 + prestige * boost%/100.
$("sim-xp").textContent = fmt((1 + effRun("xp_boost") / 100) * (1 + player.prestige * (player.prestigeBoost / 100)) * b.xp);
@ -221,7 +261,9 @@
// sim actually used (silent clamping in a theorycrafting tool is a lie). Partial input ("", "-") is left alone.
function clampedInt(el) {
const raw = Number.parseInt(el.value, 10);
const v = clamp(Number.isNaN(raw) ? 0 : raw, 0, Number.parseInt(el.max, 10) || 0);
const max = Number.parseInt(el.max, 10);
const cap = Number.isNaN(max) ? Infinity : max; // a missing max attribute means "uncapped", never "zero"
const v = clamp(Number.isNaN(raw) ? 0 : raw, 0, cap);
if (!Number.isNaN(raw) && raw !== v) el.value = v;
return v;
}
@ -265,8 +307,17 @@
recompute();
});
});
$("sim-reset").addEventListener("click", function () { seedInputs(); recompute(); });
// Reset shows the server's arrays again (not a resample of them) — the unedited state is always server truth.
$("sim-reset").addEventListener("click", function () {
seedInputs();
restoreServerCurves();
redrawPanels();
updateReadouts();
});
// Load: the SSR polylines already ARE the server curves, so don't redraw — just verify parity (drift
// self-reports via the banner), leave server arrays in place for the crosshair, and position the readouts.
seedInputs();
recompute();
verifyParity();
updateReadouts();
})();