diff --git a/client/src/lib/feed.js b/client/src/lib/feed.js index da09b8a..d4ec3a8 100644 --- a/client/src/lib/feed.js +++ b/client/src/lib/feed.js @@ -21,7 +21,7 @@ // here is presentation, and the honest presentation of a kind we have no words // for is its own name. -import { attacker, duration, prefab } from './format.js' +import { attacker, duration, weapon } from './format.js' /** * Kinds this feed asks for. @@ -205,7 +205,7 @@ export function describe(row) { */ function death(frame, name) { const where = [ - frame.weapon ? `with ${prefab(frame.weapon)}` : null, + frame.weapon ? `with ${weapon(frame)}` : null, frame.distance ? `${Math.round(frame.distance)}m` : null, frame.grid || null, frame.sleeping ? 'while sleeping' : null, diff --git a/client/src/lib/format.js b/client/src/lib/format.js index 39e0d64..8c850f4 100644 --- a/client/src/lib/format.js +++ b/client/src/lib/format.js @@ -130,6 +130,18 @@ export function prefab(name) { return String(name).replace(/[_.]+/g, ' ').trim() } +/** + * The weapon in a kill. The server sends `weaponName` — the game's own name for + * a gun, or the prefab name as words (`server/model/titles/weaponNames.js`) — + * and that is what prints. A server too old to send it gets the same fallback + * here: the `.entity` / `.weapon` ending dropped, so never "ak47u entity". + */ +export function weapon(frame) { + if (!frame || !frame.weapon) return '' + if (frame.weaponName) return String(frame.weaponName) + return prefab(String(frame.weapon).trim().replace(/[._](entity|weapon|deployed)$/, '')) +} + /** * The NPC families whose prefab reads badly as words, by the prefix the game's * short names share. First match wins, so a longer prefix sits above a shorter diff --git a/client/src/routes/admin/ChatTitles.jsx b/client/src/routes/admin/ChatTitles.jsx index 6cc3661..3c88e40 100644 --- a/client/src/routes/admin/ChatTitles.jsx +++ b/client/src/routes/admin/ChatTitles.jsx @@ -49,7 +49,7 @@ export function titlesSummary(titles, push, categories) { const rules = (titles && titles.rules) || [] if (!rules.length) return 'No chat titles.' const list = rules.map((r) => `${ruleTitle(r, categories)} (top ${r.topN} ${statOf(categories, r.stat).label.toLowerCase()})`).join(', ') - const shown = push ? ` Last pushed: ${push.count} player${push.count === 1 ? '' : 's'} hold one${push.betterChat ? '' : ' — BetterChat is not loaded, so they are not showing in game yet'}.` : '' + const shown = push ? ` Last pushed: ${push.count} player${push.count === 1 ? ' holds' : 's hold'} one${push.betterChat ? '' : ' — BetterChat is not loaded, so they are not showing in game yet'}.` : '' return `Chat titles: ${list}.${shown}` } diff --git a/client/src/routes/admin/Permissions.jsx b/client/src/routes/admin/Permissions.jsx index c76d486..b6efd81 100644 --- a/client/src/routes/admin/Permissions.jsx +++ b/client/src/routes/admin/Permissions.jsx @@ -542,7 +542,7 @@ function GroupPanel({ view, group, act, busy, chatFields }) { {tab === 'servers' && (

- A group belongs to one server unless it is shared (D189). A shared group carries the same permissions and players on every server + A group belongs to one server unless it is shared. A shared group carries the same permissions and players on every server it is on; a change made in one game gives that server its own copy.