Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 14 additions & 1 deletion client/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -3094,7 +3094,7 @@ function onWsMessage(ev) {
return;
}
if (msg.type === 'dungeon_finds') { applyDungeonFinds(msg); showDungeonFindsHud(msg); return; }
if (msg.type === 'wilds_finds') { applyWildsFinds(msg); showWildsFindsHud(msg); return; }
if (msg.type === 'wilds_finds') { wildsFindsState = msg; applyWildsFinds(msg); showWildsFindsHud(msg); return; }
if (msg.type === 'trap_warn') { dungeonTrapWarn(msg.trap, msg.ms); setUnlockToast('⚠️ The roof is going. Move!', { always: true }); return; }
if (msg.type === 'toast') {
if (msg.message) setUnlockToast(msg.message, (msg.level || msg.always) ? { level: msg.level, always: !!msg.always } : undefined);
Expand Down Expand Up @@ -10403,6 +10403,7 @@ function showDungeonFindsHud(msg) {
}
// Out in the Wilds the same line counts the day's balefires.
let wildsFindsAskedAt = 0;
let wildsFindsState = null; // the day's balefires and searched cairns, as the server last told it (the map marks them)
function showWildsFindsHud(msg) {
const el = document.getElementById('dungeonFindsHud');
if (!el || !(me && me.room === 'wilds')) return;
Expand Down Expand Up @@ -17389,6 +17390,16 @@ const { openNotifModal } = _notif;
if (typeof WILDS_CAMPFIRES !== 'undefined') {
for (const f of WILDS_CAMPFIRES) drawProp(ctx, PX(f.x), PY(f.y) + fireS * 0.2, fireS, 'campfire');
}
// Balefires: a fire for each, and a ring round the ones still to light today,
// so the round can be planned from the map.
if (world2.finds) {
const litToday = new Set((wildsFindsState && wildsFindsState.lit) || []);
for (const f of world2.finds.balefires) {
const fx = PX(f.x), fy = PY(f.y);
drawProp(ctx, fx, fy + fireS * 0.2, fireS * 0.9, 'campfire');
if (!litToday.has(f.id)) { ctx.save(); ctx.strokeStyle = '#ffb060'; ctx.lineWidth = 1.5; ctx.setLineDash([3, 3]); ctx.beginPath(); ctx.arc(fx, fy, fireS * 0.75, 0, Math.PI * 2); ctx.stroke(); ctx.restore(); }
}
}
// NPCs: villager props at their true spots, then names stacked downward so
// the tight camp clusters read as a clean list instead of a tangle.
if (typeof WILDS_NPCS !== 'undefined') {
Expand Down Expand Up @@ -20376,6 +20387,8 @@ if (location.search.includes('testdrive=1')) {
teleport(x, y) { if (me) { me.x = x; me.y = y; } },
// Turn the camera round you (radians from its usual place behind you), to look at what stands at your back.
look(yaw, pitch) { cameraYawOffset = +yaw || 0; if (pitch != null) cameraPitchOffset = +pitch || 0; return true; },
// Stand in the Manor's hall (the look of it only; the server keeps its own door).
manor() { swapToManorMap(); if (me) { me.room = 'manor'; me.x = MANOR_WORLD.spawn.x; me.y = MANOR_WORLD.spawn.y; } return activeScene === manorScene; },
// Step straight into a town building's interior (the look of it; the server still keeps its own doors).
enter(roomId) { if (me && world && world.buildings.some((b) => b.id === roomId)) { enterBuilding(roomId); return true; } return false; },
kiosks() { return OUTDOOR_KIOSKS.map(k => ({ ...k })); },
Expand Down
13 changes: 13 additions & 0 deletions test/old-ways.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -146,5 +146,18 @@ check('the panel shows why a thing waits, asks before the brownie is clothed, an
const dung = fs.readFileSync(path.join(root, 'lib/dungeons.js'), 'utf8'), delve = fs.readFileSync(path.join(root, 'lib/delve.js'), 'utf8'), cottage = fs.readFileSync(path.join(root, 'client/cottage-scene.js'), 'utf8');
check('a bound boss drags its feet in a dungeon and on a Delve floor', /m\.boundUntil > now \? \{ \.\.\.base, speed: base\.speed \* \(m\.boundSlow \|\| 0\.6\) \} : base/.test(dung) && /\(m\.boundUntil > now \? \(m\.boundSlow \|\| 0\.6\) : 1\)/.test(delve) && /findBoss: \(p, range\) => \[\.\.\.dungeonMobs, \.\.\.allDelveMobs\(\)\]\.find\(\(m\) => m\.boss && !m\.dead && m\.room === p\.room/.test(server));
check('her besom leans by the cottage door, and the cream stands on the hearthstone the night it is set', /besom: !!\(key && accounts\[key\] && accounts\[key\]\.oldWays && accounts\[key\]\.oldWays\.besom && accounts\[key\]\.oldWays\.besom\.made\)/.test(server) && /kkStatic\('wd_besom', 96, 'height'\)/.test(cottage) && /kkStatic\('wd_cream', 18, 'fit'\)/.test(cottage) && /wd_besom: 'kk\/home\/besom\.glb', wd_cream: 'kk\/home\/cream_bowl\.glb'/.test(main) && fs.existsSync(path.join(root, 'public/kk/home/besom.glb')) && fs.existsSync(path.join(root, 'public/kk/home/cream_bowl.glb')));
// a bound boss, in the real dungeon tick: it covers six tenths of the ground it would
{
const ps = new Map();
const dmod = require('../lib/dungeons')({ players: ps, send: () => {}, isEvading: () => false, absorbIncomingDamage: (_p, d) => d, noteAttacked: () => {}, DUNGEON_ROOMS: { 1: 'dungeon_t1', 2: 'dungeon_t2', 3: 'dungeon_t3', 4: 'dungeon_t4' }, DUNGEON_SIZE: 2400, dungeonAffix: () => null });
const b = dmod.dungeonMobs.find((m) => m.boss && m.tier === 1);
ps.set('z', { id: 'z', room: 'dungeon_t1', x: b.spawnX + 150, y: b.spawnY, health: 1e6, isDead: false, ws: null });
const step = () => { b.x = b.spawnX; b.y = b.spawnY; dmod.tickDungeon(1); return Math.hypot(b.x - b.spawnX, b.y - b.spawnY); };
const free = step();
b.boundUntil = Date.now() + 60000; b.boundSlow = D.POPPET.bindSlow;
const bound = step();
b.boundUntil = 0;
check('a bound boss covers six tenths of the ground in the same time, and its full stride again once the binding is off', free > 10 && Math.abs(bound / free - 0.6) < 0.01 && Math.abs(step() - free) < 0.01, { free, bound });
}
console.log(`\n${pass} passed, ${fail} failed`);
process.exit(fail ? 1 : 0);
1 change: 1 addition & 0 deletions test/wilds-finds.test.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading