@songsid/agend 2.3.0 → 2.3.2-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/README.zh-TW.md +1 -1
- package/dist/authority/authority-state.d.ts +4 -0
- package/dist/authority/authority-state.js +16 -10
- package/dist/authority/authority-state.js.map +1 -1
- package/dist/authority/session-authorizations.d.ts +7 -1
- package/dist/authority/session-authorizations.js +6 -4
- package/dist/authority/session-authorizations.js.map +1 -1
- package/dist/authority/web-authority.d.ts +19 -6
- package/dist/authority/web-authority.js +22 -8
- package/dist/authority/web-authority.js.map +1 -1
- package/dist/backend/muse.d.ts +20 -2
- package/dist/backend/muse.js +154 -16
- package/dist/backend/muse.js.map +1 -1
- package/dist/channel/adapters/discord.d.ts +2 -0
- package/dist/channel/adapters/discord.js +33 -3
- package/dist/channel/adapters/discord.js.map +1 -1
- package/dist/channel/adapters/telegram.d.ts +1 -1
- package/dist/channel/adapters/telegram.js +3 -35
- package/dist/channel/adapters/telegram.js.map +1 -1
- package/dist/channel/mcp-tools.js +5 -5
- package/dist/channel/mcp-tools.js.map +1 -1
- package/dist/channel/types.d.ts +11 -0
- package/dist/cli.js +6 -3
- package/dist/cli.js.map +1 -1
- package/dist/config-validator.js +42 -5
- package/dist/config-validator.js.map +1 -1
- package/dist/daemon.d.ts +47 -3
- package/dist/daemon.js +380 -60
- package/dist/daemon.js.map +1 -1
- package/dist/delivery-outbox.d.ts +23 -1
- package/dist/delivery-outbox.js +114 -17
- package/dist/delivery-outbox.js.map +1 -1
- package/dist/doctor.d.ts +3 -0
- package/dist/doctor.js +9 -0
- package/dist/doctor.js.map +1 -1
- package/dist/event-log.d.ts +5 -0
- package/dist/event-log.js +13 -0
- package/dist/event-log.js.map +1 -1
- package/dist/fleet-context.d.ts +1 -1
- package/dist/fleet-lock.d.ts +6 -0
- package/dist/fleet-lock.js +19 -0
- package/dist/fleet-lock.js.map +1 -1
- package/dist/fleet-manager.d.ts +174 -2
- package/dist/fleet-manager.js +678 -68
- package/dist/fleet-manager.js.map +1 -1
- package/dist/fleet-process-handlers.d.ts +1 -0
- package/dist/fleet-process-handlers.js +9 -1
- package/dist/fleet-process-handlers.js.map +1 -1
- package/dist/general-knowledge/skills/instance-lifecycle/SKILL.md +11 -0
- package/dist/general-knowledge/skills/web-appearance/SKILL.canvas-worker-off.md +4 -4
- package/dist/general-knowledge/skills/web-appearance/SKILL.md +7 -7
- package/dist/general-knowledge/skills/web-dashboard/SKILL.canvas-worker-off.md +109 -57
- package/dist/general-knowledge/skills/web-dashboard/SKILL.md +110 -58
- package/dist/guest-seen-people.d.ts +38 -0
- package/dist/guest-seen-people.js +78 -0
- package/dist/guest-seen-people.js.map +1 -0
- package/dist/instance-config-impact.js +4 -1
- package/dist/instance-config-impact.js.map +1 -1
- package/dist/instance-lifecycle.d.ts +2 -0
- package/dist/instance-lifecycle.js +27 -1
- package/dist/instance-lifecycle.js.map +1 -1
- package/dist/locale.js +62 -12
- package/dist/locale.js.map +1 -1
- package/dist/log-service.js +1 -0
- package/dist/log-service.js.map +1 -1
- package/dist/mac-auto-restore.d.ts +117 -0
- package/dist/mac-auto-restore.js +294 -0
- package/dist/mac-auto-restore.js.map +1 -0
- package/dist/needs-you.js +1 -0
- package/dist/needs-you.js.map +1 -1
- package/dist/outbound-handlers.d.ts +2 -2
- package/dist/outbound-handlers.js +5 -5
- package/dist/outbound-handlers.js.map +1 -1
- package/dist/outbound-schemas.d.ts +2 -0
- package/dist/outbound-schemas.js +2 -0
- package/dist/outbound-schemas.js.map +1 -1
- package/dist/public-web-gateway.js +9 -1
- package/dist/public-web-gateway.js.map +1 -1
- package/dist/search/search-index.d.ts +10 -2
- package/dist/search/search-index.js +17 -4
- package/dist/search/search-index.js.map +1 -1
- package/dist/service-installer.d.ts +23 -1
- package/dist/service-installer.js +40 -11
- package/dist/service-installer.js.map +1 -1
- package/dist/session-oom-stop.d.ts +45 -0
- package/dist/session-oom-stop.js +259 -0
- package/dist/session-oom-stop.js.map +1 -0
- package/dist/session-oom.d.ts +13 -0
- package/dist/session-oom.js +119 -7
- package/dist/session-oom.js.map +1 -1
- package/dist/settings-api.d.ts +27 -1
- package/dist/settings-api.js +108 -2
- package/dist/settings-api.js.map +1 -1
- package/dist/settings-change.js +37 -3
- package/dist/settings-change.js.map +1 -1
- package/dist/settings-effect.js +5 -2
- package/dist/settings-effect.js.map +1 -1
- package/dist/spawn-gate.d.ts +2 -0
- package/dist/spawn-gate.js +17 -4
- package/dist/spawn-gate.js.map +1 -1
- package/dist/start-attempt.d.ts +15 -1
- package/dist/start-attempt.js +35 -5
- package/dist/start-attempt.js.map +1 -1
- package/dist/start-failure-chat.d.ts +41 -0
- package/dist/start-failure-chat.js +159 -0
- package/dist/start-failure-chat.js.map +1 -0
- package/dist/start-failure-notice.d.ts +4 -0
- package/dist/start-failure-notice.js +8 -0
- package/dist/start-failure-notice.js.map +1 -1
- package/dist/start-failure.d.ts +49 -0
- package/dist/start-failure.js +141 -1
- package/dist/start-failure.js.map +1 -1
- package/dist/telegram-api-root.d.ts +1 -0
- package/dist/telegram-api-root.js +40 -0
- package/dist/telegram-api-root.js.map +1 -0
- package/dist/turn-reply-guard.d.ts +25 -0
- package/dist/turn-reply-guard.js +111 -12
- package/dist/turn-reply-guard.js.map +1 -1
- package/dist/types.d.ts +21 -3
- package/dist/ui/backend-signin.js +5 -2
- package/dist/ui/chat-ambient.js +1 -1
- package/dist/ui/chat-effects.js +4 -4
- package/dist/ui/chat-render.js +5 -2
- package/dist/ui/chat-strings.js +2 -2
- package/dist/ui/chat-thread.js +2 -2
- package/dist/ui/first-run.js +2 -2
- package/dist/ui/fleet-canvas-view.js +114 -0
- package/dist/ui/fleet-canvas.js +15 -77
- package/dist/ui/fleet-office-editor.js +80 -5
- package/dist/ui/fleet-office-layout.js +197 -0
- package/dist/ui/fleet-office-model.js +6 -3
- package/dist/ui/fleet-office-pack.d.ts +39 -0
- package/dist/ui/fleet-office-pack.js +240 -29
- package/dist/ui/fleet-office-skin.js +130 -21
- package/dist/ui/fleet-office-store.js +75 -4
- package/dist/ui/fleet-office-view.js +154 -0
- package/dist/ui/fleet-office-zones.js +95 -33
- package/dist/ui/fleet-office.js +530 -94
- package/dist/ui/fleet-usage.js +7 -6
- package/dist/ui/panel-chat.js +20 -7
- package/dist/ui/panel-details.js +2 -2
- package/dist/ui/panel-fleet.js +11 -77
- package/dist/ui/panel-log.js +5 -5
- package/dist/ui/panel-settings.js +586 -164
- package/dist/ui/search-dialog.js +26 -7
- package/dist/ui/settings-appearance.js +82 -29
- package/dist/ui/settings-apply.js +42 -7
- package/dist/ui/settings-dialogs.js +68 -22
- package/dist/ui/settings-draft.js +51 -0
- package/dist/ui/settings-guests.js +244 -78
- package/dist/ui/settings-learn.js +2 -2
- package/dist/ui/settings-model.js +2 -0
- package/dist/ui/settings-registry.js +142 -0
- package/dist/ui/settings-strings.js +108 -44
- package/dist/ui/settings-web-authority.js +34 -23
- package/dist/ui/shared/app-i18n.js +14 -0
- package/dist/ui/shared/app-nav.js +10 -5
- package/dist/ui/shared/app-prefs.js +80 -2
- package/dist/ui/shared/app-route.js +39 -5
- package/dist/ui/shared/app-shell.js +80 -8
- package/dist/ui/shared/app-stream.js +2 -1
- package/dist/ui/shared/app.css +251 -20
- package/dist/ui/shared/app.js +3 -0
- package/dist/ui/shared/effect-stock-trust.js +1 -1
- package/dist/ui/shared/identity-color.js +4 -4
- package/dist/ui/shared/signin.js +2 -2
- package/dist/ui/shared/ui-dialog.js +6 -1
- package/dist/ui/shared/ui-icons.js +2 -0
- package/dist/ui/shared/usage-dialog.js +21 -11
- package/dist/ui/shared/view-strings.js +2 -0
- package/dist/ui/shared/web-authorize.js +13 -12
- package/dist/web-api.d.ts +9 -3
- package/dist/web-api.js +161 -6
- package/dist/web-api.js.map +1 -1
- package/dist/web-auth.js +7 -1
- package/dist/web-auth.js.map +1 -1
- package/dist/web-experimental.d.ts +1 -1
- package/dist/web-experimental.js +1 -1
- package/dist/web-experimental.js.map +1 -1
- package/dist/web-mod-agent.js +2 -2
- package/dist/web-mod-agent.js.map +1 -1
- package/dist/web-office-skins.d.ts +108 -0
- package/dist/web-office-skins.js +298 -0
- package/dist/web-office-skins.js.map +1 -0
- package/dist/web-office-store.d.ts +8 -2
- package/dist/web-office-store.js +37 -7
- package/dist/web-office-store.js.map +1 -1
- package/dist/web-settings-patch.d.ts +6 -0
- package/dist/web-settings-patch.js +61 -4
- package/dist/web-settings-patch.js.map +1 -1
- package/dist/web-shell-routes.d.ts +4 -2
- package/dist/web-shell-routes.js +17 -7
- package/dist/web-shell-routes.js.map +1 -1
- package/dist/working-recovery.d.ts +104 -0
- package/dist/working-recovery.js +263 -0
- package/dist/working-recovery.js.map +1 -0
- package/dist/working-state-journal.d.ts +70 -0
- package/dist/working-state-journal.js +106 -0
- package/dist/working-state-journal.js.map +1 -0
- package/package.json +1 -1
|
@@ -2,27 +2,39 @@
|
|
|
2
2
|
// fleet-office-pack.js). Each instance goes to the area for its state now and takes a seat slot there; when its state
|
|
3
3
|
// changes it walks (along the pack's waypoints) to the new area. Pure — fleet-office.js draws it. Also here: what a
|
|
4
4
|
// character says in its speech bubble, and which furniture is active.
|
|
5
|
-
import { LOGICAL } from "./fleet-office-pack.js";
|
|
5
|
+
import { LOGICAL, own } from "./fleet-office-pack.js";
|
|
6
6
|
import { nameHash, pathLength, along, routeVia } from "./fleet-office-model.js";
|
|
7
7
|
|
|
8
8
|
/** The area for a state: the pack's own, else its "default", else its first area. */
|
|
9
9
|
export function zoneOf(pack, state) {
|
|
10
10
|
const z = pack.stateZones || {};
|
|
11
|
-
return z
|
|
11
|
+
return own(z, state) || own(z, "default") || Object.keys(pack.areas)[0];
|
|
12
12
|
}
|
|
13
13
|
|
|
14
|
-
/**
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
14
|
+
/**
|
|
15
|
+
* How far apart overflow spots are, and how far they stay from the area's seats (logical units); TITLE: the band at
|
|
16
|
+
* the top of an area its name is written in, kept clear. A crowded area packs tighter (STEPS, #2513: 70 instances, 42
|
|
17
|
+
* idle, piled up in the lounge) before anyone is left to the "+N" count.
|
|
18
|
+
*/
|
|
19
|
+
export const OVERFLOW = { STEP: 56, CLEAR: 40, EDGE: 24, TITLE: 30, STEPS: [56, 46, 38, 32] };
|
|
20
|
+
function spotsAt(area, step) {
|
|
21
|
+
const out = [], { x, y, w, h } = area.rect, clear = step === OVERFLOW.STEP ? OVERFLOW.CLEAR : Math.round(step * 0.72);
|
|
22
|
+
for (let sy = y + OVERFLOW.EDGE + OVERFLOW.TITLE; sy <= y + h - OVERFLOW.EDGE; sy += step) {
|
|
23
|
+
for (let sx = x + OVERFLOW.EDGE; sx <= x + w - OVERFLOW.EDGE; sx += step) {
|
|
24
|
+
if (area.seats.every((s) => Math.hypot(s.x - sx, s.y - sy) >= clear)) out.push({ x: sx, y: sy });
|
|
22
25
|
}
|
|
23
26
|
}
|
|
24
27
|
return out;
|
|
25
28
|
}
|
|
29
|
+
/**
|
|
30
|
+
* An area's overflow spots, for when its seats are taken: a tidy grid inside its rect, clear of its seats and its
|
|
31
|
+
* title, in reading order. `need`: how many are wanted — the widest spacing that fits them all, else the tightest.
|
|
32
|
+
*/
|
|
33
|
+
export function overflowSpots(area, need = 0) {
|
|
34
|
+
let spots = [];
|
|
35
|
+
for (const step of OVERFLOW.STEPS) { spots = spotsAt(area, step); if (spots.length >= need) return spots; }
|
|
36
|
+
return spots;
|
|
37
|
+
}
|
|
26
38
|
|
|
27
39
|
/**
|
|
28
40
|
* Seats for everyone: `wants` [{ name, area }] in the fleet's order; `prev` what the last call gave (name → { area,
|
|
@@ -31,51 +43,71 @@ export function overflowSpots(area) {
|
|
|
31
43
|
* Returns { seats: Map name → { area, slot, x, y }, crowd: Map }.
|
|
32
44
|
*/
|
|
33
45
|
export function assignSeats(pack, wants, prev = new Map()) {
|
|
34
|
-
const seats = new Map(), crowd = new Map(), taken = new Map(), spill = new Map();
|
|
35
|
-
const
|
|
36
|
-
const
|
|
46
|
+
const seats = new Map(), crowd = new Map(), taken = new Map(), spill = new Map(), demand = new Map();
|
|
47
|
+
const areaOf = (a) => own(pack.areas, a);
|
|
48
|
+
for (const w of wants) demand.set(w.area, (demand.get(w.area) || 0) + 1);
|
|
49
|
+
const spotsOf = (area) => {
|
|
50
|
+
if (!spill.has(area)) spill.set(area, overflowSpots(areaOf(area), Math.max(0, (demand.get(area) || 0) - areaOf(area).seats.length)));
|
|
51
|
+
return spill.get(area);
|
|
52
|
+
};
|
|
53
|
+
const pos = (area, slot) => (slot >= 0 ? areaOf(area).seats[slot] : spotsOf(area)[-slot - 1]);
|
|
37
54
|
const usedIn = (area) => { if (!taken.has(area)) taken.set(area, new Set()); return taken.get(area); };
|
|
38
55
|
const give = (name, area, slot) => { const p = pos(area, slot); usedIn(area).add(slot); seats.set(name, { area, slot, x: p.x, y: p.y }); };
|
|
39
56
|
for (const w of wants) {
|
|
40
57
|
const p = prev.get(w.name);
|
|
41
|
-
if (!p || p.area !== w.area || !
|
|
58
|
+
if (!p || p.area !== w.area || !areaOf(w.area) || !pos(w.area, p.slot) || usedIn(w.area).has(p.slot)) continue;
|
|
42
59
|
give(w.name, w.area, p.slot);
|
|
43
60
|
}
|
|
44
61
|
for (const w of wants) {
|
|
45
|
-
if (seats.has(w.name) || !
|
|
46
|
-
const used = usedIn(w.area), area =
|
|
62
|
+
if (seats.has(w.name) || !areaOf(w.area)) continue;
|
|
63
|
+
const used = usedIn(w.area), area = areaOf(w.area);
|
|
47
64
|
let slot = area.seats.findIndex((_, i) => !used.has(i));
|
|
48
65
|
if (slot < 0) { const j = spotsOf(w.area).findIndex((_, i) => !used.has(-i - 1)); slot = j < 0 ? null : -j - 1; }
|
|
49
66
|
if (slot === null) crowd.set(w.area, (crowd.get(w.area) || 0) + 1);
|
|
50
67
|
else give(w.name, w.area, slot);
|
|
51
68
|
}
|
|
52
|
-
|
|
69
|
+
// Over capacity: more people want the area than it has seats (their bubbles and tags are thinned, fleet-office.js).
|
|
70
|
+
const over = new Set([...demand].filter(([a, n]) => areaOf(a) && n > areaOf(a).seats.length).map(([a]) => a));
|
|
71
|
+
return { seats, crowd, over };
|
|
53
72
|
}
|
|
54
73
|
|
|
55
74
|
/**
|
|
56
75
|
* The zones layout for `nodes` (buildOrgView's) on a pack: everyone but the missing at their seat. The same shape as
|
|
57
76
|
* the desks layout (rooms → desks with a seat), in logical units, plus `mode: "zones"`, the pack's areas and graph, the
|
|
58
|
-
* seats given (`seats`, the next call's `prev`) and `
|
|
77
|
+
* seats given (`seats`, the next call's `prev`), `crowd` and `over` (the areas over capacity).
|
|
59
78
|
*/
|
|
60
79
|
export function zonesLayout(pack, nodes, prev = new Map()) {
|
|
61
80
|
const wants = nodes.filter((n) => n.state !== "missing").map((n) => ({ name: n.name, area: zoneOf(pack, n.state) }));
|
|
62
|
-
const { seats, crowd } = assignSeats(pack, wants, prev);
|
|
81
|
+
const { seats, crowd, over } = assignSeats(pack, wants, prev);
|
|
63
82
|
const desks = nodes.filter((n) => seats.has(n.name)).map((n) => {
|
|
64
83
|
const s = seats.get(n.name);
|
|
65
84
|
return { key: `zone/${n.name}`, node: n, x: s.x - 24, y: s.y - 52, w: 48, h: 66, seat: { x: s.x, y: s.y }, wp: null, area: s.area, slot: s.slot };
|
|
66
85
|
});
|
|
67
86
|
return { mode: "zones", rooms: [{ key: "\u0000zones", name: null, lobby: false, x: 0, y: 0, w: LOGICAL.w, h: LOGICAL.h, desks }], areas: pack.areas,
|
|
68
|
-
waypoints: pack.waypoints || [], edges: pack.edges || [], door: pack.door, width: LOGICAL.w, height: LOGICAL.h, seats, crowd };
|
|
87
|
+
waypoints: pack.waypoints || [], edges: pack.edges || [], door: pack.door, width: LOGICAL.w, height: LOGICAL.h, seats, crowd, over };
|
|
69
88
|
}
|
|
70
89
|
|
|
71
90
|
// ── Walking ──
|
|
72
91
|
|
|
73
92
|
/** Logical units per ms (crossing the canvas takes about six seconds). */
|
|
74
93
|
export const WALK = { SPEED: 0.2 };
|
|
94
|
+
/** The step of a polyline a fraction `t` (0–1) of the way along it: { dx, dy } (its direction), or null (no length). */
|
|
95
|
+
export function headingAt(pts, t) {
|
|
96
|
+
const total = pathLength(pts);
|
|
97
|
+
if (!total) return null;
|
|
98
|
+
let left = Math.max(0, Math.min(1, t)) * total;
|
|
99
|
+
for (let i = 1; i < pts.length; i++) {
|
|
100
|
+
const dx = pts[i].x - pts[i - 1].x, dy = pts[i].y - pts[i - 1].y, l = Math.hypot(dx, dy);
|
|
101
|
+
if (l > 0 && (left <= l || i === pts.length - 1)) return { dx, dy };
|
|
102
|
+
left -= l;
|
|
103
|
+
}
|
|
104
|
+
return null;
|
|
105
|
+
}
|
|
75
106
|
/**
|
|
76
107
|
* Where each character is. `sync(targets, now, graph, still)`: targets name → { x, y }; someone new is already there;
|
|
77
108
|
* someone whose target moved walks from where they are now along the graph (routeVia) — or is there at once when
|
|
78
|
-
* `still` (reduced motion); someone gone is forgotten. `at(name, now)` → { x, y, walking }
|
|
109
|
+
* `still` (reduced motion); someone gone is forgotten. `at(name, now)` → { x, y, walking } and, while walking, `heading`: the
|
|
110
|
+
* current step's { dx, dy }, which picks a pack's walkDown / walkUp / walkSide strip; `moving(now)`.
|
|
79
111
|
*/
|
|
80
112
|
export function createWalkers() {
|
|
81
113
|
const by = new Map();
|
|
@@ -84,7 +116,7 @@ export function createWalkers() {
|
|
|
84
116
|
const t = (now - w.start) / w.ms;
|
|
85
117
|
if (t >= 1) return { x: w.to.x, y: w.to.y, walking: false };
|
|
86
118
|
const p = along(w.pts, Math.max(0, t));
|
|
87
|
-
return { x: p.x, y: p.y, walking: true };
|
|
119
|
+
return { x: p.x, y: p.y, walking: true, heading: headingAt(w.pts, Math.max(0, t)) };
|
|
88
120
|
};
|
|
89
121
|
return {
|
|
90
122
|
sync(targets, now, graph, still = false) {
|
|
@@ -104,14 +136,17 @@ export function createWalkers() {
|
|
|
104
136
|
|
|
105
137
|
/**
|
|
106
138
|
* The person at (x, y) in layout px as the scene draws them (#2431 review): each desk's box moved to where its person is
|
|
107
|
-
* now (`posOf(desk)`: a walker's position; null: at the seat), the one drawn last (the nearest) tried first
|
|
139
|
+
* now (`posOf(desk)`: a walker's position; null: at the seat), the one drawn last (the nearest) tried first — the same
|
|
140
|
+
* order the scene draws them in. `boxOf(desk, at)` (#2513 review): the box the skin draws that person in there (an
|
|
141
|
+
* uploaded character's strip, anchor and size, in its current pose and walking direction); null: the desk's own box.
|
|
108
142
|
*/
|
|
109
|
-
export function personAt(desks, x, y, posOf) {
|
|
110
|
-
const people = desks.filter((d) => d.node).map((d) => {
|
|
143
|
+
export function personAt(desks, x, y, posOf, boxOf = null) {
|
|
144
|
+
const people = desks.filter((d) => d.node).map((d) => ({ d, at: posOf(d) || { ...d.seat, walking: false, heading: null } }))
|
|
111
145
|
.sort((a, b) => a.at.y - b.at.y);
|
|
112
146
|
for (let i = people.length - 1; i >= 0; i--) {
|
|
113
|
-
const { d,
|
|
114
|
-
|
|
147
|
+
const { d, at } = people[i];
|
|
148
|
+
const b = (boxOf && boxOf(d, at)) || { x: d.x + at.x - d.seat.x, y: d.y + at.y - d.seat.y, w: d.w, h: d.h };
|
|
149
|
+
if (x >= b.x && x < b.x + b.w && y >= b.y && y < b.y + b.h) return d;
|
|
115
150
|
}
|
|
116
151
|
return null;
|
|
117
152
|
}
|
|
@@ -143,11 +178,13 @@ export function bubbleAt(name, state, ms, lines) {
|
|
|
143
178
|
* { key, calling, shown, box, tail? } with `box` the bubble's whole box ({ x, y, w, h }, for its whole line, so it never
|
|
144
179
|
* moves while typing out) and `tail` the point its tail reaches: the strip from the box down to it is kept clear too. The ones calling for the person go first (they always show), then the one that started earliest
|
|
145
180
|
* (the most typed out) — one already showing keeps its place. Each takes its spot, or one row up (`lift`) when that is
|
|
146
|
-
* free; else it waits for another round. Returns the placed ones, each with its `dy` (0 or -lift).
|
|
181
|
+
* free; else it waits for another round. Returns the placed ones, each with its `dy` (0 or -lift). `rank` (optional,
|
|
182
|
+
* bubbleRank): a lower one goes first (else: calling 0, the rest 2); `blocked`: boxes no bubble may cover (name tags).
|
|
147
183
|
*/
|
|
148
|
-
export function placeBubbles(items, lift = 22) {
|
|
149
|
-
const
|
|
150
|
-
const
|
|
184
|
+
export function placeBubbles(items, lift = 22, blocked = []) {
|
|
185
|
+
const rank = (it) => (it.rank ?? (it.calling ? 0 : 2));
|
|
186
|
+
const order = [...items].sort((a, b) => (rank(a) - rank(b)) || (b.shown - a.shown) || (a.key < b.key ? -1 : a.key > b.key ? 1 : 0));
|
|
187
|
+
const taken = [...blocked], out = [];
|
|
151
188
|
const hits = (r) => taken.some((t) => r.x < t.x + t.w && t.x < r.x + r.w && r.y < t.y + t.h && t.y < r.y + r.h);
|
|
152
189
|
for (const it of order) {
|
|
153
190
|
for (const dy of [0, -lift]) {
|
|
@@ -161,10 +198,35 @@ export function placeBubbles(items, lift = 22) {
|
|
|
161
198
|
return out;
|
|
162
199
|
}
|
|
163
200
|
|
|
201
|
+
/** Who speaks first when bubbles compete: calling for the person, then working, then everyone else. */
|
|
202
|
+
export const bubbleRank = (state) => (CALLING.has(state) ? 0 : state === "working" ? 1 : 2);
|
|
203
|
+
/** At most this many bubbles in an area over capacity (#2513). */
|
|
204
|
+
export const CROWD_BUBBLES = 3;
|
|
205
|
+
/** States whose bubbles are left out in an area over capacity (the chatter; a call or work still speaks). */
|
|
206
|
+
const QUIET_IN_CROWD = new Set(["idle", "paused", "stopped", "starting", "queued"]);
|
|
207
|
+
/**
|
|
208
|
+
* The bubbles a frame may show (#2513): in an area over capacity (`over`), none for idle or asleep people and at most
|
|
209
|
+
* CROWD_BUBBLES, the highest ranked first (bubbleRank); elsewhere all of them. `items`: { area, state, shown, key, … }.
|
|
210
|
+
*/
|
|
211
|
+
export function thinBubbles(items, over) {
|
|
212
|
+
const byArea = new Map(), out = [];
|
|
213
|
+
for (const it of items) {
|
|
214
|
+
if (!over || !over.has(it.area)) { out.push(it); continue; }
|
|
215
|
+
if (QUIET_IN_CROWD.has(it.state)) continue;
|
|
216
|
+
if (!byArea.has(it.area)) byArea.set(it.area, []);
|
|
217
|
+
byArea.get(it.area).push(it);
|
|
218
|
+
}
|
|
219
|
+
for (const list of byArea.values()) {
|
|
220
|
+
list.sort((a, b) => (bubbleRank(a.state) - bubbleRank(b.state)) || (b.shown - a.shown) || (a.key < b.key ? -1 : a.key > b.key ? 1 : 0));
|
|
221
|
+
out.push(...list.slice(0, CROWD_BUBBLES));
|
|
222
|
+
}
|
|
223
|
+
return out;
|
|
224
|
+
}
|
|
225
|
+
|
|
164
226
|
/** The lines for a state: the skin's (in the page's language), else the page's own. */
|
|
165
227
|
export function linesFor(state, lang, pack, defaults) {
|
|
166
|
-
const
|
|
167
|
-
return
|
|
228
|
+
const mine = pack && own(own(pack.bubbles, lang), state);
|
|
229
|
+
return Array.isArray(mine) && mine.length ? mine : own(defaults, state) || [];
|
|
168
230
|
}
|
|
169
231
|
|
|
170
232
|
// ── Furniture ──
|