diff --git a/game.py b/game.py
index 2e7879a..8fd30f9 100644
--- a/game.py
+++ b/game.py
@@ -3560,7 +3560,7 @@ ACTION_GLYPHS.update({
for _index, (_area, _level, _prefix, _races) in enumerate(AREAS):
for _race, *_rest in _races:
ACTION_GLYPHS[f"fight_{_slug(_race)}"] = (RACE_GLYPHS[_race], TIER_TINTS[_index])
-UI_GLYPHS = ["two-coins", "sparkles", "hearts", "prayer", "checked-shield", "magic-shield", "stopwatch", "swordman",
+UI_GLYPHS = ["two-coins", "sparkles", "hearts", "prayer", "checked-shield", "magic-shield", "stopwatch", "swordman", "biceps", "cancel",
"cape", "gem-pendant", "gauntlet", "ring", "quiver", "leather-boot", "crystal-ball", "visored-helm", "breastplate",
"leg-armor", "pointy-sword", "round-shield",
*(kind["glyph"] for kind in DAMAGE_TYPES.values())]
diff --git a/static/app.js b/static/app.js
index cba657f..ebf7142 100644
--- a/static/app.js
+++ b/static/app.js
@@ -1244,32 +1244,46 @@ function dollSlot(p, slot, label, outline, picked) {
}
function paperDoll(p, mine) {
- const worn = DOLL.filter(([slot]) => p.equip[slot]).map(([slot]) => slot);
- const pick = (dollPick && slot2(dollPick, p)) || (worn.includes("weapon") ? "weapon" : worn[0]) || "weapon";
- const label = DOLL.find(([slot]) => slot === pick)[1];
- const two = pick === "shield" && p.equip.weapon && item(p.equip.weapon).two_handed;
- const id = two ? p.equip.weapon : p.equip[pick], it = id && item(id);
- const detail = it ? `
${it.icon}${esc(it.name)}
- ${label}${two ? " (two-handed weapon)" : ""}
- ${mine && !two ? `` : ""}
- ${gearChips(it, p)}`
- : `${label}: nothing worn.${mine ? ` Equip from the .` : ""}
`;
- const st = C.styles[(p.equip.weapon && item(p.equip.weapon).style) || "sword"], dt = C.damage_types[st.damage];
+ const pick = dollPick && slot2(dollPick, p);
+ const totals = `
+ ${glyph("biceps", "#e06a6a")} Power${p.power}
+ ${glyph("checked-shield", "#d4dae2")} Armour${p.armour}
+ ${glyph("magic-shield", "#a77be8")} Ward${p.ward}
+
`;
+ let side = totals;
+ if (pick) {
+ const label = DOLL.find(([slot]) => slot === pick)[1];
+ const two = pick === "shield" && p.equip.weapon && item(p.equip.weapon).two_handed;
+ const id = two ? p.equip.weapon : p.equip[pick], it = id && item(id);
+ side = `${it ? `${it.icon}${esc(it.name)}` : `${label}empty`}
+ ${it ? gearChips(it, p) : ""}${mine ? swapGrid(p, pick, two) : ""}${totals}`;
+ }
return `
${glyph("swordman", "#e6e8ee")}
${DOLL.map(([slot, name, outline]) => dollSlot(p, slot, name, outline, slot === pick)).join("")}
-
-
${detail}
-
- ${glyph(dt.glyph, dt.tint)} ${dt.name}, a swing every ${st.interval}s
- Power${p.power}
- ${glyph("checked-shield", "#d4dae2")} Armour${p.armour} -${Math.round(p.reduction * 100)}% physical
- ${glyph("magic-shield", "#a77be8")} Ward${p.ward} -${Math.round(p.ward_reduction * 100)}% magic
-
-
+
${side}
`;
}
+// What else in the bank fits the picked slot, best first: click one to put it on. For weapons the
+// corner shows the damage type, so you can pick one for what you're about to fight.
+function swapGrid(p, slot, two) {
+ const fits = Object.keys(p.bank).filter((id) => item(id).slot === slot)
+ .sort((a, b) => (item(b).tier ?? 0) - (item(a).tier ?? 0) || (item(b).power ?? 0) - (item(a).power ?? 0));
+ const tiles = fits.map((id) => {
+ const it = item(id), [skill, level] = it.req || [];
+ const why = two ? `Your ${item(p.equip.weapon).name.toLowerCase()} takes both hands`
+ : skill && p.levels[skill] < level ? `Needs ${skillOf(skill).name.toLowerCase()} ${level}` : "";
+ const corner = it.style ? dmgIcon(C.styles[it.style].damage) : "";
+ const tip = [it.name, gearStats(it), it.style ? (it.two_handed ? "two-handed" : "one-handed") : "", why].filter(Boolean).join(" · ");
+ return ``;
+ });
+ const off = p.equip[slot] && !two ? `` : "";
+ if (!tiles.length && !off) return `Nothing else in your bank fits here.
`;
+ return `Swap for
${tiles.join("")}${off}
`;
+}
+
// A picked slot only counts if it's one this character has.
function slot2(slot, p) {
return slot in p.equip ? slot : null;
@@ -1380,7 +1394,7 @@ document.addEventListener("click", (e) => {
if (d.once) return act("/api/action", { id: d.once, once: true });
if ("stop" in d) return act("/api/stop", {});
if (d.doll) {
- dollPick = d.doll;
+ dollPick = dollPick === d.doll ? null : d.doll;
return render();
}
if ("select" in d) {
diff --git a/static/icons.svg b/static/icons.svg
index b750888..9631a34 100644
--- a/static/icons.svg
+++ b/static/icons.svg
@@ -23,6 +23,7 @@
+
diff --git a/static/styles.css b/static/styles.css
index 62da4c2..af1bbfd 100644
--- a/static/styles.css
+++ b/static/styles.css
@@ -487,7 +487,6 @@ button.sheet-skill:hover { background: var(--panel-2); }
.doll-slot.small .gi { width: 26px; height: 26px; }
.doll-side { display: grid; gap: 12px; min-width: 0; }
.doll-stats { display: grid; grid-template-columns: auto 1fr; gap: 4px 12px; font-size: 13px; align-items: center; }
-.doll-stats > span:first-child { grid-column: 1 / -1; margin-bottom: 2px; }
.doll-stats b { justify-self: end; }
.doll-stats .gi { width: 14px; height: 14px; }
.worn-head { display: flex; align-items: center; gap: 8px; margin-bottom: 4px; }
@@ -496,3 +495,18 @@ button.sheet-skill:hover { background: var(--panel-2); }
.worn-head .btn { margin-left: auto; }
.tool-slots { display: flex; flex-wrap: wrap; gap: 8px; }
@media (max-width: 520px) { .doll-wrap { grid-template-columns: 1fr; justify-items: center; } .doll-side { width: 100%; } }
+
+/* Swapping gear from the doll */
+.swap-head { margin-top: 2px; }
+.swap-grid { display: flex; flex-wrap: wrap; gap: 6px; }
+.doll-slot.swap { width: 44px; height: 44px; }
+.doll-slot.swap .gi { width: 28px; height: 28px; }
+.doll-slot.swap:hover:not(:disabled) { border-color: var(--gold); }
+.doll-slot.swap:disabled { opacity: .4; cursor: not-allowed; }
+.doll-slot.swap.off { border-style: dashed; background: transparent; }
+.doll-slot.swap.off .gi { width: 18px; height: 18px; }
+.swap-type { position: absolute; bottom: -4px; right: -4px; }
+.swap-type .dmg { width: 16px; height: 16px; background: var(--panel); border-radius: 4px; }
+.swap-qty { position: absolute; top: 1px; left: 3px; font-size: 10px; font-weight: 700; color: var(--muted); }
+.doll-slot.swap .swap-type .gi { width: 11px; height: 11px; }
+.doll-slot.swap .hands { top: 1px; right: 1px; font-size: 8px; padding: 0 2px; }