Files
ark-stronghold-protocol/public/js/ui/ticker.js
T
sganggs 7b1964707d feedback1c WJ: Hidden Core damage broadcasts count only the hidden leader
Player report: "隐藏boss还没打就出了造成50%伤害播报". The BOSS_HIT ticker
("{0}博士对敌方领袖造成的伤害超过20/50/80%!") divided the player's boss damage of
the whole match (stats.bossDamage, Final Assault + Hidden Core) by the hidden
leader's pool, so the Hidden Core's first hit already announced 50 % or 80 %.
The share is now the player's damage to the current round's pool
(SharedBossPool.byPlayer) over its size; 领袖伤害 on the result keeps both rounds.

The browser's ticker strip plays its queue 5.2 s per line, so a Final Assault
line could still play over the fresh hidden leader: a BOSS_HIT line is now
dropped once the round it came in is over (ui/ticker.js tickerLineLive; lines
carry their type and round from main.js).
2026-10-03 02:22:17 +08:00

77 lines
3.2 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// Broadcast ticker (m.ticker): a strip under the top bar; each line slides in from the right, stays
// TICKER_MS and leaves; queued lines play in order (only the newest QUEUE_MAX are kept).
// A leader-damage line (BOSS_HIT "{0}博士对敌方领袖造成的伤害超过X%!") is news about the leader in play: it is dropped,
// queued or on screen, once the round it came in is over — the queue can lag a line by up to QUEUE_MAX × TICKER_MS, and
// a Final Assault line must never play over the Hidden Core's fresh leader (player report after 0.1.0: "隐藏boss还没打
// 就出了造成50%伤害播报"). Lines carry `type` and `round` from main.js (the m.ticker handler).
import { useEffect, useRef, useState } from '../../vendor/hooks.module.js';
import { html } from './components.js';
import { GIcon, RichText } from './gameComponents.js';
import { useStore } from '../store.js';
import { audio } from '../audio.js';
const TICKER_MS = 5200;
const QUEUE_MAX = 4;
/**
* Whether a ticker line may still play in `round` (m.public.round): every line except a BOSS_HIT line from another
* round (the Final Assault's lines once the Hidden Core's round started). Lines without a round always play.
* @param {{ type?: string|null, round?: number|null }|null} line
* @param {number|null} round
*/
export function tickerLineLive(line, round) {
if (!line || line.type !== 'BOSS_HIT') return true;
return line.round == null || round == null || line.round === round;
}
/** Ticker strip bound to store.ticker. */
export function Ticker() {
const items = useStore((s) => s.ticker);
const round = useStore((s) => s.match?.public?.round ?? null);
const seen = useRef(null);
const queue = useRef([]);
const roundRef = useRef(round);
const [cur, setCur] = useState(null);
const timer = useRef(null);
roundRef.current = round;
useEffect(() => {
const list = Array.isArray(items) ? items : [];
if (seen.current == null) {
// lines received before this screen mounted are history, not news
seen.current = list.length ? list[list.length - 1].id : 0;
return;
}
const fresh = list.filter((t) => t && t.id > seen.current && Date.now() - t.at < 30000);
if (!fresh.length) return;
seen.current = fresh[fresh.length - 1].id;
queue.current = [...queue.current, ...fresh].slice(-QUEUE_MAX);
if (!cur) next();
}, [items]);
// a new round: the last round's leader-damage lines leave the queue and the strip
useEffect(() => {
queue.current = queue.current.filter((t) => tickerLineLive(t, round));
if (cur && !tickerLineLive(cur, round)) next();
}, [round]);
useEffect(() => () => clearTimeout(timer.current), []);
function next() {
let it = queue.current.shift() || null;
while (it && !tickerLineLive(it, roundRef.current)) it = queue.current.shift() || null;
setCur(it);
clearTimeout(timer.current);
if (it) {
audio.sfx('broadcast', { volume: 0.5 });
timer.current = setTimeout(next, TICKER_MS);
}
}
if (!cur) return null;
return html`<div class="ticker" role="status" aria-live="polite">
<div key=${cur.id} class="ticker__line"><${GIcon} name="flag" class="ticker__icon" /><${RichText} text=${cur.text} /></div>
</div>`;
}