Main
Main files for Loot distribution. requires you to download the items.json from the Albion tools repository
This commit is contained in:
@@ -0,0 +1,125 @@
|
||||
|
||||
let items=[],players=[],loot=[],selected=null;
|
||||
const fmt=n=>Number(n).toLocaleString();
|
||||
|
||||
async function loadDatabase(){
|
||||
try{
|
||||
const response=await fetch('items.json');
|
||||
if(!response.ok) throw new Error('load');
|
||||
const raw=await response.json();
|
||||
items=raw.map(x=>{
|
||||
const name=(x.LocalizedNames&&x.LocalizedNames["EN-US"])||"";
|
||||
const u=x.UniqueName||"";
|
||||
const ench=(u.match(/@(\d)/)||[])[1]||"0";
|
||||
const tier=(u.match(/T(\d)/)||[])[1]||"";
|
||||
return {name,label:`${name} (T${tier}.${ench})`};
|
||||
}).filter(i=>i.name);
|
||||
const s=document.getElementById('dbStatus')||document.getElementById('status');
|
||||
if(s)s.textContent='';
|
||||
search.disabled=false;
|
||||
}catch(e){
|
||||
const s=document.getElementById('dbStatus')||document.getElementById('status');
|
||||
if(s)s.textContent='Unable to load items.json';
|
||||
}
|
||||
}
|
||||
loadDatabase();
|
||||
|
||||
function renderPlayers(){
|
||||
playersDiv=playersEl=document.getElementById("players");
|
||||
playersEl.innerHTML="";
|
||||
players.forEach((p,i)=>{
|
||||
const d=document.createElement("span");
|
||||
d.className="player";
|
||||
d.innerHTML=`${p} <button>x</button>`;
|
||||
d.querySelector("button").onclick=()=>{players.splice(i,1);renderPlayers();};
|
||||
playersEl.appendChild(d);
|
||||
|
||||
});
|
||||
updateSummary();
|
||||
}
|
||||
function addPlayerFn(){
|
||||
const n=playerName.value.trim();
|
||||
if(!n)return;
|
||||
players.push(n);
|
||||
playerName.value="";
|
||||
renderPlayers();
|
||||
}
|
||||
addPlayer.onclick=addPlayerFn;
|
||||
playerName.addEventListener("keydown",e=>{if(e.key==="Enter"){e.preventDefault();addPlayerFn();}});
|
||||
|
||||
search.oninput=()=>{
|
||||
const q=search.value.toLowerCase();
|
||||
results.innerHTML="";
|
||||
if(q.length<2)return;
|
||||
const groups={};
|
||||
items.filter(i=>i.name.toLowerCase().includes(q)).slice(0,80).forEach(i=>(groups[i.name]??=[]).push(i));
|
||||
Object.keys(groups).sort().forEach(name=>{
|
||||
const g=document.createElement("div");g.className="group";
|
||||
g.innerHTML=`<div class="title">${name}</div>`;
|
||||
groups[name].forEach(it=>{
|
||||
const c=document.createElement("div");c.className="child";c.textContent=it.label;
|
||||
c.onclick=()=>{selected=it;selectedSpan.textContent=it.label;search.value=it.name;results.innerHTML="";updatePriceInfo();qty.focus();};
|
||||
g.appendChild(c);
|
||||
});
|
||||
results.appendChild(g);
|
||||
|
||||
});
|
||||
updateSummary();
|
||||
};
|
||||
|
||||
const priceHistory=JSON.parse(localStorage.getItem("priceHistory")||"{}");
|
||||
function fmtAge(ts){if(!ts)return"Never";let m=Math.floor((Date.now()-ts)/60000);if(m<60)return m+"m ago";let h=Math.floor(m/60);if(h<24)return h+"h ago";let d=Math.floor(h/24);h%=24;return d+"d "+h+"h ago";}
|
||||
function updatePriceInfo(){if(!selected){lastUpdated.textContent="Never";return;}const p=priceHistory[selected.label];if(p){priceEach.value=p.price;updateTotal();lastUpdated.textContent=fmtAge(p.updated);}else lastUpdated.textContent="Never";}
|
||||
|
||||
const selectedSpan=document.getElementById("selected");
|
||||
function updateTotal(){totalValue.textContent=fmt((+qty.value||0)*(+priceEach.value||0));}
|
||||
qty.oninput=updateTotal;priceEach.oninput=updateTotal;updateTotal();
|
||||
|
||||
addLoot.onclick=()=>{
|
||||
if(!selected)return alert("Select an item.");
|
||||
const q=+qty.value||1,e=+priceEach.value||0,total=q*e;
|
||||
const existing=loot.find(x=>x.item===selected.label&&x.each===e);
|
||||
if(existing){existing.qty+=q;existing.total=existing.qty*existing.each;}
|
||||
else loot.push({item:selected.label,qty:q,each:e,total,keep:keepTogether.checked});
|
||||
priceHistory[selected.label]={price:e,updated:Date.now()};localStorage.setItem("priceHistory",JSON.stringify(priceHistory));renderLoot();
|
||||
selected=null;selectedSpan.textContent="None";search.value="";qty.value=1;priceEach.value=0;updateTotal();
|
||||
};
|
||||
|
||||
function updateSummary(){let stacks=loot.length,items=0,val=0;loot.forEach(l=>{items+=l.qty;val+=l.total;});sumStacks.textContent=stacks;sumItems.textContent=items;sumValue.textContent=fmt(val);targetShare.textContent=players.length?fmt(Math.round(val/players.length)):0;}
|
||||
|
||||
function renderLoot(){
|
||||
const tb=document.querySelector("#loot tbody");tb.innerHTML="";
|
||||
loot.forEach((l,i)=>{
|
||||
const r=tb.insertRow();
|
||||
r.insertCell().textContent=l.item;
|
||||
r.insertCell().textContent=l.qty;
|
||||
r.insertCell().textContent=fmt(l.each);
|
||||
r.insertCell().textContent=fmt(l.total);
|
||||
r.insertCell().textContent=l.keep?'✓':'';
|
||||
const b=document.createElement("button");b.textContent="❌";b.onclick=()=>{loot.splice(i,1);renderLoot();};
|
||||
r.insertCell().appendChild(b);
|
||||
|
||||
});
|
||||
updateSummary();
|
||||
}
|
||||
|
||||
distribute.onclick=()=>{
|
||||
if(players.length===0)return alert("Add players first.");
|
||||
let best=null,bestSpread=Infinity;
|
||||
for(let t=0;t<300;t++){
|
||||
let expanded=[];loot.forEach(l=>{if(l.keep){expanded.push({...l});}else{for(let i=0;i<l.qty;i++)expanded.push({item:l.item,qty:1,each:l.each,total:l.each});}});let work=expanded.sort(()=>Math.random()-0.5).sort((a,b)=>b.total-a.total);
|
||||
let p=players.map(n=>({name:n,total:0,items:[]}));
|
||||
work.forEach(it=>{p.sort((a,b)=>a.total-b.total);p[0].items.push(it);p[0].total+=it.total;});
|
||||
let vals=p.map(x=>x.total);let spread=Math.max(...vals)-Math.min(...vals);
|
||||
if(spread<bestSpread){bestSpread=spread;best=JSON.parse(JSON.stringify(p));}
|
||||
}
|
||||
distribution.innerHTML="";
|
||||
best.forEach(pl=>{
|
||||
const merged={};pl.items.forEach(i=>{const k=i.item+'|'+i.each;if(!merged[k])merged[k]={...i};else{merged[k].qty+=i.qty;merged[k].total+=i.total;}});
|
||||
const d=document.createElement("div");
|
||||
d.innerHTML=`<h3>${pl.name} — ${fmt(pl.total)} silver</h3><ul>${Object.values(merged).map(i=>`<li>${i.item} ×${i.qty}</li>`).join("")}</ul>`;
|
||||
distribution.appendChild(d);
|
||||
|
||||
});
|
||||
updateSummary();
|
||||
};
|
||||
Reference in New Issue
Block a user