diff --git a/site/drop-tables.js b/site/drop-tables.js
index f1c8338..312da66 100644
--- a/site/drop-tables.js
+++ b/site/drop-tables.js
@@ -16,6 +16,8 @@
},
};
+ const RARE_MODIFIER_VERSIONS = new Set(["v2", "bb"]);
+
function esc(value) {
return String(value ?? "")
.replaceAll("&", "&")
@@ -38,6 +40,88 @@
box.innerHTML = `
${esc(message)}
`;
}
+ function currentVersion() {
+ return qs("#drops-version")?.value || "v1";
+ }
+
+ function rareModifierEnabled() {
+ return RARE_MODIFIER_VERSIONS.has(currentVersion());
+ }
+
+ function currentRareModifier() {
+ const select = qs("#drops-rare-modifier");
+ const pct = rareModifierEnabled() ? Number(select?.value || 0) : 0;
+ const label = select?.selectedOptions?.[0]?.textContent || "No modifier";
+ return { pct, label, multiplier: 1 + (pct / 100) };
+ }
+
+ function modifierMultiplierLabel(modifier) {
+ return `x${modifier.multiplier.toFixed(3).replace(/0+$/, "").replace(/\.$/, "")}`;
+ }
+
+ function updateRareModifierControls() {
+ const wrap = qs("#drops-rare-modifier-wrap");
+ const v2Note = qs("#drops-v2-note");
+ const select = qs("#drops-rare-modifier");
+ const enabled = rareModifierEnabled();
+
+ if (wrap) wrap.hidden = !enabled;
+ if (v2Note) v2Note.hidden = currentVersion() !== "v2";
+
+ if (!enabled && select) {
+ select.value = "0";
+ }
+ }
+
+ function formatOddsDenominator(value) {
+ if (!Number.isFinite(value) || value <= 0) return "—";
+
+ if (value >= 1000) {
+ return Math.round(value).toLocaleString();
+ }
+
+ if (value >= 100) {
+ return value.toFixed(1).replace(/\.0$/, "");
+ }
+
+ return value.toFixed(2).replace(/0+$/, "").replace(/\.$/, "");
+ }
+
+ function adjustedRate(rate) {
+ const text = String(rate || "");
+ const match = text.match(/^(\d+)\/(\d+)$/);
+ if (!match) return text || "—";
+
+ const num = Number(match[1]);
+ const den = Number(match[2]);
+ const modifier = currentRareModifier();
+
+ if (!rareModifierEnabled() || modifier.pct <= 0) {
+ return text;
+ }
+
+ const baseProbability = num / den;
+ const adjustedProbability = Math.min(1, baseProbability * modifier.multiplier);
+
+ if (adjustedProbability >= 1) {
+ return "1/1";
+ }
+
+ return `1/${formatOddsDenominator(1 / adjustedProbability)}`;
+ }
+
+ function rateCellHtml(rate) {
+ const base = String(rate || "—");
+ const adjusted = adjustedRate(base);
+ const modifier = currentRareModifier();
+
+ if (!rareModifierEnabled() || modifier.pct <= 0 || adjusted === base) {
+ return esc(base);
+ }
+
+ return esc(adjusted);
+ }
+
async function fetchJson(path) {
const res = await fetch(path, { cache: "no-store" });
if (!res.ok) throw new Error(`${path}: HTTP ${res.status}`);
@@ -149,7 +233,7 @@
${esc(labelValue(row.source || "—"))} |
${esc(item)} |
${esc(itemCode)} |
- ${esc(row.rate || "—")} |
+ ${rateCellHtml(row.rate || "—")} |
`;
}).join("");
@@ -157,12 +241,17 @@
const truncation = rows.length > shown.length
? ` Showing first ${shown.length.toLocaleString()}.`
: "";
+ const modifier = currentRareModifier();
+ const modifierNote = rareModifierEnabled() && modifier.pct > 0
+ ? `Rate modifier: ${esc(modifier.label)} / ${esc(modifierMultiplierLabel(modifier))}`
+ : "";
box.innerHTML = `
Peeps ${esc(tableLabel)} drop table
${rows.length.toLocaleString()} matching rows.${truncation}
+ ${modifierNote}
${state.rows.length.toLocaleString()} total rows
@@ -214,6 +303,7 @@
if (qs("#drops-search")) qs("#drops-search").value = "";
populateFilters(state.rows);
+ updateRareModifierControls();
if (qs("#drops-rare-mode")) qs("#drops-rare-mode").value = "";
if (qs("#drops-episode")) qs("#drops-episode").value = "";
@@ -245,6 +335,7 @@
document.addEventListener("DOMContentLoaded", () => {
qs("#drops-mode")?.addEventListener("change", updateMode);
qs("#drops-version")?.addEventListener("change", loadPeeps);
+ qs("#drops-rare-modifier")?.addEventListener("change", renderTable);
qs("#drops-rare-mode")?.addEventListener("change", (event) => {
state.filters.mode = event.target.value;
diff --git a/site/drops.html b/site/drops.html
index 299d373..9bec22d 100644
--- a/site/drops.html
+++ b/site/drops.html
@@ -8,7 +8,7 @@
-
+
@@ -45,6 +45,26 @@
+ V2 drop tables apply to PSO PC only.
+
+
+
+
+
Applies to the Rate column for V2 PC and BB/V4.
+