@adatechnology/game-crowd 0.0.0-stage → 0.2.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/LICENSE +21 -0
- package/README.md +95 -2
- package/dist/index.d.ts +1128 -0
- package/dist/index.global.js +3655 -0
- package/dist/index.global.js.map +1 -0
- package/dist/index.js +2308 -0
- package/dist/index.js.map +1 -0
- package/package.json +58 -3
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,1128 @@
|
|
|
1
|
+
import { CorpseLedger } from '@adatechnology/game-characters';
|
|
2
|
+
|
|
3
|
+
var numbers = {
|
|
4
|
+
capacity: 6000,
|
|
5
|
+
hysteresis: 10,
|
|
6
|
+
flowRadius: 192,
|
|
7
|
+
flowBudgetMs: 1,
|
|
8
|
+
hashCell: 1,
|
|
9
|
+
nightSight: 0.4,
|
|
10
|
+
crouchSight: 0.6,
|
|
11
|
+
sightCone: 0.5,
|
|
12
|
+
sightNear: 2.5,
|
|
13
|
+
loseAfter: 15,
|
|
14
|
+
hearingBase: 40,
|
|
15
|
+
heardLost: 5,
|
|
16
|
+
alertRadius: 8,
|
|
17
|
+
alertDelay: 0.2,
|
|
18
|
+
alertDelayRandom: 0.4,
|
|
19
|
+
voiceDistance: 40,
|
|
20
|
+
voiceEvery: 0.25,
|
|
21
|
+
directRange: 4,
|
|
22
|
+
pyramidRange: 14,
|
|
23
|
+
screamSpeed: 1.2,
|
|
24
|
+
attackRange: 1.15,
|
|
25
|
+
attackHeight: 1.3,
|
|
26
|
+
attackSlots: 6,
|
|
27
|
+
attackEvery: 1.5,
|
|
28
|
+
crouchBite: 1.3,
|
|
29
|
+
crawlDamage: 0.6,
|
|
30
|
+
wanderSpan: 24,
|
|
31
|
+
crawlSpeed: 0.4,
|
|
32
|
+
limpSpeed: 0.5,
|
|
33
|
+
separation: 0.31,
|
|
34
|
+
separationPush: 2.2,
|
|
35
|
+
doorDamage: 10,
|
|
36
|
+
doorMessageDistance: 25,
|
|
37
|
+
skullMinDamage: 20,
|
|
38
|
+
skullTakeDamage: 60,
|
|
39
|
+
skullTakeWithin: {
|
|
40
|
+
"12ga": 5
|
|
41
|
+
},
|
|
42
|
+
jawDamage: 25,
|
|
43
|
+
jawChance: 0.3,
|
|
44
|
+
hitStunDamage: 35,
|
|
45
|
+
hitStun: 0.45,
|
|
46
|
+
dormantWake: 3,
|
|
47
|
+
dormantWakeBehind: 10,
|
|
48
|
+
pileStep: 0.48,
|
|
49
|
+
pileTop: 3.7,
|
|
50
|
+
pileMax: 160,
|
|
51
|
+
pileReleaseDistance: 30,
|
|
52
|
+
gravity: 9.8,
|
|
53
|
+
fallStun: 3.2,
|
|
54
|
+
climbSpeed: 1.9,
|
|
55
|
+
cadenceBase: 0.5,
|
|
56
|
+
cadencePerSpeed: 0.3,
|
|
57
|
+
corpsesMax: 400,
|
|
58
|
+
corpseSeconds: 900,
|
|
59
|
+
trailSeconds: 120,
|
|
60
|
+
trailStep: 1.5,
|
|
61
|
+
trailMax: 200,
|
|
62
|
+
population: 1200,
|
|
63
|
+
refillMin: 70,
|
|
64
|
+
refillMax: 160,
|
|
65
|
+
migrationFirst: 60
|
|
66
|
+
};
|
|
67
|
+
var defaults = {
|
|
68
|
+
numbers: numbers
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
/** Occupancy codes of a grid cell (G 62162: 0 free, 1 solid, 2 low wall that can be climbed, 3 open door, 4 glass; 5 closed door, G 63816). */
|
|
72
|
+
declare const CELL: {
|
|
73
|
+
readonly FREE: 0;
|
|
74
|
+
readonly SOLID: 1;
|
|
75
|
+
readonly LOW_WALL: 2;
|
|
76
|
+
readonly OPEN_DOOR: 3;
|
|
77
|
+
readonly GLASS: 4;
|
|
78
|
+
readonly CLOSED_DOOR: 5;
|
|
79
|
+
};
|
|
80
|
+
type NavGridOptions = {
|
|
81
|
+
/** Side of the square world in metres, centred on the origin (default 768, the game's world). */
|
|
82
|
+
readonly size?: number;
|
|
83
|
+
/** Cell side in metres (default 0.5). */
|
|
84
|
+
readonly cell?: number;
|
|
85
|
+
/** Fill a solid border of `borderWidth` m and `borderHeight` m around the world, as the game does (default true). */
|
|
86
|
+
readonly border?: boolean;
|
|
87
|
+
};
|
|
88
|
+
/**
|
|
89
|
+
* The navigation and collision grid of the game (G 62158-62170): a square world of cells with an occupancy code and a height. Agents, the player,
|
|
90
|
+
* the flow field and line of sight all read it. Buildings write it with `fillRect`.
|
|
91
|
+
*/
|
|
92
|
+
type NavGrid = {
|
|
93
|
+
readonly size: number;
|
|
94
|
+
readonly half: number;
|
|
95
|
+
readonly cell: number;
|
|
96
|
+
/** Cells per side. */
|
|
97
|
+
readonly n: number;
|
|
98
|
+
readonly occ: Uint8Array;
|
|
99
|
+
readonly occH: Float32Array;
|
|
100
|
+
cellOf(x: number, z: number): number;
|
|
101
|
+
/** Solid for a body at height `y` (default 0.5): outside the world, or an occupied cell that is not an open door and is taller than `y`. */
|
|
102
|
+
solidAt(x: number, z: number, y?: number): boolean;
|
|
103
|
+
/** The occupancy code at (x, z), -1 outside. */
|
|
104
|
+
cellKind(x: number, z: number): number;
|
|
105
|
+
fillRect(x0: number, z0: number, x1: number, z1: number, kind: number, height: number): void;
|
|
106
|
+
/** Blocked for a walking agent: outside, or anything but free and open door (G 66826 `zBlocked`). */
|
|
107
|
+
blocked(x: number, z: number): boolean;
|
|
108
|
+
/** Nothing solid and taller than 1.5 m between the two points, sampled every 0.5 m (G 66828 `losClear`). */
|
|
109
|
+
losClear(x0: number, z0: number, x1: number, z1: number): boolean;
|
|
110
|
+
};
|
|
111
|
+
declare function createNavGrid(options?: NavGridOptions): NavGrid;
|
|
112
|
+
|
|
113
|
+
type Door = {
|
|
114
|
+
readonly x: number;
|
|
115
|
+
readonly z: number;
|
|
116
|
+
/** The leaf runs along `x` (front or back wall) or `z`. */
|
|
117
|
+
readonly axis: 'x' | 'z';
|
|
118
|
+
readonly width: number;
|
|
119
|
+
hp: number;
|
|
120
|
+
hpMax: number;
|
|
121
|
+
open: boolean;
|
|
122
|
+
broken: boolean;
|
|
123
|
+
planks: number;
|
|
124
|
+
readonly rect: readonly [number, number, number, number];
|
|
125
|
+
/** Whatever the game hangs on it (the building it belongs to). */
|
|
126
|
+
readonly data?: unknown;
|
|
127
|
+
};
|
|
128
|
+
type DoorEventMap = {
|
|
129
|
+
sound: {
|
|
130
|
+
sound: 'wood';
|
|
131
|
+
volume: number;
|
|
132
|
+
position: [number, number, number];
|
|
133
|
+
};
|
|
134
|
+
noise: {
|
|
135
|
+
x: number;
|
|
136
|
+
z: number;
|
|
137
|
+
radius: number;
|
|
138
|
+
};
|
|
139
|
+
effect: {
|
|
140
|
+
effect: 'dust';
|
|
141
|
+
point: [number, number, number];
|
|
142
|
+
color: number;
|
|
143
|
+
};
|
|
144
|
+
broken: {
|
|
145
|
+
door: number;
|
|
146
|
+
};
|
|
147
|
+
};
|
|
148
|
+
type DoorEventName = keyof DoorEventMap;
|
|
149
|
+
type DoorNumbers = {
|
|
150
|
+
/** Hit points of a door (G 63803 `PORTA_VIDA`). */
|
|
151
|
+
readonly doorHp: number;
|
|
152
|
+
/** Hit points each plank adds (G 63803 `TABUA_VIDA`). */
|
|
153
|
+
readonly plankHp: number;
|
|
154
|
+
readonly height: number;
|
|
155
|
+
readonly thickness: number;
|
|
156
|
+
readonly soundChance: number;
|
|
157
|
+
readonly soundVolume: number;
|
|
158
|
+
readonly breakVolume: number;
|
|
159
|
+
readonly breakNoise: number;
|
|
160
|
+
};
|
|
161
|
+
declare const DOOR_DEFAULTS: DoorNumbers;
|
|
162
|
+
type Doors = {
|
|
163
|
+
readonly list: readonly Door[];
|
|
164
|
+
/** The door index at a grid cell, -1 for none. */
|
|
165
|
+
at(cell: number): number;
|
|
166
|
+
add(x: number, z: number, axis: 'x' | 'z', width: number, data?: unknown): number;
|
|
167
|
+
/** Opens or closes: the cells become passable (3) or a closed door (5). A broken door stays open. */
|
|
168
|
+
set(index: number, open: boolean): void;
|
|
169
|
+
/** An agent hits a closed door (G 64044 `doorHit`): the 30% knock, planks giving way, and the door breaking open. */
|
|
170
|
+
hit(index: number, damage: number): void;
|
|
171
|
+
/** Nails a plank on (each adds `plankHp`). */
|
|
172
|
+
plank(index: number): void;
|
|
173
|
+
on<K extends DoorEventName>(event: K, listener: (event: DoorEventMap[K]) => void): () => void;
|
|
174
|
+
};
|
|
175
|
+
/** The doors of the game's buildings on a grid (G 63796-63816 `DOORS`, `doorAt`, `addDoor`, `setDoor`; G 64044 `doorHit`). */
|
|
176
|
+
declare function createDoors(grid: NavGrid, options: {
|
|
177
|
+
random: () => number;
|
|
178
|
+
numbers?: Partial<DoorNumbers>;
|
|
179
|
+
}): Doors;
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* The agents as a struct of arrays (G 66717 `Z`, ZMAX 6000): one typed array per field, the same types as the game so the floats round the same way.
|
|
183
|
+
* The names are the game's in English; `armHp` and `legHp` hold two values per agent (left, right).
|
|
184
|
+
*/
|
|
185
|
+
declare const createStore: (capacity: number) => {
|
|
186
|
+
n: number;
|
|
187
|
+
capacity: number;
|
|
188
|
+
x: Float32Array<ArrayBuffer>;
|
|
189
|
+
z: Float32Array<ArrayBuffer>;
|
|
190
|
+
vx: Float32Array<ArrayBuffer>;
|
|
191
|
+
vz: Float32Array<ArrayBuffer>;
|
|
192
|
+
yaw: Float32Array<ArrayBuffer>;
|
|
193
|
+
phase: Float32Array<ArrayBuffer>;
|
|
194
|
+
type: Uint8Array<ArrayBuffer>;
|
|
195
|
+
age: Uint8Array<ArrayBuffer>;
|
|
196
|
+
outfit: Uint8Array<ArrayBuffer>;
|
|
197
|
+
height: Float32Array<ArrayBuffer>;
|
|
198
|
+
build: Float32Array<ArrayBuffer>;
|
|
199
|
+
chaseSpeed: Float32Array<ArrayBuffer>;
|
|
200
|
+
wanderSpeed: Float32Array<ArrayBuffer>;
|
|
201
|
+
hp: Float32Array<ArrayBuffer>;
|
|
202
|
+
hpMax: Float32Array<ArrayBuffer>;
|
|
203
|
+
headHp: Float32Array<ArrayBuffer>;
|
|
204
|
+
armHp: Float32Array<ArrayBuffer>;
|
|
205
|
+
legHp: Float32Array<ArrayBuffer>;
|
|
206
|
+
missing: Uint16Array<ArrayBuffer>;
|
|
207
|
+
helmet: Uint8Array<ArrayBuffer>;
|
|
208
|
+
state: Uint8Array<ArrayBuffer>;
|
|
209
|
+
stateTimer: Float32Array<ArrayBuffer>;
|
|
210
|
+
lost: Float32Array<ArrayBuffer>;
|
|
211
|
+
attackTimer: Float32Array<ArrayBuffer>;
|
|
212
|
+
band: Uint8Array<ArrayBuffer>;
|
|
213
|
+
next: Float32Array<ArrayBuffer>;
|
|
214
|
+
wx: Float32Array<ArrayBuffer>;
|
|
215
|
+
wz: Float32Array<ArrayBuffer>;
|
|
216
|
+
crawl: Uint8Array<ArrayBuffer>;
|
|
217
|
+
limp: Uint8Array<ArrayBuffer>;
|
|
218
|
+
color: Uint32Array<ArrayBuffer>;
|
|
219
|
+
skin: Float32Array<ArrayBuffer>;
|
|
220
|
+
alertIn: Float32Array<ArrayBuffer>;
|
|
221
|
+
cooldown: Float32Array<ArrayBuffer>;
|
|
222
|
+
y: Float32Array<ArrayBuffer>;
|
|
223
|
+
floor: Uint8Array<ArrayBuffer>;
|
|
224
|
+
floorLocked: Uint8Array<ArrayBuffer>;
|
|
225
|
+
vy: Float32Array<ArrayBuffer>;
|
|
226
|
+
abilityTimer: Float32Array<ArrayBuffer>;
|
|
227
|
+
eaten: Uint8Array<ArrayBuffer>;
|
|
228
|
+
stuck: Float32Array<ArrayBuffer>;
|
|
229
|
+
stepCell: Int32Array<ArrayBuffer>;
|
|
230
|
+
burn: Float32Array<ArrayBuffer>;
|
|
231
|
+
hunts: Int8Array<ArrayBuffer>;
|
|
232
|
+
named: Int8Array<ArrayBuffer>;
|
|
233
|
+
dvx: Float32Array<ArrayBuffer>;
|
|
234
|
+
dvz: Float32Array<ArrayBuffer>;
|
|
235
|
+
steering: Uint8Array<ArrayBuffer>;
|
|
236
|
+
renderYaw: Float32Array<ArrayBuffer>;
|
|
237
|
+
renderSpeed: Float32Array<ArrayBuffer>;
|
|
238
|
+
pause: Float32Array<ArrayBuffer>;
|
|
239
|
+
lod: Uint8Array<ArrayBuffer>;
|
|
240
|
+
variant: Uint8Array<ArrayBuffer>;
|
|
241
|
+
attackPose: Uint8Array<ArrayBuffer>;
|
|
242
|
+
arms: Float32Array<ArrayBuffer>;
|
|
243
|
+
};
|
|
244
|
+
type CrowdStore = ReturnType<typeof createStore>;
|
|
245
|
+
/** The one-per-agent fields (G 66733 `FIELDS`): what a removal copies from the last agent. */
|
|
246
|
+
declare const AGENT_FIELDS: readonly ["x", "z", "vx", "vz", "yaw", "phase", "type", "age", "outfit", "height", "build", "chaseSpeed", "wanderSpeed", "hp", "hpMax", "headHp", "missing", "helmet", "state", "stateTimer", "lost", "attackTimer", "band", "next", "wx", "wz", "crawl", "limp", "color", "skin", "alertIn", "cooldown", "y", "floor", "floorLocked", "vy", "abilityTimer", "eaten", "stuck", "stepCell", "burn", "hunts", "named", "dvx", "dvz", "steering", "renderYaw", "renderSpeed", "pause", "lod", "variant", "attackPose", "arms"];
|
|
247
|
+
|
|
248
|
+
/** What an agent is doing (G 66724 and 67180-67183): the store keeps the number. */
|
|
249
|
+
declare const STATE: {
|
|
250
|
+
readonly WANDER: 0;
|
|
251
|
+
readonly CHASE: 1;
|
|
252
|
+
readonly GRAB: 2;
|
|
253
|
+
readonly STUNNED: 3;
|
|
254
|
+
readonly CALLING: 4;
|
|
255
|
+
readonly AIRBORNE: 5;
|
|
256
|
+
readonly DORMANT: 6;
|
|
257
|
+
readonly SWELLING: 7;
|
|
258
|
+
readonly SWING: 8;
|
|
259
|
+
readonly EATING: 9;
|
|
260
|
+
readonly PILE_STEP: 10;
|
|
261
|
+
readonly SEEKING_SOUND: 12;
|
|
262
|
+
};
|
|
263
|
+
/** Body regions of a hit (G 67012): 0 head, 1 torso, 2 left arm, 3 right arm, 4 left leg, 5 right leg. */
|
|
264
|
+
type Region = 0 | 1 | 2 | 3 | 4 | 5;
|
|
265
|
+
/**
|
|
266
|
+
* Missing parts as bits (G 67010-67045): 1 skull, 2 left arm off, 4 right arm off, 8 left leg off, 16 right leg off, 32 left arm broken, 64 right arm broken,
|
|
267
|
+
* 128 left leg broken, 256 right leg broken, 512 jaw.
|
|
268
|
+
*/
|
|
269
|
+
declare const MISSING: {
|
|
270
|
+
readonly SKULL: 1;
|
|
271
|
+
readonly ARM_L: 2;
|
|
272
|
+
readonly ARM_R: 4;
|
|
273
|
+
readonly LEG_L: 8;
|
|
274
|
+
readonly LEG_R: 16;
|
|
275
|
+
readonly ARM_L_BROKEN: 32;
|
|
276
|
+
readonly ARM_R_BROKEN: 64;
|
|
277
|
+
readonly LEG_L_BROKEN: 128;
|
|
278
|
+
readonly LEG_R_BROKEN: 256;
|
|
279
|
+
readonly JAW: 512;
|
|
280
|
+
};
|
|
281
|
+
/**
|
|
282
|
+
* The type traits: the special moves of a type, read in the game's order. A type without a trait does not have the move. Every number is the game's
|
|
283
|
+
* (`jogo.js` G 67180-67430, the Bestiário table 3.1 and 12.7).
|
|
284
|
+
*/
|
|
285
|
+
type CrowdTraits = {
|
|
286
|
+
/** Jumps a low obstacle in the way while chasing (car, yard wall) up to `maxHeight` m (runner, leaper). */
|
|
287
|
+
readonly vaultsLow?: {
|
|
288
|
+
readonly maxHeight: number;
|
|
289
|
+
readonly minRise: number;
|
|
290
|
+
readonly clearance: number;
|
|
291
|
+
readonly speedFactor: number;
|
|
292
|
+
};
|
|
293
|
+
/** Pounce from `min` to `max` m in line of sight: cooldown, flight time, speed cap, the vertical speeds and the knock-down on landing (leaper). */
|
|
294
|
+
readonly pounce?: {
|
|
295
|
+
readonly min: number;
|
|
296
|
+
readonly max: number;
|
|
297
|
+
readonly cooldown: number;
|
|
298
|
+
readonly time: number;
|
|
299
|
+
readonly speedCap: number;
|
|
300
|
+
readonly lift: number;
|
|
301
|
+
readonly liftHigh: number;
|
|
302
|
+
readonly highAbove: number;
|
|
303
|
+
readonly landRange: number;
|
|
304
|
+
readonly knock: number;
|
|
305
|
+
};
|
|
306
|
+
/** A heavy swing: chance per attack, wind-up, reach and knock-down (brute). */
|
|
307
|
+
readonly heavySwing?: {
|
|
308
|
+
readonly chance: number;
|
|
309
|
+
readonly windUp: number;
|
|
310
|
+
readonly range: number;
|
|
311
|
+
readonly knock: number;
|
|
312
|
+
};
|
|
313
|
+
/** Multiplies the damage on doors (brute 3). */
|
|
314
|
+
readonly doorDamage?: number;
|
|
315
|
+
/** Seconds stunned by a heavy hit (default `numbers.hitStun`; brute 0.25). */
|
|
316
|
+
readonly hitStun?: number;
|
|
317
|
+
/** Only hears: goes to the source of a sound and hits whatever it meets on the way, other agents too (blind). */
|
|
318
|
+
readonly soundSeeker?: {
|
|
319
|
+
readonly arrive: number;
|
|
320
|
+
readonly loseChase: number;
|
|
321
|
+
readonly hitRadius2: number;
|
|
322
|
+
};
|
|
323
|
+
/** Calls the crowd: wind-up, radius, cooldown, the boost it gives the target, and running from the fight afterwards (screamer). */
|
|
324
|
+
readonly caller?: {
|
|
325
|
+
readonly range: number;
|
|
326
|
+
readonly windUp: number;
|
|
327
|
+
readonly radius: number;
|
|
328
|
+
readonly cooldown: number;
|
|
329
|
+
readonly boost: number;
|
|
330
|
+
readonly fleeAbove: number;
|
|
331
|
+
readonly fleeRange: number;
|
|
332
|
+
};
|
|
333
|
+
/** Sets the target on fire on a hit (charred). */
|
|
334
|
+
readonly burns?: {
|
|
335
|
+
readonly seconds: number;
|
|
336
|
+
};
|
|
337
|
+
/** Loses a share of its health the first time it enters water (charred 0.7). */
|
|
338
|
+
readonly waterWeak?: {
|
|
339
|
+
readonly keep: number;
|
|
340
|
+
readonly cloud: number;
|
|
341
|
+
};
|
|
342
|
+
/** Waits under water and pulls the target down (drowned). */
|
|
343
|
+
readonly submerged?: {
|
|
344
|
+
readonly depth: number;
|
|
345
|
+
readonly wake: number;
|
|
346
|
+
readonly swim: number;
|
|
347
|
+
readonly surface: number;
|
|
348
|
+
};
|
|
349
|
+
/** Plays dead and wakes close or behind the target, then sprints for a while (stalker). */
|
|
350
|
+
readonly ambush?: {
|
|
351
|
+
readonly chance: number;
|
|
352
|
+
readonly wake: number;
|
|
353
|
+
readonly wakeBehind: number;
|
|
354
|
+
readonly behindCos: number;
|
|
355
|
+
readonly sprint: number;
|
|
356
|
+
readonly sprintSeconds: number;
|
|
357
|
+
readonly slow: number;
|
|
358
|
+
};
|
|
359
|
+
/** Swells and bursts close to the target: blinds and marks it with a scent (bloater). */
|
|
360
|
+
readonly burst?: {
|
|
361
|
+
readonly range: number;
|
|
362
|
+
readonly swell: number;
|
|
363
|
+
readonly radius: number;
|
|
364
|
+
readonly blind: number;
|
|
365
|
+
readonly scent: number;
|
|
366
|
+
readonly noiseNear: number;
|
|
367
|
+
readonly noise: number;
|
|
368
|
+
readonly cloudColor: number;
|
|
369
|
+
readonly bloodColor: number;
|
|
370
|
+
readonly bloodDry: number;
|
|
371
|
+
};
|
|
372
|
+
/** Eats corpses: search radius, reach, seconds, how many, what it gains (devourer). */
|
|
373
|
+
readonly eatsCorpses?: {
|
|
374
|
+
readonly max: number;
|
|
375
|
+
readonly search: number;
|
|
376
|
+
readonly reach: number;
|
|
377
|
+
readonly seconds: number;
|
|
378
|
+
readonly grabRange: number;
|
|
379
|
+
readonly health: number;
|
|
380
|
+
readonly grow: number;
|
|
381
|
+
readonly rest: number;
|
|
382
|
+
readonly retry: number;
|
|
383
|
+
readonly defend: number;
|
|
384
|
+
readonly approach: number;
|
|
385
|
+
};
|
|
386
|
+
/** Follows the target's blood trail and leads agents of the type `leads` along (sniffer). */
|
|
387
|
+
readonly tracker?: {
|
|
388
|
+
readonly range: number;
|
|
389
|
+
readonly leads: string;
|
|
390
|
+
readonly max: number;
|
|
391
|
+
readonly leadRadius: number;
|
|
392
|
+
};
|
|
393
|
+
/** Never older than this age index (runner: recent at most). */
|
|
394
|
+
readonly maxAge?: number;
|
|
395
|
+
/** The groan sound id (runner `runner_groan`; default `groan`). */
|
|
396
|
+
readonly voice?: string;
|
|
397
|
+
/** How much it adds to the target's panic (runner 2.5). */
|
|
398
|
+
readonly panicWeight?: number;
|
|
399
|
+
/** Pulls the target into water when it grabs there (drowned). */
|
|
400
|
+
readonly drownGrab?: boolean;
|
|
401
|
+
/** Body colour and skin override at birth (charred, drowned). */
|
|
402
|
+
readonly color?: number;
|
|
403
|
+
readonly skin?: number;
|
|
404
|
+
};
|
|
405
|
+
/** One type of agent (a zombie type, a cow, a civilian). The undead pack (`undeadCrowdTypes`) gives the 13 types of the game. */
|
|
406
|
+
type CrowdType = {
|
|
407
|
+
readonly id: string;
|
|
408
|
+
/** Weight in the draw of an agent without a forced type (0: never drawn). */
|
|
409
|
+
readonly weight: number;
|
|
410
|
+
readonly health: number;
|
|
411
|
+
readonly speed: {
|
|
412
|
+
readonly wander: number;
|
|
413
|
+
readonly chase: number;
|
|
414
|
+
};
|
|
415
|
+
readonly damage: number;
|
|
416
|
+
/** Chance per attack to grab (and bite). */
|
|
417
|
+
readonly bite: number;
|
|
418
|
+
readonly multipliers: {
|
|
419
|
+
readonly head: number;
|
|
420
|
+
readonly torso: number;
|
|
421
|
+
readonly arms: number;
|
|
422
|
+
readonly legs: number;
|
|
423
|
+
};
|
|
424
|
+
/** Metres. */
|
|
425
|
+
readonly perception: {
|
|
426
|
+
readonly sight: number;
|
|
427
|
+
readonly hearing: number;
|
|
428
|
+
readonly smell: number;
|
|
429
|
+
};
|
|
430
|
+
readonly crawls?: boolean;
|
|
431
|
+
/** Height multiplier (brute 1.42). */
|
|
432
|
+
readonly scale?: number;
|
|
433
|
+
/** Build multiplier (bloater 1.35; a scaled type without one is 1.3). */
|
|
434
|
+
readonly build?: number;
|
|
435
|
+
/** Body variants of the type for the renderer (walker 4, runner 3, crawler and brute 2, others 1). */
|
|
436
|
+
readonly variants?: number;
|
|
437
|
+
readonly eye?: number;
|
|
438
|
+
readonly traits?: CrowdTraits;
|
|
439
|
+
};
|
|
440
|
+
/** The age of a body (G IDADES): its share, and what it does to speed, health, limbs and senses. */
|
|
441
|
+
type CrowdAge = {
|
|
442
|
+
readonly id: string;
|
|
443
|
+
readonly p: number;
|
|
444
|
+
readonly speed: number;
|
|
445
|
+
readonly health: number;
|
|
446
|
+
readonly limb: number;
|
|
447
|
+
readonly sight: number;
|
|
448
|
+
readonly hearing: number;
|
|
449
|
+
readonly blood: number;
|
|
450
|
+
readonly bloodColor: number;
|
|
451
|
+
readonly dryColor: number;
|
|
452
|
+
};
|
|
453
|
+
/** What a body wears (G ROUPAS): its share, the vest against pistol and rifle classes, a helmet, a limb factor and the colour. */
|
|
454
|
+
type CrowdOutfit = {
|
|
455
|
+
readonly id: string;
|
|
456
|
+
readonly p: number;
|
|
457
|
+
readonly vest?: {
|
|
458
|
+
readonly pistol: number;
|
|
459
|
+
readonly rifle: number;
|
|
460
|
+
};
|
|
461
|
+
readonly helmet?: boolean;
|
|
462
|
+
readonly limb?: number;
|
|
463
|
+
readonly color: number | null;
|
|
464
|
+
};
|
|
465
|
+
/** Everything the crowd draws a body from. */
|
|
466
|
+
type CrowdPack = {
|
|
467
|
+
readonly types: readonly CrowdType[];
|
|
468
|
+
readonly ages: readonly CrowdAge[];
|
|
469
|
+
readonly outfits: readonly CrowdOutfit[];
|
|
470
|
+
/** Hit points of the segments, only for dismembering (G `SEG`). */
|
|
471
|
+
readonly segments: {
|
|
472
|
+
readonly head: number;
|
|
473
|
+
readonly arm: number;
|
|
474
|
+
readonly leg: number;
|
|
475
|
+
};
|
|
476
|
+
/** Clothes colours of the outfits without one (G `CIVIL_COR`). */
|
|
477
|
+
readonly palette: readonly number[];
|
|
478
|
+
};
|
|
479
|
+
/** The calibre of a projectile hit: its class (pistol or rifle, for vests and helmets), the skull distance (1: any) and an id. */
|
|
480
|
+
type CrowdCaliber = {
|
|
481
|
+
readonly id: string;
|
|
482
|
+
readonly class: 'pistol' | 'rifle';
|
|
483
|
+
readonly skull: number;
|
|
484
|
+
};
|
|
485
|
+
type CrowdHit = {
|
|
486
|
+
readonly region: Region;
|
|
487
|
+
readonly amount: number;
|
|
488
|
+
readonly distance: number;
|
|
489
|
+
readonly cut?: number;
|
|
490
|
+
readonly caliber?: CrowdCaliber | null;
|
|
491
|
+
};
|
|
492
|
+
type CrowdDamageResult = {
|
|
493
|
+
readonly died: boolean;
|
|
494
|
+
readonly headshot?: boolean;
|
|
495
|
+
};
|
|
496
|
+
/**
|
|
497
|
+
* Who the crowd hunts. `game-player`'s `Player` is one as it is; a game with its own player writes a small object with the same names.
|
|
498
|
+
* Reads: `state`. Writes: the verbs, and `state.burnTimer`, `state.blind`, `state.scentTimer`, `state.screamBoost`.
|
|
499
|
+
*/
|
|
500
|
+
interface CrowdTarget {
|
|
501
|
+
readonly state: {
|
|
502
|
+
x: number;
|
|
503
|
+
z: number;
|
|
504
|
+
y: number;
|
|
505
|
+
floor: number;
|
|
506
|
+
alive: boolean;
|
|
507
|
+
turned: boolean;
|
|
508
|
+
crouch: boolean;
|
|
509
|
+
bleeding: number;
|
|
510
|
+
scentTimer: number;
|
|
511
|
+
screamBoost: number;
|
|
512
|
+
grabbedBy: number;
|
|
513
|
+
blind: number;
|
|
514
|
+
burnTimer: number;
|
|
515
|
+
/** The body's yaw; the view looks the other way (`yaw - π`). */
|
|
516
|
+
yaw: number;
|
|
517
|
+
};
|
|
518
|
+
grab(by: number, noJaw?: boolean, drown?: boolean): void;
|
|
519
|
+
hurt(amount: number, by?: number): void;
|
|
520
|
+
knock(seconds: number): void;
|
|
521
|
+
release(): void;
|
|
522
|
+
}
|
|
523
|
+
type CrowdSoundId = 'groan' | 'runner_groan' | 'scream_hoarse' | 'step' | 'impact' | 'flesh' | 'wood' | (string & {});
|
|
524
|
+
type CrowdEffectId = 'spark' | 'blood' | 'limb' | 'cloud' | 'dust' | (string & {});
|
|
525
|
+
type CrowdMessageId = 'called' | 'burst_hit' | 'swing_knock' | 'pounce_knock' | 'migration' | 'door_broken' | (string & {});
|
|
526
|
+
type CrowdEventMap = {
|
|
527
|
+
sound: {
|
|
528
|
+
sound: CrowdSoundId;
|
|
529
|
+
volume: number;
|
|
530
|
+
position: [number, number, number];
|
|
531
|
+
distance: number;
|
|
532
|
+
};
|
|
533
|
+
effect: {
|
|
534
|
+
effect: CrowdEffectId;
|
|
535
|
+
point: [number, number, number];
|
|
536
|
+
agent?: number;
|
|
537
|
+
region?: number;
|
|
538
|
+
severed?: boolean;
|
|
539
|
+
radius?: number;
|
|
540
|
+
color?: number;
|
|
541
|
+
amount?: number;
|
|
542
|
+
died?: boolean;
|
|
543
|
+
age?: number;
|
|
544
|
+
};
|
|
545
|
+
message: {
|
|
546
|
+
id: CrowdMessageId;
|
|
547
|
+
seconds: number;
|
|
548
|
+
type?: string;
|
|
549
|
+
};
|
|
550
|
+
spawn: {
|
|
551
|
+
agent: number;
|
|
552
|
+
type: string;
|
|
553
|
+
};
|
|
554
|
+
alert: {
|
|
555
|
+
agent: number;
|
|
556
|
+
};
|
|
557
|
+
kill: {
|
|
558
|
+
agent: number;
|
|
559
|
+
type: string;
|
|
560
|
+
headshot: boolean;
|
|
561
|
+
x: number;
|
|
562
|
+
z: number;
|
|
563
|
+
};
|
|
564
|
+
remove: {
|
|
565
|
+
agent: number;
|
|
566
|
+
moved: number;
|
|
567
|
+
};
|
|
568
|
+
scream: {
|
|
569
|
+
agent: number;
|
|
570
|
+
x: number;
|
|
571
|
+
z: number;
|
|
572
|
+
};
|
|
573
|
+
};
|
|
574
|
+
type CrowdEventName = keyof CrowdEventMap;
|
|
575
|
+
|
|
576
|
+
type CrowdNumbers = typeof defaults.numbers;
|
|
577
|
+
type CrowdBand = {
|
|
578
|
+
readonly max: number;
|
|
579
|
+
readonly dt: number;
|
|
580
|
+
};
|
|
581
|
+
/** The game's numbers; `bands[3].max` is `Infinity` (JSON keeps it as null). */
|
|
582
|
+
declare const CROWD_DEFAULTS: {
|
|
583
|
+
readonly sources: Readonly<Record<string, string>>;
|
|
584
|
+
readonly bands: readonly CrowdBand[];
|
|
585
|
+
readonly numbers: CrowdNumbers;
|
|
586
|
+
};
|
|
587
|
+
/** A body on the ground (G 67062 `CP`). */
|
|
588
|
+
type Corpse = {
|
|
589
|
+
readonly x: number;
|
|
590
|
+
readonly z: number;
|
|
591
|
+
readonly yaw: number;
|
|
592
|
+
readonly height: number;
|
|
593
|
+
readonly build: number;
|
|
594
|
+
readonly missing: number;
|
|
595
|
+
readonly color: number;
|
|
596
|
+
/** Body variant of the renderer, -1 for a body that was not an agent (a civilian). */
|
|
597
|
+
readonly variant: number;
|
|
598
|
+
readonly skin: number;
|
|
599
|
+
readonly seed: number;
|
|
600
|
+
readonly named: number;
|
|
601
|
+
};
|
|
602
|
+
/** A custom move: runs on every decision tick after the timed states and before the moves on the target; `true` means it took care of the movement. */
|
|
603
|
+
type CrowdPlugin = {
|
|
604
|
+
readonly id: string;
|
|
605
|
+
ability?(crowd: Crowd, i: number, context: {
|
|
606
|
+
d: number;
|
|
607
|
+
dx: number;
|
|
608
|
+
dz: number;
|
|
609
|
+
tdt: number;
|
|
610
|
+
band: number;
|
|
611
|
+
alive: boolean;
|
|
612
|
+
}): boolean;
|
|
613
|
+
};
|
|
614
|
+
/** A migration: `count` agents every `every` s (the first after `numbers.migrationFirst`), born in the box at (x, z) and walking to `goal`. */
|
|
615
|
+
type MigrationOptions = {
|
|
616
|
+
readonly every: number;
|
|
617
|
+
readonly count: number;
|
|
618
|
+
readonly x: number;
|
|
619
|
+
readonly z: number;
|
|
620
|
+
readonly width: number;
|
|
621
|
+
readonly depth: number;
|
|
622
|
+
readonly goal: readonly [number, number];
|
|
623
|
+
};
|
|
624
|
+
type CrowdOptions = {
|
|
625
|
+
readonly pack: CrowdPack;
|
|
626
|
+
readonly random?: () => number;
|
|
627
|
+
readonly seed?: number;
|
|
628
|
+
readonly capacity?: number;
|
|
629
|
+
readonly grid?: NavGrid;
|
|
630
|
+
readonly doors?: Doors;
|
|
631
|
+
/** Water at (x, z): the drowned swim, the charred lose health (the game's `POOL`). */
|
|
632
|
+
readonly water?: (x: number, z: number) => boolean;
|
|
633
|
+
readonly numbers?: Partial<CrowdNumbers>;
|
|
634
|
+
readonly bands?: readonly CrowdBand[];
|
|
635
|
+
/** Flow field: half window in cells (192), and the clock its time budget reads (default `performance.now`; pass `() => 0` to finish every field in one frame). */
|
|
636
|
+
readonly flow?: {
|
|
637
|
+
readonly radius?: number;
|
|
638
|
+
readonly clock?: () => number;
|
|
639
|
+
};
|
|
640
|
+
readonly plugins?: readonly CrowdPlugin[];
|
|
641
|
+
readonly target?: CrowdTarget | null;
|
|
642
|
+
};
|
|
643
|
+
type CrowdView = {
|
|
644
|
+
readonly x: number;
|
|
645
|
+
readonly z: number;
|
|
646
|
+
readonly yaw: number;
|
|
647
|
+
readonly far: number;
|
|
648
|
+
};
|
|
649
|
+
type CrowdUpdateContext = {
|
|
650
|
+
readonly target?: CrowdTarget | null;
|
|
651
|
+
/** 0 day, 1 night: sight drops by 40% at night. */
|
|
652
|
+
readonly nightFactor?: number;
|
|
653
|
+
/** Where the flow field converges (the target by default; the foot of a ladder when the target is on a roof). */
|
|
654
|
+
readonly flowTarget?: readonly [number, number];
|
|
655
|
+
/** Where the viewer looks (yaw: forward is `(-sin, -cos)`); the stalker wakes when the target turns its back. Default: the target's view. */
|
|
656
|
+
readonly viewYaw?: number;
|
|
657
|
+
};
|
|
658
|
+
type Crowd = {
|
|
659
|
+
readonly store: CrowdStore;
|
|
660
|
+
readonly pack: CrowdPack;
|
|
661
|
+
readonly grid: NavGrid;
|
|
662
|
+
readonly doors: Doors;
|
|
663
|
+
readonly corpses: CorpseLedger<Corpse>;
|
|
664
|
+
readonly numbers: CrowdNumbers;
|
|
665
|
+
readonly stats: {
|
|
666
|
+
bands: [number, number, number, number];
|
|
667
|
+
slots: number;
|
|
668
|
+
kills: number;
|
|
669
|
+
heads: number;
|
|
670
|
+
};
|
|
671
|
+
/** Height of the bodies piled per grid cell. */
|
|
672
|
+
readonly pile: Float32Array;
|
|
673
|
+
/** How many agents are steps of a pile now. */
|
|
674
|
+
pileCount(): number;
|
|
675
|
+
readonly trail: {
|
|
676
|
+
x: number;
|
|
677
|
+
z: number;
|
|
678
|
+
t: number;
|
|
679
|
+
}[];
|
|
680
|
+
/** Global variant index of each type's variants (G 67079 `ZVAR_OF`). */
|
|
681
|
+
readonly variantsOf: readonly (readonly number[])[];
|
|
682
|
+
target: CrowdTarget | null;
|
|
683
|
+
/** The stream every draw takes (the behaviours share it, in the game's order). */
|
|
684
|
+
readonly random: () => number;
|
|
685
|
+
/** Emits a `sound` event, as the crowd's own (for the behaviours). */
|
|
686
|
+
sound(id: string, volume: number, x: number, y: number, z: number, distance: number): void;
|
|
687
|
+
/** Emits an `effect` event, as the crowd's own (for the behaviours). */
|
|
688
|
+
effect(payload: CrowdEventMap['effect']): void;
|
|
689
|
+
typeIndex(id: string): number;
|
|
690
|
+
spawn(x: number, z: number, type?: number): number;
|
|
691
|
+
remove(i: number): void;
|
|
692
|
+
update(dt: number, context?: CrowdUpdateContext): void;
|
|
693
|
+
emitNoise(x: number, z: number, radius: number): void;
|
|
694
|
+
damage(i: number, hit: CrowdHit): CrowdDamageResult;
|
|
695
|
+
kill(i: number, headshot?: boolean): void;
|
|
696
|
+
/** The blood trail of the target, for the trackers (G 67238 `trailUpdate`). */
|
|
697
|
+
updateTrail(dt: number, target?: CrowdTarget | null): void;
|
|
698
|
+
updateCorpses(dt: number): void;
|
|
699
|
+
/** Keeps the count near `target` from the edge, removes the excess out of sight and sends a migration now and then (G 67158). */
|
|
700
|
+
updatePopulation(dt: number, view: CrowdView, options?: {
|
|
701
|
+
readonly target?: number;
|
|
702
|
+
readonly migration?: MigrationOptions | null;
|
|
703
|
+
}): void;
|
|
704
|
+
/** Spawns one agent `minD` to `maxD` m from the target, out of the view (G 67141 `spawnAway`). */
|
|
705
|
+
spawnAway(minD: number, maxD: number, view: CrowdView): number;
|
|
706
|
+
/** A blast at the base of a pile undoes it (G 67227 `pileBlast`). */
|
|
707
|
+
pileBlast(x: number, z: number, radius: number): void;
|
|
708
|
+
/** The agent hunts something else than the target (a civilian): `game-crowd` civilians set it. */
|
|
709
|
+
setHunt(hunt: ((i: number, tdt: number) => boolean) | null): void;
|
|
710
|
+
/** The chase speed of agent `i` now (the stalker's sprint, the drowned in water; G 67343 `zChaseSpeed`). */
|
|
711
|
+
chaseSpeed(i: number): number;
|
|
712
|
+
/** The interface `game-player` uses to push, cut and be held by the agents. */
|
|
713
|
+
asPlayerCrowd(): PlayerCrowdLike;
|
|
714
|
+
on<K extends CrowdEventName>(event: K, listener: (event: CrowdEventMap[K]) => void): () => void;
|
|
715
|
+
};
|
|
716
|
+
/** The same shape as `game-player`'s `PlayerCrowd` (structural, no dependency). */
|
|
717
|
+
type PlayerCrowdLike = {
|
|
718
|
+
count(): number;
|
|
719
|
+
active(i: number): boolean;
|
|
720
|
+
x(i: number): number;
|
|
721
|
+
z(i: number): number;
|
|
722
|
+
y(i: number): number;
|
|
723
|
+
floor(i: number): number;
|
|
724
|
+
chasing(i: number): boolean;
|
|
725
|
+
down(i: number): boolean;
|
|
726
|
+
panicWeight(i: number): number;
|
|
727
|
+
hold(i: number, x: number, z: number, k: number, lookX: number, lookZ: number): void;
|
|
728
|
+
stun(i: number, seconds: number, vx: number, vz: number): void;
|
|
729
|
+
chase(i: number, cooldown: number): void;
|
|
730
|
+
damage(i: number, hit: {
|
|
731
|
+
region: number;
|
|
732
|
+
amount: number;
|
|
733
|
+
distance: number;
|
|
734
|
+
cut: number;
|
|
735
|
+
}): void;
|
|
736
|
+
};
|
|
737
|
+
/**
|
|
738
|
+
* The crowd: a literal port of the team game's horde (`jogo.js` G 66714-67430). One struct of arrays, relevance bands R0-R3 with hysteresis, perception
|
|
739
|
+
* by sight, hearing and smell, the sliced flow field, the spatial hash, separation, six attack slots, chain alerts, doors, piles against walls, the
|
|
740
|
+
* abilities as type traits, corpses, the blood trail and the population. Every draw on `random` is in the game's order.
|
|
741
|
+
*/
|
|
742
|
+
declare function createCrowd(options: CrowdOptions): Crowd;
|
|
743
|
+
|
|
744
|
+
/** Deterministic mulberry32 generator; returns floats in [0, 1). */
|
|
745
|
+
declare function createRng(seed: number): () => number;
|
|
746
|
+
|
|
747
|
+
/** A building the civilians walk between: its rectangle, whether it is a house (it has a gate), and the side its front faces (-1: toward -z). */
|
|
748
|
+
type CivilianBuilding = {
|
|
749
|
+
readonly x: number;
|
|
750
|
+
readonly z: number;
|
|
751
|
+
readonly w: number;
|
|
752
|
+
readonly d: number;
|
|
753
|
+
readonly house?: boolean;
|
|
754
|
+
readonly front: -1 | 1;
|
|
755
|
+
};
|
|
756
|
+
type CivilianSpec = {
|
|
757
|
+
readonly id: string;
|
|
758
|
+
/** The building name it lives in. */
|
|
759
|
+
readonly home: string;
|
|
760
|
+
readonly child?: boolean;
|
|
761
|
+
readonly color?: number;
|
|
762
|
+
/** `[hour, building]`: from that hour, for one hour, it walks to that building. */
|
|
763
|
+
readonly routine?: readonly (readonly [number, string])[];
|
|
764
|
+
/** In a group it follows this civilian when that one is in the group too, else the target. */
|
|
765
|
+
readonly leader?: string;
|
|
766
|
+
/** How close it keeps to whom it follows (2.2 m; the game's child keeps 1.2). */
|
|
767
|
+
readonly followDistance?: number;
|
|
768
|
+
};
|
|
769
|
+
type CivilianState = 'home' | 'walking' | 'group' | 'fleeing' | 'gone' | 'dead' | 'undead';
|
|
770
|
+
type Civilian = {
|
|
771
|
+
readonly id: string;
|
|
772
|
+
readonly spec: CivilianSpec;
|
|
773
|
+
readonly k: number;
|
|
774
|
+
x: number;
|
|
775
|
+
z: number;
|
|
776
|
+
yaw: number;
|
|
777
|
+
phase: number;
|
|
778
|
+
vx: number;
|
|
779
|
+
vz: number;
|
|
780
|
+
hp: number;
|
|
781
|
+
state: CivilianState;
|
|
782
|
+
path: [number, number][];
|
|
783
|
+
pathIndex: number;
|
|
784
|
+
/** Seconds left to turn after a bite (0: not bitten). */
|
|
785
|
+
biteTimer: number;
|
|
786
|
+
attackTimer: number;
|
|
787
|
+
fear: number;
|
|
788
|
+
/** The building it is going to (or is at). */
|
|
789
|
+
goal: string;
|
|
790
|
+
stuckTimer: number;
|
|
791
|
+
/** The agent it turned into. */
|
|
792
|
+
agent: number;
|
|
793
|
+
};
|
|
794
|
+
type CivilianNumbers = {
|
|
795
|
+
readonly hpAdult: number;
|
|
796
|
+
readonly hpChild: number;
|
|
797
|
+
readonly childOffset: number;
|
|
798
|
+
readonly sightSquared: number;
|
|
799
|
+
readonly leaveDistance: number;
|
|
800
|
+
readonly attackRange: number;
|
|
801
|
+
readonly attackEvery: number;
|
|
802
|
+
readonly biteFactor: number;
|
|
803
|
+
readonly biteSeconds: number;
|
|
804
|
+
readonly fearAfterHit: number;
|
|
805
|
+
readonly nearMessage: number;
|
|
806
|
+
readonly fearRange: number;
|
|
807
|
+
readonly fearSpeed: number;
|
|
808
|
+
readonly walkSpeed: number;
|
|
809
|
+
readonly childSpeed: number;
|
|
810
|
+
readonly bittenSpeed: number;
|
|
811
|
+
readonly groupRunBeyond: number;
|
|
812
|
+
readonly groupRunSpeed: number;
|
|
813
|
+
readonly fleeSpeed: number;
|
|
814
|
+
readonly childFleeFactor: number;
|
|
815
|
+
readonly stuckSeconds: number;
|
|
816
|
+
readonly arrive: number;
|
|
817
|
+
readonly probe: number;
|
|
818
|
+
readonly whiskers: readonly number[];
|
|
819
|
+
readonly doorProbe: number;
|
|
820
|
+
readonly steer: number;
|
|
821
|
+
readonly bodyHeight: number;
|
|
822
|
+
readonly patrolChance: number;
|
|
823
|
+
readonly childHeight: number;
|
|
824
|
+
readonly childBuild: number;
|
|
825
|
+
readonly cadenceBase: number;
|
|
826
|
+
readonly cadencePerSpeed: number;
|
|
827
|
+
readonly inside: number;
|
|
828
|
+
readonly doorInside: number;
|
|
829
|
+
readonly doorOutside: number;
|
|
830
|
+
readonly gate: number;
|
|
831
|
+
readonly sidewalk: number;
|
|
832
|
+
readonly houseOffset: number;
|
|
833
|
+
};
|
|
834
|
+
/** The game's numbers (`jogo.js` G 69960-70175). */
|
|
835
|
+
declare const CIVILIAN_DEFAULTS: CivilianNumbers;
|
|
836
|
+
type CivilianEventMap = {
|
|
837
|
+
bitten: {
|
|
838
|
+
id: string;
|
|
839
|
+
near: boolean;
|
|
840
|
+
};
|
|
841
|
+
died: {
|
|
842
|
+
id: string;
|
|
843
|
+
cause: 'attacked';
|
|
844
|
+
};
|
|
845
|
+
turned: {
|
|
846
|
+
id: string;
|
|
847
|
+
agent: number;
|
|
848
|
+
};
|
|
849
|
+
gone: {
|
|
850
|
+
id: string;
|
|
851
|
+
};
|
|
852
|
+
};
|
|
853
|
+
type CivilianEventName = keyof CivilianEventMap;
|
|
854
|
+
type CivilianOptions = {
|
|
855
|
+
readonly people: readonly CivilianSpec[];
|
|
856
|
+
readonly buildings: Readonly<Record<string, CivilianBuilding>>;
|
|
857
|
+
/** The hour of the day now (0-24), for the routines. */
|
|
858
|
+
readonly hour?: () => number;
|
|
859
|
+
/** The crowd type a bitten civilian turns into (default the first type). */
|
|
860
|
+
readonly turnInto?: number;
|
|
861
|
+
/** The waypoints of a building (G 69967 `pontos`): inside, the door from inside and outside, the gate of a house, the sidewalk. */
|
|
862
|
+
readonly waypoints?: (building: CivilianBuilding) => [number, number][];
|
|
863
|
+
readonly numbers?: Partial<CivilianNumbers>;
|
|
864
|
+
};
|
|
865
|
+
type Civilians = {
|
|
866
|
+
readonly list: readonly Civilian[];
|
|
867
|
+
get(id: string): Civilian | undefined;
|
|
868
|
+
/** Moves the civilians, lets the agents hunt them, bites, deaths and turning (G 70144 `npcUpdate`, G 70042 `npcZombies`). */
|
|
869
|
+
update(dt: number): void;
|
|
870
|
+
/** Joins the target's group: follows its leader or the target. */
|
|
871
|
+
join(id: string): void;
|
|
872
|
+
/** Leaves along a path of points; at the end it is `gone`. */
|
|
873
|
+
flee(id: string, path: readonly (readonly [number, number])[]): void;
|
|
874
|
+
/** The route between two buildings (G 69974 `rota`): the points of one, the street crossing, the points of the other reversed. */
|
|
875
|
+
route(from: string, to: string): [number, number][];
|
|
876
|
+
on<K extends CivilianEventName>(event: K, listener: (event: CivilianEventMap[K]) => void): () => void;
|
|
877
|
+
};
|
|
878
|
+
/**
|
|
879
|
+
* Civilians on a crowd: a literal port of the team game's survivors on the block (`jogo.js` G 69960-70175: `pontos`, `rota`, `npcZombies`,
|
|
880
|
+
* `zChaseNpc`, `npcMorre`, `npcVira`, `npcMove`, `npcUpdate`). They keep a routine by the hour, run home when an agent is near, follow a leader in a
|
|
881
|
+
* group, leave along a path, open doors on the way; agents within 10 m that are closer to them than to the target hunt them, bite, and a bitten one
|
|
882
|
+
* turns after `biteSeconds`. No names, lines, radio or diary: those are the game's, through the events.
|
|
883
|
+
*/
|
|
884
|
+
declare function createCivilians(crowd: Crowd, options: CivilianOptions): Civilians;
|
|
885
|
+
|
|
886
|
+
/** What an animal does besides wandering and fleeing; each is optional, an animal without one only wanders and flees. */
|
|
887
|
+
type HerdRole = {
|
|
888
|
+
/** Wanders within this many metres of home (8). */
|
|
889
|
+
readonly range?: number;
|
|
890
|
+
/** Flees from the target closer than this and from agents closer than `fear·1.5 + 2` (5; 0 never flees). */
|
|
891
|
+
readonly fear?: number;
|
|
892
|
+
/** Calls when it flees (the hen): sound, noise radius, cooldown. */
|
|
893
|
+
readonly fleeCall?: {
|
|
894
|
+
readonly sound: string;
|
|
895
|
+
readonly noise: number;
|
|
896
|
+
readonly cooldown: number;
|
|
897
|
+
};
|
|
898
|
+
/** Alarm when the target comes within `range` (the lapwing): flies for `fly` s. */
|
|
899
|
+
readonly alarm?: {
|
|
900
|
+
readonly range: number;
|
|
901
|
+
readonly sound: string;
|
|
902
|
+
readonly noise: number;
|
|
903
|
+
readonly cooldown: number;
|
|
904
|
+
readonly fly: number;
|
|
905
|
+
};
|
|
906
|
+
/** Now and then calls loud (the cow): chance per second, sound, noise, cooldown. */
|
|
907
|
+
readonly call?: {
|
|
908
|
+
readonly chance: number;
|
|
909
|
+
readonly sound: string;
|
|
910
|
+
readonly noise: number;
|
|
911
|
+
readonly cooldown: number;
|
|
912
|
+
};
|
|
913
|
+
/** Barks at agents within `bark` m and growls at agents within `growl` m when it is the target's companion (the dog). */
|
|
914
|
+
readonly guard?: {
|
|
915
|
+
readonly bark: number;
|
|
916
|
+
readonly barkNoise: number;
|
|
917
|
+
readonly barkCooldown: number;
|
|
918
|
+
readonly growl: number;
|
|
919
|
+
readonly growlCooldown: number;
|
|
920
|
+
readonly sound: string;
|
|
921
|
+
};
|
|
922
|
+
};
|
|
923
|
+
type HerdAnimalSpec = HerdRole & {
|
|
924
|
+
/** The species id (any registry: `game-animals-species` has the 13 of the deliveries). */
|
|
925
|
+
readonly species: string;
|
|
926
|
+
readonly x: number;
|
|
927
|
+
readonly z: number;
|
|
928
|
+
/** The species' gait rates and its size (`game-animals` `quadrupedLayout(body).size`, `birdSize(body)`). */
|
|
929
|
+
readonly walkHz: number;
|
|
930
|
+
readonly runHz: number;
|
|
931
|
+
readonly size: number;
|
|
932
|
+
/** Follows 2.2 m behind the target (the companion dog). */
|
|
933
|
+
readonly companion?: boolean;
|
|
934
|
+
/** A carcass: it does not move (the vultures circle it). */
|
|
935
|
+
readonly dead?: boolean;
|
|
936
|
+
/** A bird of the sky (the vulture): only the flock moves it. */
|
|
937
|
+
readonly sky?: boolean;
|
|
938
|
+
};
|
|
939
|
+
type HerdAnimal = {
|
|
940
|
+
readonly index: number;
|
|
941
|
+
readonly spec: HerdAnimalSpec;
|
|
942
|
+
x: number;
|
|
943
|
+
z: number;
|
|
944
|
+
yaw: number;
|
|
945
|
+
homeX: number;
|
|
946
|
+
homeZ: number;
|
|
947
|
+
range: number;
|
|
948
|
+
fear: number;
|
|
949
|
+
clip: 'idle' | 'walk' | 'run';
|
|
950
|
+
timer: number;
|
|
951
|
+
targetX: number;
|
|
952
|
+
targetZ: number;
|
|
953
|
+
fly: number;
|
|
954
|
+
cooldown: number;
|
|
955
|
+
walkSpeed: number;
|
|
956
|
+
runSpeed: number;
|
|
957
|
+
companion: boolean;
|
|
958
|
+
dead: boolean;
|
|
959
|
+
/** The nearest agent seen in the last look (index and distance), refreshed about a quarter of the time. */
|
|
960
|
+
near: readonly [number, number] | null | undefined;
|
|
961
|
+
};
|
|
962
|
+
type HerdEventMap = {
|
|
963
|
+
sound: {
|
|
964
|
+
sound: string;
|
|
965
|
+
volume: number;
|
|
966
|
+
position: [number, number, number];
|
|
967
|
+
distance: number;
|
|
968
|
+
animal: number;
|
|
969
|
+
};
|
|
970
|
+
noise: {
|
|
971
|
+
x: number;
|
|
972
|
+
z: number;
|
|
973
|
+
radius: number;
|
|
974
|
+
animal: number;
|
|
975
|
+
};
|
|
976
|
+
message: {
|
|
977
|
+
id: 'alarm' | 'bark' | 'growl';
|
|
978
|
+
seconds: number;
|
|
979
|
+
animal: number;
|
|
980
|
+
distance?: number;
|
|
981
|
+
};
|
|
982
|
+
};
|
|
983
|
+
type HerdEventName = keyof HerdEventMap;
|
|
984
|
+
type HerdNumbers = {
|
|
985
|
+
readonly range: number;
|
|
986
|
+
readonly fear: number;
|
|
987
|
+
readonly walkFactor: number;
|
|
988
|
+
readonly walkBase: number;
|
|
989
|
+
readonly runFactor: number;
|
|
990
|
+
readonly runBase: number;
|
|
991
|
+
readonly activeDistance: number;
|
|
992
|
+
readonly companionBehind: number;
|
|
993
|
+
readonly companionRun: number;
|
|
994
|
+
readonly companionStop: number;
|
|
995
|
+
readonly retargetTries: number;
|
|
996
|
+
readonly restBase: number;
|
|
997
|
+
readonly restRandom: number;
|
|
998
|
+
readonly lookEvery: number;
|
|
999
|
+
readonly lookShare: number;
|
|
1000
|
+
readonly lookRadius: number;
|
|
1001
|
+
readonly fearAgentFactor: number;
|
|
1002
|
+
readonly fearAgentBase: number;
|
|
1003
|
+
readonly fleeStep: number;
|
|
1004
|
+
readonly arrive: number;
|
|
1005
|
+
readonly bodyHeight: number;
|
|
1006
|
+
readonly turn: number;
|
|
1007
|
+
readonly freeHeight: number;
|
|
1008
|
+
readonly worldMargin: number;
|
|
1009
|
+
};
|
|
1010
|
+
/** The game's numbers (`jogo.js` G 66592-66700 `bichoNovo`, `bichoLivre`, `bichosUpdate`). */
|
|
1011
|
+
declare const HERD_DEFAULTS: HerdNumbers;
|
|
1012
|
+
/**
|
|
1013
|
+
* The roles of the animals of the deliveries, by `game-animals-species` id: what `bichosPovoar` gives each one (`jogo.js` G 66607-66623) and the
|
|
1014
|
+
* calls of `bichosUpdate` (hen 30 m every 6 s; lapwing 12 m, 40 m, flies 4 s; cow 80 m, 2% a second, every 30 s; dog barks under 12 m, 60 m, every
|
|
1015
|
+
* 3 s, growls under 40 m every 10 s). A game passes its own or changes one.
|
|
1016
|
+
*/
|
|
1017
|
+
declare const HERD_ROLES: Readonly<Record<string, HerdRole & {
|
|
1018
|
+
readonly sky?: boolean;
|
|
1019
|
+
}>>;
|
|
1020
|
+
type HerdOptions = {
|
|
1021
|
+
/** Where the camera is: animals farther than 70 m rest, and sounds carry their distance from here. Default: the target. */
|
|
1022
|
+
readonly view?: () => {
|
|
1023
|
+
readonly x: number;
|
|
1024
|
+
readonly z: number;
|
|
1025
|
+
};
|
|
1026
|
+
/** A spot an animal must not wander into (inside a building). */
|
|
1027
|
+
readonly blocked?: (x: number, z: number) => boolean;
|
|
1028
|
+
readonly numbers?: Partial<HerdNumbers>;
|
|
1029
|
+
};
|
|
1030
|
+
type Herd = {
|
|
1031
|
+
readonly list: readonly HerdAnimal[];
|
|
1032
|
+
/** Adds an animal (draws its heading and its first rest, as the game does). */
|
|
1033
|
+
add(spec: HerdAnimalSpec): HerdAnimal;
|
|
1034
|
+
/** A free spot `r0` to `r1` m from (x, z), or null (G 66601 `bichoLivre`). */
|
|
1035
|
+
free(x: number, z: number, r0: number, r1: number, tries?: number): [number, number] | null;
|
|
1036
|
+
/** Wander, flee, follow, call (G 66648 `bichosUpdate`, without the drawing). */
|
|
1037
|
+
update(dt: number): void;
|
|
1038
|
+
/** The time the herd has run (the flock reads it). */
|
|
1039
|
+
readonly time: number;
|
|
1040
|
+
setCompanion(index: number, on: boolean): void;
|
|
1041
|
+
on<K extends HerdEventName>(event: K, listener: (event: HerdEventMap[K]) => void): () => void;
|
|
1042
|
+
};
|
|
1043
|
+
/**
|
|
1044
|
+
* Animals on a crowd: a literal port of the team game's animals (`jogo.js` G 66592-66700). Each wanders around home and rests 4 to 11 s, flees
|
|
1045
|
+
* from the target and from the crowd's agents, and may call, raise an alarm or guard the target as its companion. The calls are noises the crowd
|
|
1046
|
+
* hears. The drawing and the bones are the game's (`game-animals-three`).
|
|
1047
|
+
*/
|
|
1048
|
+
declare function createHerd(crowd: Crowd, options?: HerdOptions): Herd;
|
|
1049
|
+
|
|
1050
|
+
/** One bird of a flock this frame: where it is, its heading and its roll, its wing phase, and whether it is close enough to draw. */
|
|
1051
|
+
type FlockBird = {
|
|
1052
|
+
x: number;
|
|
1053
|
+
y: number;
|
|
1054
|
+
z: number;
|
|
1055
|
+
yaw: number;
|
|
1056
|
+
roll: number;
|
|
1057
|
+
wing: number;
|
|
1058
|
+
visible: boolean;
|
|
1059
|
+
};
|
|
1060
|
+
type FlockMode =
|
|
1061
|
+
/** The vultures (G 66700-66708): circle the centre of the bodies on the ground, each at its own speed, radius and height. */
|
|
1062
|
+
'carrion'
|
|
1063
|
+
/** The birds of the live map (Bancada de Hordas G 53609-53615): a loose ring that rises and falls. */
|
|
1064
|
+
| 'orbit';
|
|
1065
|
+
type FlockOptions = {
|
|
1066
|
+
readonly count: number;
|
|
1067
|
+
readonly mode: FlockMode;
|
|
1068
|
+
/** Visible within this distance of the view (carrion 260 m; orbit always). */
|
|
1069
|
+
readonly visibleWithin?: number;
|
|
1070
|
+
};
|
|
1071
|
+
type Flock = {
|
|
1072
|
+
readonly birds: readonly FlockBird[];
|
|
1073
|
+
/** Moves the flock to time `t` (seconds) around `center`; `view` decides what is visible. */
|
|
1074
|
+
update(t: number, dt: number, center: readonly [number, number], view?: readonly [number, number]): void;
|
|
1075
|
+
};
|
|
1076
|
+
/** The centre the vultures circle: the mean of the bodies on the ground when there are three or more, else `fallback` (a carcass). */
|
|
1077
|
+
declare const carrionCenter: (corpses: readonly {
|
|
1078
|
+
readonly x: number;
|
|
1079
|
+
readonly z: number;
|
|
1080
|
+
}[], fallback: readonly [number, number] | null) => [number, number];
|
|
1081
|
+
/** A flock of birds by formula: the game's vultures or the live map's ring (literal formulas from the deliveries). */
|
|
1082
|
+
declare function createFlock(options: FlockOptions): Flock;
|
|
1083
|
+
|
|
1084
|
+
/** What the crowd needs of a region model: `game-infection`'s `Infection` is one as it is. */
|
|
1085
|
+
type InfectionModelLike = {
|
|
1086
|
+
materialize(region: string, n: number): {
|
|
1087
|
+
state: 'active' | 'contained' | 'removed';
|
|
1088
|
+
seed: number;
|
|
1089
|
+
}[];
|
|
1090
|
+
giveBack(region: string, batch: {
|
|
1091
|
+
state: 'active' | 'contained' | 'removed';
|
|
1092
|
+
seed: number;
|
|
1093
|
+
}[]): void;
|
|
1094
|
+
infect(region: string, n?: number, hoursElapsed?: number): void;
|
|
1095
|
+
};
|
|
1096
|
+
type InfectionBindingOptions = {
|
|
1097
|
+
/** Where the k-th agent of a batch is born in the region, from its seed; null skips it (it goes straight back). */
|
|
1098
|
+
readonly place: (region: string, seed: number, k: number) => readonly [number, number] | null;
|
|
1099
|
+
/** The crowd type of an agent (default: drawn by the pack's weights). */
|
|
1100
|
+
readonly typeFor?: (agent: {
|
|
1101
|
+
readonly state: 'active' | 'contained' | 'removed';
|
|
1102
|
+
readonly seed: number;
|
|
1103
|
+
}, region: string) => number;
|
|
1104
|
+
/** The relevance band from which an agent goes back to the model (default 3: farther than 400 m). */
|
|
1105
|
+
readonly giveBackBand?: number;
|
|
1106
|
+
/** Civilians whose bites the model hears about (`infect`), in the region `regionOf` gives. */
|
|
1107
|
+
readonly civilians?: Civilians;
|
|
1108
|
+
readonly regionOf?: (x: number, z: number) => string | null;
|
|
1109
|
+
};
|
|
1110
|
+
type InfectionBinding = {
|
|
1111
|
+
/** Brings up to `n` infected of `region` out of the model into the crowd. Returns the agents born. */
|
|
1112
|
+
materialize(region: string, n: number): number[];
|
|
1113
|
+
/** Gives back to the model the agents of `region` (all regions when left out) that are in the far band, or all of them with `all`. */
|
|
1114
|
+
giveBack(region?: string, options?: {
|
|
1115
|
+
readonly all?: boolean;
|
|
1116
|
+
}): number;
|
|
1117
|
+
/** The region of a materialised agent, or null. */
|
|
1118
|
+
regionOf(agent: number): string | null;
|
|
1119
|
+
unbind(): void;
|
|
1120
|
+
};
|
|
1121
|
+
/**
|
|
1122
|
+
* Ties a crowd to a region model (`game-infection`): `materialize` turns the model's numbers into agents near the player, a kill of one of them
|
|
1123
|
+
* goes back to its region as removed, the far ones go back with `giveBack`, and a civilian's bite is an `infect`. No team code exists for this bridge
|
|
1124
|
+
* (decision P12 of the spec); the model's own API is used as it is.
|
|
1125
|
+
*/
|
|
1126
|
+
declare function bindInfection(crowd: Crowd, model: InfectionModelLike, options: InfectionBindingOptions): InfectionBinding;
|
|
1127
|
+
|
|
1128
|
+
export { AGENT_FIELDS, CELL, CIVILIAN_DEFAULTS, CROWD_DEFAULTS, type Civilian, type CivilianBuilding, type CivilianEventMap, type CivilianEventName, type CivilianNumbers, type CivilianOptions, type CivilianSpec, type CivilianState, type Civilians, type Corpse, type Crowd, type CrowdAge, type CrowdBand, type CrowdCaliber, type CrowdDamageResult, type CrowdEffectId, type CrowdEventMap, type CrowdEventName, type CrowdHit, type CrowdMessageId, type CrowdNumbers, type CrowdOptions, type CrowdOutfit, type CrowdPack, type CrowdPlugin, type CrowdSoundId, type CrowdStore, type CrowdTarget, type CrowdTraits, type CrowdType, type CrowdUpdateContext, type CrowdView, DOOR_DEFAULTS, type Door, type DoorEventMap, type DoorEventName, type DoorNumbers, type Doors, type Flock, type FlockBird, type FlockMode, type FlockOptions, HERD_DEFAULTS, HERD_ROLES, type Herd, type HerdAnimal, type HerdAnimalSpec, type HerdEventMap, type HerdEventName, type HerdNumbers, type HerdOptions, type HerdRole, type InfectionBinding, type InfectionBindingOptions, type InfectionModelLike, MISSING, type MigrationOptions, type NavGrid, type NavGridOptions, type PlayerCrowdLike, type Region, STATE, bindInfection, carrionCenter, createCivilians, createCrowd, createDoors, createFlock, createHerd, createNavGrid, createRng, createStore };
|