Weapon styles: warhammer, sword and shield, staff, bow; trophies in recipes
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
19ccab4ac3
commit
4cb6ff5ec0
6 changed files with 244 additions and 24 deletions
|
|
@ -441,6 +441,17 @@ function toolPanel(skill) {
|
|||
: `<span class="muted">No tool. A smith can make you one that speeds this up.</span>`}</div>`;
|
||||
}
|
||||
|
||||
// What a monster is weak to and shrugs off, and how your weapon fares against it.
|
||||
function weaknessLine(kind, odds) {
|
||||
const table = C.weakness[kind];
|
||||
if (!table) return "";
|
||||
const names = (pick) => Object.entries(table).filter(([, m]) => pick(m)).map(([s]) => `${C.styles[s].name}s`).join(", ");
|
||||
const weak = names((m) => m > 1), tough = names((m) => m < 1);
|
||||
const yours = odds.weakness > 1 ? ` · <b class="good">your ${C.styles[odds.style].name} hits it hard</b>`
|
||||
: odds.weakness < 1 ? ` · <b class="bad">your ${C.styles[odds.style].name} does half damage</b>` : "";
|
||||
return `<div class="small muted">${weak ? `Weak to ${weak}` : ""}${weak && tough ? " · " : ""}${tough ? `shrugs off ${tough}` : ""}${yours}</div>`;
|
||||
}
|
||||
|
||||
// The fight in progress, replayed from the server's swing-by-swing record.
|
||||
function fightPanel() {
|
||||
const f = S.me.action?.fight;
|
||||
|
|
@ -461,6 +472,7 @@ function fightLine(e, enemy) {
|
|||
const foe = esc(enemy);
|
||||
if (kind === "eat") return `<li class="good">You eat ${esc(item(food).name.toLowerCase())} (+${amount})</li>`;
|
||||
if (kind === "wind") return `<li class="good">Second wind! Back on your feet</li>`;
|
||||
if (kind === "block") return `<li class="good">You block ${foe}'s blow</li>`;
|
||||
if (who === "you") return kind === "miss" ? `<li class="muted">You miss</li>` : `<li>You ${kind === "crit" ? "<b>crit</b>" : "hit"} for <b>${amount}</b></li>`;
|
||||
return kind === "miss" ? `<li class="muted">${foe} misses</li>` : `<li class="bad">${foe} ${kind === "crit" ? "<b>crits</b>" : "hits"} you for <b>${amount}</b></li>`;
|
||||
}
|
||||
|
|
@ -498,6 +510,19 @@ function animateFight(now) {
|
|||
});
|
||||
}
|
||||
|
||||
// How you fight with what's in your hands, and what your trade fights best with.
|
||||
function styleNote(me) {
|
||||
const weapon = me.equip.weapon, styleId = (weapon && item(weapon).style) || "sword", st = C.styles[styleId];
|
||||
const own = C.class_style[me.cls], traits = {
|
||||
sword: `a swing every ${st.interval}s${me.equip.shield ? `, and your shield blocks ${Math.round(C.block_chance * 100)}% of hits` : ""}`,
|
||||
hammer: `slow (${st.interval}s) heavy blows, twice the crits`,
|
||||
staff: `a cast every ${st.interval}s that rarely misses and goes through armour`,
|
||||
bow: `fast (${st.interval}s), and you shoot first`,
|
||||
};
|
||||
return `<p class="small">Fighting with ${weapon ? `a ${esc(st.name)}` : "your fists"}: ${traits[styleId]}.
|
||||
${own === styleId ? `<b class="good">Your trade's weapon: +15% damage.</b>` : `As a ${esc(C.classes[me.cls].name.toLowerCase())} you hit 15% harder with a ${esc(C.styles[own].name)}.`}</p>`;
|
||||
}
|
||||
|
||||
function combatPanel() {
|
||||
const me = S.me;
|
||||
const stat = (id) => [item(id).power && `+${item(id).power} power`, item(id).armour && `+${item(id).armour} armour`].filter(Boolean).join(", ");
|
||||
|
|
@ -524,6 +549,7 @@ function combatPanel() {
|
|||
<div class="panel"><h2>Equipment</h2>
|
||||
<div class="gear">${slot("weapon", "weapon")}${slot("shield", "shield")}${slot("helmet", "helmet")}${slot("body", "body armour")}${slot("legs", "leg armour")}</div>
|
||||
<p class="small muted">Power ${me.power} (level + weapon + shield + half your armour) · armour ${me.armour} takes ${Math.round(me.reduction * 100)}% off the damage you take. Equip gear from the bank.</p>
|
||||
${styleNote(me)}
|
||||
</div></div>`;
|
||||
}
|
||||
|
||||
|
|
@ -534,6 +560,10 @@ function itemStats(id) {
|
|||
if (it.heal) parts.push(`❤️ Heals ${it.heal}`);
|
||||
if (it.food) parts.push(`feeds ${it.food} ${it.food === 1 ? "person" : "people"} for two days`);
|
||||
if (it.power) parts.push(`+${it.power} power`);
|
||||
if (it.style) {
|
||||
const st = C.styles[it.style], trade = Object.entries(C.class_style).find(([, s]) => s === it.style)?.[0];
|
||||
parts.push(`${it.two_handed ? "two-handed " : ""}${st.name}, a swing every ${st.interval}s${trade ? ` (the ${C.classes[trade].name.toLowerCase()}'s weapon)` : ""}`);
|
||||
}
|
||||
if (it.armour) parts.push(`+${it.armour} armour`);
|
||||
if (it.tool) parts.push(`${Math.round(it.speed * 100)}% faster ${skillOf(it.tool).name.toLowerCase()}`);
|
||||
if (it.req && it.req[1] > 1) parts.push(`needs ${skillOf(it.req[0]).name.toLowerCase()} ${it.req[1]}`);
|
||||
|
|
@ -569,7 +599,8 @@ function actionCard(a) {
|
|||
const o = me.fight_odds[a.id], e = a.enemy, pct = (x) => `${Math.round(x * 100)}%`;
|
||||
extra = `<div class="small">${HEART} ${fmt(e.hp)} HP · hits up to <b>${o.their_max}</b> every ${e.interval}s${e.boss ? ` · <span class="tag warn">Boss</span>` : ""}</div>
|
||||
<div class="small">You land <b>${pct(o.hit)}</b> of swings (up to ${o.max_hit}) · it lands <b>${pct(o.their_hit)}</b></div>
|
||||
<div class="small">About <b>${dur(o.kill_time)}</b> a kill, <b>${Math.round(o.damage)}</b> damage taken${a.gold ? ` · ${a.gold} gold` : ""}</div>`;
|
||||
<div class="small">About <b>${dur(o.kill_time)}</b> a kill, <b>${Math.round(o.damage)}</b> damage taken${a.gold ? ` · ${a.gold} gold` : ""}</div>
|
||||
${weaknessLine(e.kind, o)}`;
|
||||
if (a.drops) io += a.drops.map(([id, q, odds]) => `<span class="item-chip" title="${esc(item(id).name)}: ${Math.round(odds * 100)}% chance">${item(id).icon} ${q} <span class="have">${Math.round(odds * 100)}%</span></span>`).join("");
|
||||
if (a.special === "sabotage") extra += `<div class="small muted">Each win weakens the coming raid by 3%, up to 30%.</div>`;
|
||||
}
|
||||
|
|
@ -1068,6 +1099,7 @@ function characterSheet(uid) {
|
|||
<p class="small">${esc(cls.bonus)}.</p>
|
||||
<p class="small">${esc(cls.masterwork)}.</p>
|
||||
<p class="small">${esc(cls.signature)}.</p>
|
||||
<p class="small">${esc(cls.combat)}.</p>
|
||||
</div>
|
||||
<div class="panel"><h2>Equipment</h2>
|
||||
<div class="sheet-gear">${Object.entries(SLOT_NAMES).map(([slot, label]) => gearSlot(slot, label, "Nothing")).join("")}</div>
|
||||
|
|
@ -1085,7 +1117,7 @@ function characterSheet(uid) {
|
|||
function classCards() {
|
||||
return Object.entries(C.classes).map(([id, c]) => `
|
||||
<button class="class-card ${pickedClass === id ? "on" : ""}" data-class="${id}">
|
||||
<span class="ico">${c.icon}</span><span><b>${c.name}</b><p>${esc(c.bonus)}.</p><p>${esc(c.masterwork)}.</p><p>${esc(c.signature)}.</p></span>
|
||||
<span class="ico">${c.icon}</span><span><b>${c.name}</b><p>${esc(c.bonus)}.</p><p>${esc(c.masterwork)}.</p><p>${esc(c.signature)}.</p><p>${esc(c.combat)}.</p></span>
|
||||
</button>`).join("");
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue