fable/val Public Public: anyone can read this; nobody can change it.

forked from benjivers/val

workbenchthis machine
Files a0d9f596c8eff1543b804d104e75740aa115413c
1
/**
2
 * Coming into sight and going out of it, as arithmetic. The case that
3
 * matters is a bot crossing a doorway: it should arrive over a tenth of a
4
 * second from the side it came from, and leave a mark where it went.
5
 */
6
7
import { expect, test } from "bun:test";
8
import {
9
  ENTRY,
10
  FADE,
11
  forget,
12
  GHOST,
13
  ghosts,
14
  makePresence,
15
  REACH,
16
  shown,
17
  sighted,
18
  slide,
19
  SMALL,
20
  swell,
21
} from "../static/presence.js";
22
23
const body = (over: Record<string, unknown> = {}) => ({
24
  id: "them",
25
  x: 400,
26
  y: 200,
27
  angle: 0,
28
  alive: true,
29
  mate: false,
30
  agent: "sable",
31
  ...over,
32
});
33
34
const here = (x: number, y: number) => ({ x, y, angle: 0 });
35
36
test("a body just in sight is drawn in over a tenth of a second", () => {
37
  const p = makePresence();
38
  sighted(p, [body()], 10);
39
  expect(shown(p, "them", 10)).toBe(0);
40
  expect(shown(p, "them", 10 + FADE / 2)).toBeCloseTo(0.5, 5);
41
  expect(shown(p, "them", 10 + FADE * 1.01)).toBe(1);
42
  expect(shown(p, "them", 30)).toBe(1);
43
  // It starts small and reaches its own size, never past it.
44
  expect(swell(0)).toBe(SMALL);
45
  expect(swell(1)).toBe(1);
46
  expect(swell(4)).toBe(1);
47
});
48
49
test("a body already in sight is not faded in again by the next snapshot", () => {
50
  const p = makePresence();
51
  sighted(p, [body()], 10);
52
  sighted(p, [body({ x: 420 })], 10.03);
53
  sighted(p, [body({ x: 440 })], 10.06);
54
  expect(shown(p, "them", 10.06)).toBeCloseTo(0.5, 5);
55
  expect(shown(p, "them", 10.2)).toBe(1);
56
});
57
58
test("somebody nobody has ever seen is solid, not invisible", () => {
59
  const p = makePresence();
60
  expect(shown(p, "nobody", 10)).toBe(1);
61
  expect(slide(p, "nobody", here(1, 2), 10, here(0, 0))).toEqual(here(1, 2));
62
});
63
64
test("a body that steps back into view slides in from the way it came", () => {
65
  const p = makePresence();
66
  sighted(p, [body({ x: 400, y: 200 })], 10); // seen at the door
67
  sighted(p, [], 10.1); // and gone behind the wall
68
  sighted(p, [body({ x: 500, y: 200 })], 11); // back, further along
69
70
  const out = here(0, 0);
71
  // It begins a stride back down the line it walked, not at its destination.
72
  const start = slide(p, "them", here(500, 200), 11, out);
73
  expect(start.x).toBeCloseTo(500 - ENTRY, 5);
74
  expect(start.y).toBeCloseTo(200, 5);
75
  // Half way through the fade it is half way in.
76
  const half = slide(p, "them", here(500, 200), 11 + FADE / 2, out);
77
  expect(half.x).toBeCloseTo(500 - ENTRY / 2, 5);
78
  // And once it is in, the drawing is the interpolation's, untouched.
79
  const done = slide(p, "them", here(500, 200), 11 + FADE * 1.01, out);
80
  expect(done).toEqual(here(500, 200));
81
});
82
83
test("a body that turns up across the map does not slide across it", () => {
84
  const p = makePresence();
85
  sighted(p, [body({ x: 100, y: 100 })], 10);
86
  sighted(p, [], 10.1);
87
  sighted(p, [body({ x: 100 + REACH + 10, y: 100 })], 12);
88
  const out = here(0, 0);
89
  const at = here(100 + REACH + 10, 100);
90
  expect(slide(p, "them", at, 12, out)).toEqual(at);
91
  // It still fades in: an arrival, just not a walk from anywhere.
92
  expect(shown(p, "them", 12)).toBe(0);
93
});
94
95
test("a body that has not moved since has no direction to come from", () => {
96
  const p = makePresence();
97
  sighted(p, [body({ x: 300, y: 300 })], 10);
98
  sighted(p, [], 10.1);
99
  sighted(p, [body({ x: 300.5, y: 300 })], 11);
100
  const at = here(300.5, 300);
101
  expect(slide(p, "them", at, 11, here(0, 0))).toEqual(at);
102
});
103
104
test("where somebody was last seen is marked, and the mark dims away", () => {
105
  const p = makePresence();
106
  sighted(p, [body({ x: 640, y: 480, agent: "veil" })], 10);
107
  expect(ghosts(p, 10)).toEqual([]);
108
109
  sighted(p, [], 10.5);
110
  const fresh = ghosts(p, 10.5);
111
  expect(fresh.length).toBe(1);
112
  expect(fresh[0]).toMatchObject({ id: "them", x: 640, y: 480, agent: "veil", fade: 1 });
113
  expect(ghosts(p, 10.5 + GHOST / 2)[0]!.fade).toBeCloseTo(0.5, 5);
114
  expect(ghosts(p, 10.5 + GHOST)).toEqual([]);
115
  // And it is forgotten, not kept for ever.
116
  expect(p.last.size).toBe(0);
117
});
118
119
test("a body last seen dead leaves no mark: a corpse is not a question", () => {
120
  const p = makePresence();
121
  sighted(p, [body({ alive: false })], 10);
122
  sighted(p, [], 10.2);
123
  expect(ghosts(p, 10.2)).toEqual([]);
124
});
125
126
test("coming back into sight takes the mark away at once", () => {
127
  const p = makePresence();
128
  sighted(p, [body({ x: 400 })], 10);
129
  sighted(p, [], 10.2);
130
  expect(ghosts(p, 10.3).length).toBe(1);
131
  sighted(p, [body({ x: 430 })], 10.4);
132
  expect(ghosts(p, 10.4)).toEqual([]);
133
});
134
135
test("a body in sight the whole time is never marked and never re-faded", () => {
136
  const p = makePresence();
137
  for (let i = 0; i < 20; i++) sighted(p, [body({ x: 400 + i * 5 })], 10 + i * 0.033);
138
  expect(ghosts(p, 10.7)).toEqual([]);
139
  expect(shown(p, "them", 10.7)).toBe(1);
140
});
141
142
test("a new round forgets everybody", () => {
143
  const p = makePresence();
144
  sighted(p, [body()], 10);
145
  sighted(p, [], 10.2);
146
  forget(p);
147
  expect(ghosts(p, 10.3)).toEqual([]);
148
  expect(p.live.size).toBe(0);
149
  // And the next sighting is a first sighting, with nothing to slide from.
150
  sighted(p, [body({ x: 900 })], 11);
151
  expect(shown(p, "them", 11)).toBe(0);
152
  const at = here(900, 200);
153
  expect(slide(p, "them", at, 11, here(0, 0))).toEqual(at);
154
});
155
156
test("two bodies are tracked apart", () => {
157
  const p = makePresence();
158
  sighted(p, [body({ id: "a" }), body({ id: "b", x: 800 })], 10);
159
  sighted(p, [body({ id: "a" })], 10.2);
160
  expect(shown(p, "a", 10.2)).toBe(1);
161
  const marks = ghosts(p, 10.2);
162
  expect(marks.map((m) => m.id)).toEqual(["b"]);
163
});
↑↓ navigate ↵ open esc close
↑↓ navigate ↵ open esc close

Keyboard shortcuts