Compact gear cards and add dual pet stats
This commit is contained in:
@@ -83,6 +83,8 @@ function createDefaultPiece(slot, index) {
|
||||
name: slot.fixed?.name || slot.title,
|
||||
baseType: slot.fixed?.baseType || (index % 3 === 1 ? "health" : "damage"),
|
||||
baseValue: slot.fixed?.baseValue || 0,
|
||||
baseDamage: slot.fixed?.baseType === "damage" ? slot.fixed.baseValue : 0,
|
||||
baseHealth: slot.fixed?.baseType === "health" ? slot.fixed.baseValue : 0,
|
||||
fixedBase: Boolean(slot.fixed),
|
||||
effects: [{ type: "", value: 1 }, { type: "", value: 1 }],
|
||||
};
|
||||
@@ -96,6 +98,8 @@ function enforceFixedPieceFields(piece, index) {
|
||||
name: fixed.name,
|
||||
baseType: fixed.baseType,
|
||||
baseValue: fixed.baseValue,
|
||||
baseDamage: fixed.baseType === "damage" ? fixed.baseValue : 0,
|
||||
baseHealth: fixed.baseType === "health" ? fixed.baseValue : 0,
|
||||
fixedBase: true,
|
||||
};
|
||||
}
|
||||
@@ -111,6 +115,8 @@ function normalizeState(candidate) {
|
||||
pieces: fallback.pieces.map((piece, index) => enforceFixedPieceFields({
|
||||
...piece,
|
||||
...(candidate?.pieces?.[index] || {}),
|
||||
baseDamage: Number(candidate?.pieces?.[index]?.baseDamage ?? (candidate?.pieces?.[index]?.baseType === "damage" ? candidate?.pieces?.[index]?.baseValue : piece.baseDamage) ?? 0),
|
||||
baseHealth: Number(candidate?.pieces?.[index]?.baseHealth ?? (candidate?.pieces?.[index]?.baseType === "health" ? candidate?.pieces?.[index]?.baseValue : piece.baseHealth) ?? 0),
|
||||
effects: [0, 1].map((effectIndex) => ({
|
||||
type: candidate?.pieces?.[index]?.effects?.[effectIndex]?.type || "",
|
||||
value: clampEffectValue(
|
||||
@@ -150,19 +156,34 @@ function renderGear() {
|
||||
state.pieces.forEach((piece, pieceIndex) => {
|
||||
const node = template.content.firstElementChild.cloneNode(true);
|
||||
node.dataset.index = pieceIndex;
|
||||
node.querySelector("h3").textContent = piece.fixedBase ? `${piece.title} · ${piece.name}` : piece.title;
|
||||
node.querySelector("h3").textContent = piece.name;
|
||||
node.querySelector('[data-field="name"]').value = piece.name;
|
||||
node.querySelector('[data-field="baseType"]').value = piece.baseType;
|
||||
node.querySelector('[data-field="baseValue"]').value = piece.baseValue;
|
||||
const baseFields = node.querySelector(".inline-fields");
|
||||
if (piece.fixedBase) {
|
||||
node.classList.add("fixed-piece");
|
||||
node.querySelector('[data-field="name"]').readOnly = true;
|
||||
node.querySelector('[data-field="baseType"]').disabled = true;
|
||||
node.querySelector('[data-field="baseValue"]').readOnly = true;
|
||||
const badge = document.createElement("span");
|
||||
badge.className = "fixed-badge";
|
||||
badge.textContent = "Fixed base";
|
||||
node.querySelector(".gear-title-row").appendChild(badge);
|
||||
baseFields.innerHTML = `
|
||||
<label>Base stat
|
||||
<select data-field="baseType" disabled>
|
||||
<option value="damage">Damage</option>
|
||||
<option value="health">Health</option>
|
||||
</select>
|
||||
</label>
|
||||
<label>Value
|
||||
<input data-field="baseValue" type="number" min="0" step="1" readonly />
|
||||
</label>`;
|
||||
baseFields.querySelector('[data-field="baseType"]').value = piece.baseType;
|
||||
baseFields.querySelector('[data-field="baseValue"]').value = piece.baseValue;
|
||||
} else {
|
||||
baseFields.innerHTML = `
|
||||
<label>Damage base
|
||||
<input data-field="baseDamage" type="number" min="0" step="1" />
|
||||
</label>
|
||||
<label>Health base
|
||||
<input data-field="baseHealth" type="number" min="0" step="1" />
|
||||
</label>`;
|
||||
baseFields.querySelector('[data-field="baseDamage"]').value = piece.baseDamage || 0;
|
||||
baseFields.querySelector('[data-field="baseHealth"]').value = piece.baseHealth || 0;
|
||||
}
|
||||
|
||||
const effects = node.querySelector(".effects");
|
||||
@@ -216,9 +237,8 @@ function updateAnalysis() {
|
||||
function calculateTotals() {
|
||||
const totals = { baseDamage: 0, baseHealth: 0, effects: Object.fromEntries(EFFECTS.map((effect) => [effect.id, 0])) };
|
||||
for (const piece of state.pieces) {
|
||||
const baseValue = Number(piece.baseValue || 0);
|
||||
if (piece.baseType === "health") totals.baseHealth += baseValue;
|
||||
else totals.baseDamage += baseValue;
|
||||
totals.baseDamage += Number(piece.baseDamage || 0);
|
||||
totals.baseHealth += Number(piece.baseHealth || 0);
|
||||
for (const effect of piece.effects) {
|
||||
if (effect.type) totals.effects[effect.type] += clampEffectValue(effect.type, Number(effect.value));
|
||||
}
|
||||
@@ -290,9 +310,10 @@ function calculateGroupScore(totals, profile, groups, baseKind) {
|
||||
}
|
||||
|
||||
function scorePiece(piece, profile, totals) {
|
||||
const baseWeight = piece.baseType === "health" ? profile.baseHealth : profile.baseDamage;
|
||||
const baseAverage = Math.max(1, piece.baseType === "health" ? totals.baseHealth / 6 : totals.baseDamage / 6);
|
||||
let score = (Number(piece.baseValue || 0) / baseAverage) * 35 * baseWeight;
|
||||
const baseAverageDamage = Math.max(1, totals.baseDamage / 6);
|
||||
const baseAverageHealth = Math.max(1, totals.baseHealth / 6);
|
||||
let score = (Number(piece.baseDamage || 0) / baseAverageDamage) * 35 * profile.baseDamage
|
||||
+ (Number(piece.baseHealth || 0) / baseAverageHealth) * 35 * profile.baseHealth;
|
||||
const reasons = [];
|
||||
|
||||
for (const effect of piece.effects) {
|
||||
@@ -307,7 +328,7 @@ function scorePiece(piece, profile, totals) {
|
||||
if (profile.weights[effect.type] <= 3) reasons.push(`${def.label} is low priority for this profile`);
|
||||
}
|
||||
|
||||
if (!Number(piece.baseValue || 0)) reasons.push("no base stat entered");
|
||||
if (!Number(piece.baseDamage || 0) && !Number(piece.baseHealth || 0)) reasons.push("no base stat entered");
|
||||
return { piece, score, reasons: [...new Set(reasons)] };
|
||||
}
|
||||
|
||||
@@ -555,7 +576,11 @@ function handleGearInput(event) {
|
||||
return;
|
||||
}
|
||||
const field = event.target.dataset.field;
|
||||
piece[field] = field === "baseValue" ? Math.max(0, Number(event.target.value || 0)) : event.target.value;
|
||||
piece[field] = ["baseValue", "baseDamage", "baseHealth"].includes(field) ? Math.max(0, Number(event.target.value || 0)) : event.target.value;
|
||||
if (field === "baseDamage" || field === "baseHealth") {
|
||||
piece.baseType = Number(piece.baseHealth || 0) > Number(piece.baseDamage || 0) ? "health" : "damage";
|
||||
piece.baseValue = Math.max(Number(piece.baseDamage || 0), Number(piece.baseHealth || 0));
|
||||
}
|
||||
}
|
||||
if (event.target.dataset.effectType !== undefined) {
|
||||
const index = Number(event.target.dataset.effectType);
|
||||
|
||||
Reference in New Issue
Block a user