@wildware/smart-fellas 0.0.0-stage → 1.8.0
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/CHANGELOG.md +107 -0
- package/LICENSE +21 -0
- package/README.md +142 -2
- package/package.json +35 -4
- package/smart-fellas.d.ts +1057 -0
|
@@ -0,0 +1,1057 @@
|
|
|
1
|
+
// Smart Fellas map scripts: the types and docs for everything a map's script can reach.
|
|
2
|
+
//
|
|
3
|
+
// Keep this file in your map's scripts folder (Export puts a fresh copy there each time), and any
|
|
4
|
+
// editor that knows TypeScript completes and checks your scripts as you type. Write each script as a
|
|
5
|
+
// .ts file (or plain .js). Export and Test Map turn them into JavaScript for the game.
|
|
6
|
+
//
|
|
7
|
+
// The modding wiki has a guide to every part, with examples to copy:
|
|
8
|
+
// https://github.com/wildware-uk/smart-fellas-modding/wiki
|
|
9
|
+
//
|
|
10
|
+
// Where a script runs is the folder it is in:
|
|
11
|
+
// - Directly in the scripts folder: in the host's game only, which decides the match. What it
|
|
12
|
+
// changes reaches every player the way everything else does.
|
|
13
|
+
// - In client/: on each player's own PC, for that player alone. Its messages and sounds are for
|
|
14
|
+
// that one screen. It can't change the match: anything else it asks for is ignored.
|
|
15
|
+
// - In shared/: in the host's game for real, and on each player's own PC to guess ahead, so a door
|
|
16
|
+
// a player pulls starts moving at once on their screen. On a player's PC only its piece moves,
|
|
17
|
+
// turns, shows and hides happen, as a guess the host's game then confirms or puts right. Its
|
|
18
|
+
// messages and sounds come from the host's game. The copy on a player's PC hears only that
|
|
19
|
+
// player using a switch, and game.random() gives it different numbers, so let it guess from
|
|
20
|
+
// what it reads at the moment (where the door is now), not from counts it keeps.
|
|
21
|
+
// - On a player's PC a script reads only what that player's game was sent: a player it wasn't sent
|
|
22
|
+
// has no position.
|
|
23
|
+
//
|
|
24
|
+
// How a script runs:
|
|
25
|
+
// - The scripts in one place are loaded at the start of the match, in name order, and share their
|
|
26
|
+
// globals. The host's game loads shared/ first, then its own. There is no import: the game loads
|
|
27
|
+
// them all itself.
|
|
28
|
+
// - Register handlers once, at the top of a file. The game calls them each tick (64 a second).
|
|
29
|
+
// - Actions such as door.moveTo() are queued and applied after your handlers finish, so what you
|
|
30
|
+
// read stays as the tick began.
|
|
31
|
+
// - There is no clock (no Date) and no Math.random: use game.seconds and game.random(), or a
|
|
32
|
+
// Random of your own.
|
|
33
|
+
// - Every script also has the helpers at the end of this file: Vec, Maths, Random, Ease, tween,
|
|
34
|
+
// StateMachine, store and log.
|
|
35
|
+
// - A script that runs too long, uses too much memory, or throws and doesn't catch it is switched
|
|
36
|
+
// off for the rest of the match, and the host sees one line saying why.
|
|
37
|
+
// - A bad argument (a name that doesn't exist, a point far outside the map) throws an Error you can
|
|
38
|
+
// catch. A handle to something that has gone does nothing and reads as gone.
|
|
39
|
+
//
|
|
40
|
+
// Game modes use the same calls. A mode is a folder with a mode.json (its name, description, player
|
|
41
|
+
// counts and the lobby settings it offers) and a scripts/ folder laid out as a map's. The host picks
|
|
42
|
+
// the mode in the lobby, apart from the map, and the mode's scripts run beside the map's in a world
|
|
43
|
+
// of their own: each numbers the players for itself. The mode's run first each tick.
|
|
44
|
+
// Every round is played by a mode, Classic and Infected included: they ship as modes in the same
|
|
45
|
+
// shape. The game has no win checks of its own: the mode ends the round with game.endRound(). A
|
|
46
|
+
// round can't start until the mode's script is running. When the clock runs out (and isn't held),
|
|
47
|
+
// the mode hears onTimeUp; if it doesn't end the round on that tick, the round ends as a draw. A
|
|
48
|
+
// mode whose script stops ends a round being played as a draw, and the match goes back to Classic.
|
|
49
|
+
//
|
|
50
|
+
// mode.json may also say, each optional:
|
|
51
|
+
// - "minDivers", "minOctopuses": the fewest players on each team a round may start with (0);
|
|
52
|
+
// - "teamLines": { "octopus": "...", "diver": "..." }, the lines under each team's name in the
|
|
53
|
+
// lobby (a team the mode adds says its own, in game.registerTeam), and "startLines" the same shape, the lines under the banner as the hunt starts (1 to 60
|
|
54
|
+
// characters each);
|
|
55
|
+
// - "look": "catches" or "turns" for the game's own octopuses-left count and results (Classic's,
|
|
56
|
+
// Infected's), or left out for the mode's own scoreboard and banner;
|
|
57
|
+
// - "revives": true if the lobby's Revives setting applies: a netted octopus may be freed.
|
|
58
|
+
// The calls marked "for game modes" change the round's rules. A map's script may use them too, and
|
|
59
|
+
// the mode then hears what happened through its own events (onTeamChange, onRoundEnd).
|
|
60
|
+
// The calls marked "on the host only" work only in the host's game: a client/ script's call does
|
|
61
|
+
// nothing. The host's game decides them and sends them to the players they are for.
|
|
62
|
+
// An object a call takes (a spec, a point) is read for the values it holds itself, as an object
|
|
63
|
+
// literal or a Vec point does: a value from a getter, from its prototype or through a Proxy reads as
|
|
64
|
+
// left out, so none of the script's own code runs inside a call.
|
|
65
|
+
|
|
66
|
+
/** A point in the map, in metres. y is up. */
|
|
67
|
+
interface Point {
|
|
68
|
+
readonly x: number;
|
|
69
|
+
readonly y: number;
|
|
70
|
+
readonly z: number;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/** Where a ray first met the map: from `game.raycast` and `game.groundBelow`. */
|
|
74
|
+
interface RayHit {
|
|
75
|
+
/** The point it met the map's rock, sand or pieces. */
|
|
76
|
+
readonly point: Point;
|
|
77
|
+
/** Which way that surface faces, one metre long: straight up on flat ground. */
|
|
78
|
+
readonly normal: Point;
|
|
79
|
+
/** How far from the ray's start, in metres. */
|
|
80
|
+
readonly distance: number;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/** The box players swim in, from its lowest corner to its highest. */
|
|
84
|
+
interface PlayArea {
|
|
85
|
+
readonly min: Point;
|
|
86
|
+
readonly max: Point;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* A side in a match: the octopuses (Smart Fellas), the divers (Fart Smellas), or a team the game
|
|
91
|
+
* mode added with game.registerTeam, by the id it gave it.
|
|
92
|
+
*/
|
|
93
|
+
type Team = "octopus" | "diver" | (string & {});
|
|
94
|
+
|
|
95
|
+
/** A team a game mode adds of its own (game.registerTeam). */
|
|
96
|
+
interface TeamSpec {
|
|
97
|
+
/** What players read, 1 to 24 characters. */
|
|
98
|
+
name: string;
|
|
99
|
+
/** Its colour, "#rrggbb". */
|
|
100
|
+
colour: string;
|
|
101
|
+
/** The creature its players drive, with their own keys and mouse; a bot's swims on its own. */
|
|
102
|
+
body: "shark";
|
|
103
|
+
/** The most players it may have, people and bots, 1 to 32. */
|
|
104
|
+
most: number;
|
|
105
|
+
/** Whose start points it comes in at: "octopus" (all over the map, the default) or "diver". */
|
|
106
|
+
spawns?: "octopus" | "diver";
|
|
107
|
+
/** The line under its name in the lobby, at most 60 characters. */
|
|
108
|
+
line?: string;
|
|
109
|
+
/** The line under the banner its players see as the hunt starts, at most 60 characters. */
|
|
110
|
+
startLine?: string;
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* An ability a game mode gives one of its own teams (game.registerAbility). The game shows it on
|
|
114
|
+
* the HUD of that team's players with its key, its name and its cooldown, and aims it for them: it
|
|
115
|
+
* goes off only when someone they can see (not hidden, behind rock or in ink) is near the middle
|
|
116
|
+
* of their screen and within `range`.
|
|
117
|
+
*/
|
|
118
|
+
interface AbilitySpec {
|
|
119
|
+
/** The team whose players have it: one the mode added with game.registerTeam. */
|
|
120
|
+
team: Team;
|
|
121
|
+
/** Which of the team's two ability keys it is on: 1 is the player's Dash key, 2 their Ink key. */
|
|
122
|
+
slot: 1 | 2;
|
|
123
|
+
/** What players read under its button, 1 to 16 characters. */
|
|
124
|
+
name: string;
|
|
125
|
+
/** Seconds from one use to the next, up to 600 (at least a quarter of a second). */
|
|
126
|
+
cooldown: number;
|
|
127
|
+
/** How far off whoever it is aimed at may be, 1 to 60 metres. */
|
|
128
|
+
range: number;
|
|
129
|
+
/**
|
|
130
|
+
* If given, the user's creature darts straight at whoever it was aimed at: at `speed` (1 to 40
|
|
131
|
+
* metres a second) for at most `metres` (1 to 60). Rock stops it. game.onAbilityLand hears it
|
|
132
|
+
* get there.
|
|
133
|
+
*/
|
|
134
|
+
lunge?: { speed: number; metres: number };
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/** A tool a diver may carry (game.loadout). */
|
|
138
|
+
type Tool = "spear" | "net" | "sensor" | "torch";
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* Something a player does that a script may switch off for them alone, with player.allow(): an
|
|
142
|
+
* octopus's dash, ink, grab and smell, and a diver's gun ("shoot", whichever gun they carry).
|
|
143
|
+
*/
|
|
144
|
+
type Skill = "dash" | "ink" | "grab" | "smell" | "shoot";
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* How well a bot plays, the same choices as the lobby's bot skill (player.setBotLevel). New in 1.7.0.
|
|
148
|
+
*/
|
|
149
|
+
type BotLevel = "easy" | "normal" | "hard";
|
|
150
|
+
|
|
151
|
+
/** Where a player is in the round. */
|
|
152
|
+
type Life = "alive" | "respawning" | "out" | "waiting";
|
|
153
|
+
|
|
154
|
+
/** Where the match is. */
|
|
155
|
+
type Phase = "lobby" | "play" | "results";
|
|
156
|
+
|
|
157
|
+
/** How a player was caught: in a creature's jaws, or in a diver's net. */
|
|
158
|
+
type Catch = "jaws" | "net";
|
|
159
|
+
|
|
160
|
+
/** Food a player can eat. */
|
|
161
|
+
type FoodKind = "crab" | "clam" | "shrimp" | "wrasse" | "lobster";
|
|
162
|
+
|
|
163
|
+
/** The creatures and food a script can find with game.creatures(), spawn and remove. */
|
|
164
|
+
type CreatureKind =
|
|
165
|
+
| "shark"
|
|
166
|
+
| "eel"
|
|
167
|
+
| "groper"
|
|
168
|
+
| "flounder"
|
|
169
|
+
| "lionfish"
|
|
170
|
+
| "crab"
|
|
171
|
+
| "clam"
|
|
172
|
+
| "shrimp";
|
|
173
|
+
|
|
174
|
+
/** The sounds a map can play. game.sounds() lists them too. */
|
|
175
|
+
type SoundName =
|
|
176
|
+
| "groan"
|
|
177
|
+
| "drip"
|
|
178
|
+
| "rockfall"
|
|
179
|
+
| "whale"
|
|
180
|
+
| "boom"
|
|
181
|
+
| "swell"
|
|
182
|
+
| "hiss"
|
|
183
|
+
| "chime"
|
|
184
|
+
| "roar"
|
|
185
|
+
| "thunk";
|
|
186
|
+
|
|
187
|
+
/** A number after() or every() gave back, for cancel(). */
|
|
188
|
+
type TimerId = number;
|
|
189
|
+
|
|
190
|
+
/**
|
|
191
|
+
* What being caught or killed does to a player of a team (for game modes):
|
|
192
|
+
* - "out": out for the rest of the round;
|
|
193
|
+
* - "held": out, and a netted octopus stays in its net where a teammate could free it;
|
|
194
|
+
* - "respawn": back after the wait, at the team's spawn;
|
|
195
|
+
* - "turn": back after the wait, on the other team.
|
|
196
|
+
*/
|
|
197
|
+
type Fate = "out" | "held" | "respawn" | "turn";
|
|
198
|
+
|
|
199
|
+
/**
|
|
200
|
+
* What a bot is after (for game modes). The bot's own brain still swims it there.
|
|
201
|
+
* - "own": its usual play: an octopus hides, a diver hunts;
|
|
202
|
+
* - "hide": an octopus hides as usual; a diver keeps still;
|
|
203
|
+
* - "flee": away from the nearest foe it can see;
|
|
204
|
+
* - "roam": wanders about;
|
|
205
|
+
* - "hunt": a diver hunts as usual; an octopus goes after the nearest diver it can see;
|
|
206
|
+
* - "goTo": swims to a point and stays there.
|
|
207
|
+
*
|
|
208
|
+
* A bot on a team the mode added (game.registerTeam) heeds "own" and "hunt" only. With "own" its
|
|
209
|
+
* creature swims on its own brain, as a wild one does. With "hunt" the bot plays it as a person
|
|
210
|
+
* would, through the same controls: it goes for the nearest player of another team it can see
|
|
211
|
+
* (nobody hidden, behind rock or in ink), bites when it is close, uses its team's abilities
|
|
212
|
+
* (game.registerAbility) when they are ready, and between chases looks round the food patches that
|
|
213
|
+
* have food on them.
|
|
214
|
+
*/
|
|
215
|
+
type Goal = "own" | "hide" | "flee" | "roam" | "hunt" | "goTo";
|
|
216
|
+
|
|
217
|
+
/**
|
|
218
|
+
* One of the game's own lines for why a round ended, for game.endRound():
|
|
219
|
+
* - "allCaught": every octopus was caught (speared, netted, starved or eaten);
|
|
220
|
+
* - "allTurned": every octopus was caught and turned into a diver;
|
|
221
|
+
* - "timeUp": time ran out and the octopuses survived;
|
|
222
|
+
* - "diversLeft": every diver left;
|
|
223
|
+
* - "octopusesLeft": every octopus left.
|
|
224
|
+
*/
|
|
225
|
+
type EndWhy = "allCaught" | "allTurned" | "timeUp" | "diversLeft" | "octopusesLeft";
|
|
226
|
+
|
|
227
|
+
/** The value of one of a game mode's lobby settings: a number, a choice's name, or a toggle. */
|
|
228
|
+
type SettingValue = number | string | boolean;
|
|
229
|
+
|
|
230
|
+
/**
|
|
231
|
+
* Who sees something on screen (game.announce, game.widget, game.marker): one team, or one player.
|
|
232
|
+
* Leave it out for everyone.
|
|
233
|
+
*/
|
|
234
|
+
type Viewers = Team | Player;
|
|
235
|
+
|
|
236
|
+
/** One HUD widget (game.widget), drawn in a column on the left of the screen, under the banner. */
|
|
237
|
+
interface WidgetSpec {
|
|
238
|
+
/** "text": a line of text; "bar": a filling bar; "counter": a number; "timer": a countdown. */
|
|
239
|
+
kind: "text" | "bar" | "counter" | "timer";
|
|
240
|
+
/** The small label above it, 0 to 24 characters. */
|
|
241
|
+
label?: string;
|
|
242
|
+
/** "text": what it says, 0 to 40 characters. */
|
|
243
|
+
text?: string;
|
|
244
|
+
/** "bar": how full, 0 to max; "counter": the number shown (whole numbers shown without decimals). */
|
|
245
|
+
value?: number;
|
|
246
|
+
/** "bar": the value that fills it (1 if left out). */
|
|
247
|
+
max?: number;
|
|
248
|
+
/** "timer": the seconds it counts down from, now (0 to 86400). Shown as m:ss, stops at 0:00. */
|
|
249
|
+
seconds?: number;
|
|
250
|
+
/** Its colour, "#rrggbb" (white if left out). */
|
|
251
|
+
colour?: string;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
/**
|
|
255
|
+
* A menu (game.menu): a card on the right of the screen with a title over 2 to 5 choices. Players
|
|
256
|
+
* pick one with the number keys 1 to 5 (on the top row or the number pad), or on a controller move
|
|
257
|
+
* along it with the D-pad's up and down and pick with right. Those keys and buttons do nothing else
|
|
258
|
+
* while it shows. Picking closes it for them.
|
|
259
|
+
*/
|
|
260
|
+
interface MenuSpec {
|
|
261
|
+
/** The question or heading, 1 to 60 characters. */
|
|
262
|
+
title: string;
|
|
263
|
+
/** 2 to 5 choices, each 1 to 30 characters, in the order of the keys that pick them. */
|
|
264
|
+
choices: string[];
|
|
265
|
+
/** How long it stays open by itself, in seconds (above 0, up to 600, counted down under it). Left out, it stays until picked from or closed. */
|
|
266
|
+
seconds?: number;
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
/** How a vote (game.vote) came out. */
|
|
270
|
+
interface VoteResult {
|
|
271
|
+
/** The choice with the most answers, or null when nobody answered or the most are tied. */
|
|
272
|
+
readonly winner: string | null;
|
|
273
|
+
/** Where the winner is in the vote's choices (0 for the first), or null as for `winner`. */
|
|
274
|
+
readonly index: number | null;
|
|
275
|
+
/** How many answered each choice, in the order of the choices. */
|
|
276
|
+
readonly counts: readonly number[];
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
/** What game.vote asks: like a menu, but `seconds` must be given, from 1 to 600. */
|
|
280
|
+
interface VoteSpec {
|
|
281
|
+
title: string;
|
|
282
|
+
choices: string[];
|
|
283
|
+
seconds: number;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
/** A marker (game.marker) at a point in the world, seen through rock, with its distance under it. */
|
|
287
|
+
interface MarkerSpec {
|
|
288
|
+
/** Where it is, within 1000 m of the map's middle. Give this or `on`, not both. */
|
|
289
|
+
at?: Point;
|
|
290
|
+
/**
|
|
291
|
+
* The player it rides over, moving with them, in place of `at`. A screen shows it only while that
|
|
292
|
+
* screen is sent the player's body, as when they are near enough to see, so it never shows anyone
|
|
293
|
+
* more than their own game knows. Not shown while the player has no body (waiting, respawning, out
|
|
294
|
+
* or gone). New in 1.6.0.
|
|
295
|
+
*/
|
|
296
|
+
on?: Player;
|
|
297
|
+
/** The text over it, 0 to 24 characters. */
|
|
298
|
+
label?: string;
|
|
299
|
+
/** Its colour, "#rrggbb" (white if left out). */
|
|
300
|
+
colour?: string;
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
/**
|
|
304
|
+
* The water as game.setWater changes it. Anything left out stays as the map has it.
|
|
305
|
+
*/
|
|
306
|
+
interface WaterSpec {
|
|
307
|
+
/** The colour far things fade into, "#rrggbb". */
|
|
308
|
+
colour?: string;
|
|
309
|
+
/** How far anyone sees through it, in metres, from 5 to 300. Bots see through it as far. */
|
|
310
|
+
visibility?: number;
|
|
311
|
+
/**
|
|
312
|
+
* How bright it is, as a share of the map's own light, from 0 to 2: 0.2 is dim, 1 is as the
|
|
313
|
+
* map has it, 2 twice as bright. Unless `colour` is given too, the haze dims or brightens with it.
|
|
314
|
+
*/
|
|
315
|
+
light?: number;
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
/** A light (game.light) at a point in the world, lighting what is near it. */
|
|
319
|
+
interface LightSpec {
|
|
320
|
+
/** Where it is, within 1000 m of the map's middle. */
|
|
321
|
+
at: Point;
|
|
322
|
+
/** Its colour, "#rrggbb" (white if left out). */
|
|
323
|
+
colour?: string;
|
|
324
|
+
/** How strong it is, from 0 to 10: 1, the default, is about as bright as a diver's torch. */
|
|
325
|
+
strength?: number;
|
|
326
|
+
/** How far it reaches, in metres, from 1 to 40 (10 if left out). */
|
|
327
|
+
range?: number;
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
/**
|
|
331
|
+
* A player in the match. The same player is always the same object, so === works. Once they have
|
|
332
|
+
* left, `gone` is true, what they were reads as null, and what you ask of them does nothing.
|
|
333
|
+
*/
|
|
334
|
+
interface Player {
|
|
335
|
+
/** Their number in this match. */
|
|
336
|
+
readonly id: number;
|
|
337
|
+
/** The name they play under. */
|
|
338
|
+
readonly name: string;
|
|
339
|
+
/** Whether they have left the match. */
|
|
340
|
+
readonly gone: boolean;
|
|
341
|
+
/** Their side, or null once gone. */
|
|
342
|
+
readonly team: Team | null;
|
|
343
|
+
/** Where they are in the round, or null once gone. */
|
|
344
|
+
readonly life: Life | null;
|
|
345
|
+
/** Whether they are alive and swimming. */
|
|
346
|
+
readonly alive: boolean;
|
|
347
|
+
/** Where they are, or null while they have no body (waiting, respawning, out or gone). */
|
|
348
|
+
readonly position: Point | null;
|
|
349
|
+
/** Their energy, or null while they have no body (and once gone). */
|
|
350
|
+
readonly energy: number | null;
|
|
351
|
+
|
|
352
|
+
/** Moves them to a point within 1000 m of the map's middle. */
|
|
353
|
+
moveTo(x: number, y: number, z: number): void;
|
|
354
|
+
/** Kills them, as the game's own kills do: the kill scene, the score and the respawn all happen. */
|
|
355
|
+
kill(): void;
|
|
356
|
+
/** Gives them energy, or takes it away with a negative number: -1000 to 1000. */
|
|
357
|
+
addEnergy(points: number): void;
|
|
358
|
+
/** Shows them alone a message from the map: 1 to 120 characters, a few a second at most. */
|
|
359
|
+
say(text: string): void;
|
|
360
|
+
|
|
361
|
+
/** Whether the player is one of the game's bots. */
|
|
362
|
+
readonly isBot: boolean;
|
|
363
|
+
/** Their score this round, as the match's scripts set it (0 at the start of each round). */
|
|
364
|
+
readonly score: number;
|
|
365
|
+
/**
|
|
366
|
+
* Their role this round, as the match's scripts set it ("" for none). Only the host's scripts know
|
|
367
|
+
* it: it is never sent to players, so a mode can keep roles secret.
|
|
368
|
+
*/
|
|
369
|
+
readonly role: string;
|
|
370
|
+
|
|
371
|
+
/**
|
|
372
|
+
* Moves them to the other team, at any time (for game modes). One alive gets a fresh body at the
|
|
373
|
+
* new team's start at once (from onRoundStart, at the start the round gives that team, as if they
|
|
374
|
+
* had chosen it); one waiting for a round waits on the new team. They go back to the team they
|
|
375
|
+
* chose when the lobby comes back. It takes effect after this tick: until the next one they still
|
|
376
|
+
* read as on their old team.
|
|
377
|
+
*/
|
|
378
|
+
setTeam(team: Team): void;
|
|
379
|
+
/**
|
|
380
|
+
* Gives them a role for this round, kept on the host and shown nowhere by itself: 0 to 24
|
|
381
|
+
* characters, "" for none (for game modes).
|
|
382
|
+
*/
|
|
383
|
+
setRole(role: string): void;
|
|
384
|
+
/** Sets their score: a whole number from -1000000000 to 1000000000 (for game modes). */
|
|
385
|
+
setScore(points: number): void;
|
|
386
|
+
/** Adds to their score, or takes away with a negative number (for game modes). */
|
|
387
|
+
addScore(points: number): void;
|
|
388
|
+
/**
|
|
389
|
+
* Brings them back now, if they are out or waiting to respawn in a round being played: at a point
|
|
390
|
+
* within 1000 m of the map's middle, or where their team comes back (for game modes).
|
|
391
|
+
*/
|
|
392
|
+
respawn(x?: number, y?: number, z?: number): void;
|
|
393
|
+
/** Takes this bot out of the match, and one fewer of its team's bots is asked for (bots only). */
|
|
394
|
+
removeBot(): void;
|
|
395
|
+
/** Gives this bot something to be after; "goTo" takes a point (bots only, for game modes). */
|
|
396
|
+
setGoal(goal: Goal, x?: number, y?: number, z?: number): void;
|
|
397
|
+
/**
|
|
398
|
+
* How well this bot plays: it starts at the lobby's bot skill. null for a person, and in every
|
|
399
|
+
* script on a player's PC, which isn't told. New in 1.7.0.
|
|
400
|
+
*/
|
|
401
|
+
readonly botLevel: BotLevel | null;
|
|
402
|
+
/**
|
|
403
|
+
* Makes this bot play at `level` from now on: how fast it reacts, turns and aims, how much it
|
|
404
|
+
* notices, and how hard it chases; the rest of its ways stay its own. Other bots keep theirs. It
|
|
405
|
+
* stays through rounds until the mode is done, when the bot goes back to the level it joined at
|
|
406
|
+
* (bots only, for game modes). New in 1.7.0.
|
|
407
|
+
*/
|
|
408
|
+
setBotLevel(level: BotLevel): void;
|
|
409
|
+
/**
|
|
410
|
+
* The creature they drive takes `target` in its jaws, as its own bite landing does: the catch, the
|
|
411
|
+
* kill and its credit all happen, wherever the two are. Nothing happens unless both are alive in
|
|
412
|
+
* a round being played, they drive a creature that bites (a shark), and its mouth is empty (for
|
|
413
|
+
* game modes).
|
|
414
|
+
*/
|
|
415
|
+
bite(target: Player): void;
|
|
416
|
+
/**
|
|
417
|
+
* Sets their cell under one of the columns game.scoreboard() named: a number, or text of 0 to 16
|
|
418
|
+
* characters (for game modes).
|
|
419
|
+
*/
|
|
420
|
+
setCell(column: string, value: number | string): void;
|
|
421
|
+
/**
|
|
422
|
+
* Shows them alone a line under the banner, until it is changed or a round starts, or the lobby
|
|
423
|
+
* comes back: 0 to 80 characters, "" to clear it. It is on screen, not in chat (for game modes).
|
|
424
|
+
*/
|
|
425
|
+
setLine(text: string): void;
|
|
426
|
+
|
|
427
|
+
/**
|
|
428
|
+
* Their speed as a share of normal: 1 is normal, 0 held still; null once gone. On the host it is
|
|
429
|
+
* what scripts set; on a player's PC it is what that PC was sent for them (1 if nothing).
|
|
430
|
+
*/
|
|
431
|
+
readonly speed: number | null;
|
|
432
|
+
/**
|
|
433
|
+
* Sets their speed as a share of normal, 0 to 3: 0 holds them still (they can still look round and
|
|
434
|
+
* use abilities), 1 is normal, 3 is three times as fast. It works for octopuses and divers: it
|
|
435
|
+
* scales swimming and crawling, while dashes keep their own pace. A creature a player drives (a
|
|
436
|
+
* shark on a mode's team) keeps its own speed. It stays until changed, and goes back to normal
|
|
437
|
+
* when a round starts and when the lobby comes back (on the host only).
|
|
438
|
+
*/
|
|
439
|
+
setSpeed(share: number): void;
|
|
440
|
+
/**
|
|
441
|
+
* Whether a script made them invisible (on the host); null in every script on a player's PC,
|
|
442
|
+
* which isn't told. New in 1.8.0.
|
|
443
|
+
*/
|
|
444
|
+
readonly invisible: boolean | null;
|
|
445
|
+
/**
|
|
446
|
+
* Makes them invisible to everyone else, or seen again with false. No other player's PC is sent
|
|
447
|
+
* their body (or the creature they drive on a mode's team), so nobody else sees or hears them, or
|
|
448
|
+
* sees their name, chat bubble or a marker on them, as if they were far off; they still see
|
|
449
|
+
* themselves and everyone else. They stay solid, and the game's bots still
|
|
450
|
+
* sense them. It stays until changed, through deaths and respawns, and
|
|
451
|
+
* goes back to seen when a round starts and when the lobby comes back (on the host only). New in
|
|
452
|
+
* 1.8.0.
|
|
453
|
+
*/
|
|
454
|
+
setInvisible(invisible: boolean): void;
|
|
455
|
+
/** Plays one of the game's sounds for them alone, wherever they are (in a client/ script, on that player's own screen only). */
|
|
456
|
+
playSound(sound: SoundName): void;
|
|
457
|
+
/**
|
|
458
|
+
* Shows them alone big text in the middle of the screen, as game.announce does for more players:
|
|
459
|
+
* 1 to 60 characters, for 0.5 to 15 seconds (3 if left out). It counts as a message from the map,
|
|
460
|
+
* with the same limits as game.say (in a client/ script, on that player's own screen only).
|
|
461
|
+
*/
|
|
462
|
+
announce(text: string, seconds?: number): void;
|
|
463
|
+
|
|
464
|
+
/**
|
|
465
|
+
* Switches one of their skills off, or on again with true. A skill switched off does nothing when
|
|
466
|
+
* they use it: pressing it (or starting to hold smell) plays a soft "no", an octopus's button for
|
|
467
|
+
* it shows faint, and a diver's crosshair dot dims. Switching grab off lets go of whatever they hold, and stops a grab on its way. Ink or a shot already on
|
|
468
|
+
* its way finishes. It stays until changed, through deaths and respawns, and every skill comes
|
|
469
|
+
* back as a round starts and when the lobby comes back, so switch them off in onRoundStart (on
|
|
470
|
+
* the host only).
|
|
471
|
+
*/
|
|
472
|
+
allow(skill: Skill, allowed: boolean): void;
|
|
473
|
+
/**
|
|
474
|
+
* Whether a skill works for them (true unless a script switched it off); null once gone. On a
|
|
475
|
+
* player's PC it is what that PC was sent for them.
|
|
476
|
+
*/
|
|
477
|
+
allowed(skill: Skill): boolean | null;
|
|
478
|
+
|
|
479
|
+
/**
|
|
480
|
+
* A store of values of their own, kept from round to round for the whole match. It is let go at
|
|
481
|
+
* the first round start after they leave, so onLeave can still read it. Each set of scripts has
|
|
482
|
+
* its own, as with store.
|
|
483
|
+
*/
|
|
484
|
+
readonly data: Store;
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
/** A trigger box placed on the map, found by name with game.zone(). */
|
|
488
|
+
interface Zone {
|
|
489
|
+
/** Its name on the map. */
|
|
490
|
+
readonly name: string;
|
|
491
|
+
/** Every living player inside it now. */
|
|
492
|
+
players(): Player[];
|
|
493
|
+
/** Calls `handler` each time a player swims in. */
|
|
494
|
+
onEnter(handler: (player: Player) => void): void;
|
|
495
|
+
/** Calls `handler` each time a player swims out. */
|
|
496
|
+
onLeave(handler: (player: Player) => void): void;
|
|
497
|
+
/** Calls `handler` when a spear flies in, with who threw it, if anyone still in the match did. */
|
|
498
|
+
onSpearEnter(handler: (thrower: Player | null) => void): void;
|
|
499
|
+
/** Calls `handler` when a spear leaves, with who threw it. */
|
|
500
|
+
onSpearLeave(handler: (thrower: Player | null) => void): void;
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
/**
|
|
504
|
+
* A piece of the map you named for scripts: in the add-on, add it to the group `script` (or
|
|
505
|
+
* `switch`, for one players can use, such as a lever). Its node's name is its name here.
|
|
506
|
+
*/
|
|
507
|
+
interface Piece {
|
|
508
|
+
/** Its name on the map. */
|
|
509
|
+
readonly name: string;
|
|
510
|
+
/** Whether players can use it (it is in the `switch` group). */
|
|
511
|
+
readonly isSwitch: boolean;
|
|
512
|
+
/** Where it is, or null before the match's first tick. */
|
|
513
|
+
readonly position: Point | null;
|
|
514
|
+
/** Which way it faces, in degrees round the up axis, or null before the first tick. */
|
|
515
|
+
readonly turn: number | null;
|
|
516
|
+
/** Whether it is shown, or null before the first tick. */
|
|
517
|
+
readonly shown: boolean | null;
|
|
518
|
+
|
|
519
|
+
/**
|
|
520
|
+
* Moves it to a point within 1000 m of the map's middle, at once or gliding over 0 to 60 seconds.
|
|
521
|
+
* It is solid on its way, like anything else that moves.
|
|
522
|
+
*/
|
|
523
|
+
moveTo(x: number, y: number, z: number, seconds?: number): void;
|
|
524
|
+
/** Turns it to face `degrees` round the up axis (-3600 to 3600), at once or over 0 to 60 seconds. */
|
|
525
|
+
turnTo(degrees: number, seconds?: number): void;
|
|
526
|
+
/** Shows it, solid again. */
|
|
527
|
+
show(): void;
|
|
528
|
+
/** Hides it: nobody sees it or bumps into it. */
|
|
529
|
+
hide(): void;
|
|
530
|
+
/**
|
|
531
|
+
* Calls `handler` each time a player uses it: they press Interact (the eat key) within 1.5 m.
|
|
532
|
+
* Only a switch can be used; asking this of any other piece throws.
|
|
533
|
+
*/
|
|
534
|
+
onUse(handler: (player: Player) => void): void;
|
|
535
|
+
}
|
|
536
|
+
|
|
537
|
+
/**
|
|
538
|
+
* A creature or food in the match, placed by the map or spawned by a script. The same one is always
|
|
539
|
+
* the same object. Once it has gone (eaten, killed or removed), `gone` is true and it reads as null.
|
|
540
|
+
*/
|
|
541
|
+
interface Creature {
|
|
542
|
+
/** Its number in this match. */
|
|
543
|
+
readonly id: number;
|
|
544
|
+
/** What it is. */
|
|
545
|
+
readonly kind: CreatureKind;
|
|
546
|
+
/** Whether it is no longer in the match. */
|
|
547
|
+
readonly gone: boolean;
|
|
548
|
+
/** Whether it is alive. */
|
|
549
|
+
readonly alive: boolean;
|
|
550
|
+
/** Where it is, or null once gone. */
|
|
551
|
+
readonly position: Point | null;
|
|
552
|
+
/** Takes it out of the match, on every player's screen. */
|
|
553
|
+
remove(): void;
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
/** The match, as the script sees it. */
|
|
557
|
+
interface Game {
|
|
558
|
+
/** The match's time, in ticks: 64 a second. */
|
|
559
|
+
readonly ticks: number;
|
|
560
|
+
/** The match's time, in seconds. */
|
|
561
|
+
readonly seconds: number;
|
|
562
|
+
/** Where the match is: in the lobby, playing a round, or showing its results. */
|
|
563
|
+
readonly phase: Phase;
|
|
564
|
+
/** How long the round has left, in seconds. */
|
|
565
|
+
readonly timeLeft: number;
|
|
566
|
+
|
|
567
|
+
/** Every player in the match, by number. */
|
|
568
|
+
players(): Player[];
|
|
569
|
+
/** A number from 0 up to (not including) 1, the same series for the same match. */
|
|
570
|
+
random(): number;
|
|
571
|
+
/**
|
|
572
|
+
* Ends the round, with `winner` the team that won it, or one player (where everyone plays for
|
|
573
|
+
* themselves, in a game mode), or "draw" for nobody. The results say why with the game's own line
|
|
574
|
+
* named by `why`, or else that the map (or the game mode) decided. `why` must fit the winning
|
|
575
|
+
* team: "allCaught", "allTurned" and "octopusesLeft" are the divers' wins, "timeUp" and
|
|
576
|
+
* "diversLeft" the octopuses'. Give `text` (up to 80 characters) to say why in your own words
|
|
577
|
+
* instead; pass null for `why` to give only that: game.endRound("red", null, "Red held the reef").
|
|
578
|
+
*/
|
|
579
|
+
endRound(winner: Team | Player | "draw", why?: EndWhy | null, text?: string): void;
|
|
580
|
+
/** Adds time to the round, or takes it away with a negative number: -3600 to 3600 seconds. */
|
|
581
|
+
addTime(seconds: number): void;
|
|
582
|
+
|
|
583
|
+
/** The trigger zone with this name, or null if the map has none. */
|
|
584
|
+
zone(name: string): Zone | null;
|
|
585
|
+
/** Every trigger zone on the map. */
|
|
586
|
+
zones(): Zone[];
|
|
587
|
+
/** The piece with this name, or null if no piece is named that. */
|
|
588
|
+
piece(name: string): Piece | null;
|
|
589
|
+
/** Every piece named for scripts. */
|
|
590
|
+
pieces(): Piece[];
|
|
591
|
+
|
|
592
|
+
/** Every creature and food in the match, or only those of one kind. */
|
|
593
|
+
creatures(kind?: CreatureKind): Creature[];
|
|
594
|
+
/**
|
|
595
|
+
* Asks the game for a creature or food near a point within 1000 m of the map's middle, and gives
|
|
596
|
+
* back its handle at once. The game puts it where such a thing can be:
|
|
597
|
+
* - food grows on the free food spot nearest the point that suits it, if one is within 10 m
|
|
598
|
+
* (crabs on sand or rock, shrimp on sand, clams on rock), and doesn't grow back once eaten;
|
|
599
|
+
* - a shark joins its loop round the map at the point nearest yours;
|
|
600
|
+
* - an eel or a groper goes beside the rock nearest the point;
|
|
601
|
+
* - a lionfish hovers at the point, lifted clear of any rock, and a flounder lies on the seabed
|
|
602
|
+
* under it, if the seabed is within 50 m. Every player sees them, players who join later too.
|
|
603
|
+
* Sharks, eels and gropers come only while a round is being played. If the game finds no place,
|
|
604
|
+
* the handle reads as gone from the next tick. A script may have at most 1 shark, 4 eels, 4
|
|
605
|
+
* gropers, 256 of each food and 256 fish it spawned alive at once; asking for more throws.
|
|
606
|
+
*/
|
|
607
|
+
spawn(kind: CreatureKind, x: number, y: number, z: number): Creature;
|
|
608
|
+
|
|
609
|
+
/**
|
|
610
|
+
* Living players with a position within `radius` metres of `point`, nearest first; only `team`'s if
|
|
611
|
+
* given. On a player's PC it finds only the players that PC was sent.
|
|
612
|
+
*/
|
|
613
|
+
playersNear(point: Point, radius: number, team?: Team): Player[];
|
|
614
|
+
/**
|
|
615
|
+
* The nearest living player with a position, of `team` if given, leaving out `except` (say, the
|
|
616
|
+
* player asking); or null if there is none.
|
|
617
|
+
*/
|
|
618
|
+
nearestPlayer(point: Point, team?: Team, except?: Player): Player | null;
|
|
619
|
+
/** Living creatures and food within `radius` metres of `point`, nearest first; only `kind`'s if given. */
|
|
620
|
+
creaturesNear(point: Point, radius: number, kind?: CreatureKind): Creature[];
|
|
621
|
+
/** The nearest living creature or food, of `kind` if given; or null if there is none. */
|
|
622
|
+
nearestCreature(point: Point, kind?: CreatureKind): Creature | null;
|
|
623
|
+
|
|
624
|
+
/** The box players swim in. Fixed for the match. */
|
|
625
|
+
readonly playArea: PlayArea;
|
|
626
|
+
/**
|
|
627
|
+
* Casts a ray from `from` to `to` through the map and settles with where it first met the map's
|
|
628
|
+
* rock, sand or pieces, or null if nothing is in the way. It meets only the map: players,
|
|
629
|
+
* creatures, plants and the play area's edge are let through. The answer comes on the next tick
|
|
630
|
+
* (a sixty-fourth of a second), so `await` it. Both ends must be within 1000 m of the map's
|
|
631
|
+
* middle. At most 32 rays a tick; asking for more throws. Every script can use it.
|
|
632
|
+
*/
|
|
633
|
+
raycast(from: Point, to: Point): Promise<RayHit | null>;
|
|
634
|
+
/** Whether nothing of the map stands between `a` and `b`: true when a ray between them meets nothing. One ray. */
|
|
635
|
+
lineOfSight(a: Point, b: Point): Promise<boolean>;
|
|
636
|
+
/** The ground straight under `point`, down to under the play area's floor; or null if there is none. One ray. */
|
|
637
|
+
groundBelow(point: Point): Promise<RayHit | null>;
|
|
638
|
+
|
|
639
|
+
/** Shows everyone a message from the map: 1 to 120 characters, a few a second at most. */
|
|
640
|
+
say(text: string): void;
|
|
641
|
+
/** Shows one team a message from the map. */
|
|
642
|
+
sayToTeam(team: Team, text: string): void;
|
|
643
|
+
/** Plays one of the game's sounds for everyone, wherever they are. A few a second at most. */
|
|
644
|
+
playSound(sound: SoundName): void;
|
|
645
|
+
/** Plays one of the game's sounds for one team only, wherever they are (in a client/ script, on that player's own screen only). */
|
|
646
|
+
playSoundForTeam(team: Team, sound: SoundName): void;
|
|
647
|
+
/** Plays one of the game's sounds at a point, heard by whoever is near. */
|
|
648
|
+
playSoundAt(sound: SoundName, x: number, y: number, z: number): void;
|
|
649
|
+
/** The names of the sounds a map can play. */
|
|
650
|
+
sounds(): SoundName[];
|
|
651
|
+
|
|
652
|
+
/**
|
|
653
|
+
* The value of the game mode's lobby setting with this name in its mode.json, as the host chose
|
|
654
|
+
* it, or null if it has none (for game modes; a map's script reads null).
|
|
655
|
+
*/
|
|
656
|
+
setting(name: string): SettingValue | null;
|
|
657
|
+
/** A team's score this round, as the match's scripts set it. */
|
|
658
|
+
teamScore(team: Team): number;
|
|
659
|
+
/** Sets a team's score: a whole number from -1000000000 to 1000000000 (for game modes). */
|
|
660
|
+
setTeamScore(team: Team, points: number): void;
|
|
661
|
+
/** Adds to a team's score, or takes away with a negative number (for game modes). */
|
|
662
|
+
addTeamScore(team: Team, points: number): void;
|
|
663
|
+
/**
|
|
664
|
+
* Everyone plays for themselves: nobody is anyone's teammate. No names over rivals' heads, no
|
|
665
|
+
* shared pings, team chat or diver radio, every diver may hurt every other whatever the lobby's
|
|
666
|
+
* friendly fire says, and diver bots fight rival divers as well as hunting octopuses (for game
|
|
667
|
+
* modes).
|
|
668
|
+
*/
|
|
669
|
+
freeForAll(on: boolean): void;
|
|
670
|
+
/**
|
|
671
|
+
* What divers carry, from "spear" (the spear gun), "net" (the net gun), "sensor" (motion sensors)
|
|
672
|
+
* and "torch" (the lamp), each once, with at least one gun. With one gun only, divers get that gun
|
|
673
|
+
* whatever the lobby's Gun setting, and the lobby shows it as set by the mode. What they lack isn't
|
|
674
|
+
* on their screen. Until a script calls it, divers carry everything (for game modes).
|
|
675
|
+
*/
|
|
676
|
+
loadout(team: "diver", ...tools: Tool[]): void;
|
|
677
|
+
/**
|
|
678
|
+
* Closes a team to people in the lobby: its Join button greys out with `why` (1 to 60 characters)
|
|
679
|
+
* under it, and asking to join it is refused. Nobody already on it is moved; use setTeam for that
|
|
680
|
+
* (for game modes).
|
|
681
|
+
*/
|
|
682
|
+
closeTeam(team: Team, why: string): void;
|
|
683
|
+
/** Opens a team closed by closeTeam again (for game modes). */
|
|
684
|
+
openTeam(team: Team): void;
|
|
685
|
+
/**
|
|
686
|
+
* Adds a team of the mode's own, or changes one it added: `id` (1 to 16 lower-case letters) is
|
|
687
|
+
* what every call that takes a team calls it from then on. Its players each drive a creature of
|
|
688
|
+
* `team.body`; bots fill it with setBots, and people join it in the lobby like any team. A mode may
|
|
689
|
+
* add 2. Call it from onMatchStart: a mode being left takes its teams with it, and anyone on one
|
|
690
|
+
* goes back to the octopuses or the divers (for game modes).
|
|
691
|
+
*/
|
|
692
|
+
registerTeam(id: string, team: TeamSpec): void;
|
|
693
|
+
/**
|
|
694
|
+
* Gives a team the mode added an ability, or changes one it gave: `id` (1 to 16 lower-case
|
|
695
|
+
* letters) is what onAbility and onAbilityLand call it. A team may have 2, one in each slot. The
|
|
696
|
+
* game does the key, the HUD button, the cooldown and the aiming; what the ability does is up to
|
|
697
|
+
* the handlers. Call it from onMatchStart, after registerTeam (for game modes).
|
|
698
|
+
*
|
|
699
|
+
* For a picture of its own on the button, put a square PNG named after the id in the mode's
|
|
700
|
+
* `icons` folder, beside `scripts`: `icons/quickdash.png` for the id "quickdash". Up to 512 KB
|
|
701
|
+
* and 1024 pixels across each, and 8 in a mode; it is drawn round, so keep what matters away from the corners. Without
|
|
702
|
+
* one the button shows a plain arrow.
|
|
703
|
+
*/
|
|
704
|
+
registerAbility(id: string, ability: AbilitySpec): void;
|
|
705
|
+
/**
|
|
706
|
+
* The mode alone decides how many bots a team has, with setBots: the lobby hides the host's bot
|
|
707
|
+
* count for that team and says the mode sets it (for game modes).
|
|
708
|
+
*/
|
|
709
|
+
modeBots(team: Team, on: boolean): void;
|
|
710
|
+
/**
|
|
711
|
+
* Asks for `count` bots on a team, 0 to 32. The lobby keeps that many, and a round being played
|
|
712
|
+
* gets or loses them at once. People always keep their places: no more bots join than the
|
|
713
|
+
* team's cap in the lobby, the game's 32 players and the mode's maxPlayers have room for (for
|
|
714
|
+
* game modes).
|
|
715
|
+
*/
|
|
716
|
+
setBots(team: Team, count: number): void;
|
|
717
|
+
/**
|
|
718
|
+
* What being caught or killed does to a team's players, with the wait for "respawn" and "turn": 0
|
|
719
|
+
* to 600 seconds, or the lobby's respawn time when left out (for game modes). Until a script sets
|
|
720
|
+
* it, octopuses are "held" and divers "respawn". A player who turns is marked as turned for the
|
|
721
|
+
* rest of the round, on the scoreboard and the results.
|
|
722
|
+
*/
|
|
723
|
+
setFate(team: Team, fate: Fate, seconds?: number): void;
|
|
724
|
+
/** Where a team's players come back, at a point within 1000 m of the map's middle (for game modes). */
|
|
725
|
+
setSpawn(team: Team, x: number, y: number, z: number): void;
|
|
726
|
+
/** A team's players come back at their own start points again (for game modes). */
|
|
727
|
+
clearSpawn(team: Team): void;
|
|
728
|
+
/** Sets the time left in a round being played: 0 to 86400 seconds (for game modes). */
|
|
729
|
+
setTimeLeft(seconds: number): void;
|
|
730
|
+
/** Holds the round's clock still, or lets it run again (for game modes). */
|
|
731
|
+
holdClock(held: boolean): void;
|
|
732
|
+
/**
|
|
733
|
+
* Names the live scoreboard's columns, up to 6 of 1 to 16 characters, each once, shown beside each
|
|
734
|
+
* player's name and score during the round and on the results. None hides it (for game modes).
|
|
735
|
+
* Every person is listed; a bot only once the match's scripts give it a score or a cell
|
|
736
|
+
* (setScore, addScore, setCell), even 0 or "", so bots a mode leaves alone stay off.
|
|
737
|
+
*/
|
|
738
|
+
scoreboard(...columns: string[]): void;
|
|
739
|
+
/** Shows everyone a banner across the top: 0 to 80 characters, "" to clear it (for game modes). */
|
|
740
|
+
banner(text: string): void;
|
|
741
|
+
|
|
742
|
+
/**
|
|
743
|
+
* Shows big text in the middle of the screen: 1 to 60 characters, for `seconds` (0.5 to 15, 3 if
|
|
744
|
+
* left out). A new one replaces the one showing. It counts as a message from the map, towards the
|
|
745
|
+
* same limits as game.say: at most 3 a tick and 6 a second for any one player, and a call that
|
|
746
|
+
* would go over throws. `viewers` is one team or one player; leave it out for everyone (in a
|
|
747
|
+
* client/ script, on that player's own screen only).
|
|
748
|
+
*/
|
|
749
|
+
announce(text: string, seconds?: number, viewers?: Viewers): void;
|
|
750
|
+
/**
|
|
751
|
+
* Shows a HUD widget in the column on the left of the screen, under the banner, or changes the
|
|
752
|
+
* one with this id: `id` is 1 to 16 letters, digits, - or _. At most 8 widgets show on any
|
|
753
|
+
* player's screen: a 9th isn't shown on that screen (no error), and changing or removing those
|
|
754
|
+
* already there always works. They stay until removed, or until the lobby comes back. A call that
|
|
755
|
+
* changes nothing sends nothing, so it is fine to call it every tick; when a script changes a lot
|
|
756
|
+
* at once, each player is sent a few changes a tick and the latest of each wins. A "timer" counts
|
|
757
|
+
* down by itself: asking for it again with the same seconds doesn't restart it; new seconds do.
|
|
758
|
+
* A player who joins later sees what is showing for everyone and for their team, and one who
|
|
759
|
+
* moves to another team swaps the old team's for the new one's. A map's and a mode's widgets
|
|
760
|
+
* never share an id, and a client/ script's own widgets have their own room of 8. `viewers` is one team or one player; leave it out for
|
|
761
|
+
* everyone (in a client/ script, on that player's own screen only).
|
|
762
|
+
*/
|
|
763
|
+
widget(id: string, spec: WidgetSpec, viewers?: Viewers): void;
|
|
764
|
+
/**
|
|
765
|
+
* Takes the widget with this id off the screens of `viewers`, or everyone's if left out
|
|
766
|
+
* (in a client/ script, on that player's own screen only).
|
|
767
|
+
*/
|
|
768
|
+
removeWidget(id: string, viewers?: Viewers): void;
|
|
769
|
+
/**
|
|
770
|
+
* Shows a marker in the world, or moves or changes the one with this id (ids as for widget). At
|
|
771
|
+
* most 16 show on any player's screen: a 17th isn't shown on that screen (no error), and changing
|
|
772
|
+
* or removing those already there always works. Like widgets, it reaches players who join later.
|
|
773
|
+
* `viewers` is one team or one player; leave it out for everyone (in a client/ script, on that player's own screen only).
|
|
774
|
+
*/
|
|
775
|
+
marker(id: string, spec: MarkerSpec, viewers?: Viewers): void;
|
|
776
|
+
/**
|
|
777
|
+
* Takes the marker with this id off the screens of `viewers`, or everyone's if left out
|
|
778
|
+
* (in a client/ script, on that player's own screen only).
|
|
779
|
+
*/
|
|
780
|
+
removeMarker(id: string, viewers?: Viewers): void;
|
|
781
|
+
/**
|
|
782
|
+
* Opens a menu (ids as for widget) on the screens of `viewers`, or everyone's if left out. A
|
|
783
|
+
* player has one menu at a time: a new one takes the place of the one they have. A pick calls
|
|
784
|
+
* game.onChoose's handlers and closes the menu for that player; open it again to let them pick
|
|
785
|
+
* again. It is shown to who is in the match now, not to players who join later, and the lobby
|
|
786
|
+
* closes every menu. Host scripts only: in a client/ script it does nothing. At most 16 menu
|
|
787
|
+
* and removeMenu calls a tick; more throws.
|
|
788
|
+
*/
|
|
789
|
+
menu(id: string, spec: MenuSpec, viewers?: Viewers): void;
|
|
790
|
+
/** Closes the menu with this id for `viewers`, or everyone, if they still have it. */
|
|
791
|
+
removeMenu(id: string, viewers?: Viewers): void;
|
|
792
|
+
/**
|
|
793
|
+
* Puts a question to `viewers` (or everyone) as a menu, and settles with how it came out once
|
|
794
|
+
* `seconds` are up or every person shown it has answered, whichever comes first. Each person's
|
|
795
|
+
* first pick counts; bots never answer and aren't waited for. Its menu's id is "vote-" and a
|
|
796
|
+
* number, and its picks reach game.onChoose too. Host scripts only.
|
|
797
|
+
*/
|
|
798
|
+
vote(spec: VoteSpec, viewers?: Viewers): Promise<VoteResult>;
|
|
799
|
+
|
|
800
|
+
/**
|
|
801
|
+
* Changes the water for everyone: its colour, how far anyone sees through it and how bright it
|
|
802
|
+
* is, each left as the map has it when left out. It fades in over `seconds` (0 to 60; at once if
|
|
803
|
+
* left out). A new call takes the place of the last, from the water shown then. Players who join
|
|
804
|
+
* later get it, and the lobby gives back the map's own. Host scripts only: in a client/ script it
|
|
805
|
+
* does nothing.
|
|
806
|
+
*/
|
|
807
|
+
setWater(spec: WaterSpec, seconds?: number): void;
|
|
808
|
+
/** Gives back the map's own water, fading over `seconds` (0 to 60; at once if left out). */
|
|
809
|
+
resetWater(seconds?: number): void;
|
|
810
|
+
/**
|
|
811
|
+
* Puts up a light for everyone, or moves or changes the one with this id (ids as for widget). At
|
|
812
|
+
* most 16 are up at once, the map's and the mode's together: a 17th isn't put up (no error), and
|
|
813
|
+
* changing or removing those already up always works. Lights cast no shadows. Players who join
|
|
814
|
+
* later get them, and the lobby takes them all down. Host scripts only.
|
|
815
|
+
*/
|
|
816
|
+
light(id: string, spec: LightSpec): void;
|
|
817
|
+
/** Takes down the light with this id, if it is up. */
|
|
818
|
+
removeLight(id: string): void;
|
|
819
|
+
|
|
820
|
+
/** Calls `handler` once, when the match starts. */
|
|
821
|
+
onMatchStart(handler: () => void): void;
|
|
822
|
+
/** Calls `handler` when a round starts. */
|
|
823
|
+
onRoundStart(handler: () => void): void;
|
|
824
|
+
/**
|
|
825
|
+
* Calls `handler` when a round ends, with the team that won it, or null and the player who won it,
|
|
826
|
+
* or null and null for a draw.
|
|
827
|
+
*/
|
|
828
|
+
onRoundEnd(handler: (winner: Team | null, player: Player | null) => void): void;
|
|
829
|
+
/**
|
|
830
|
+
* Calls `handler` when a player comes back in a round being played, after being out or waiting
|
|
831
|
+
* to respawn. The lobby's warm-up bodies aren't respawns.
|
|
832
|
+
*/
|
|
833
|
+
onRespawn(handler: (player: Player) => void): void;
|
|
834
|
+
/** Calls `handler` when a player moves to the other team, whatever moved them. */
|
|
835
|
+
onTeamChange(handler: (player: Player, from: Team, to: Team) => void): void;
|
|
836
|
+
/**
|
|
837
|
+
* Calls `handler` when the round's clock runs out, in a game mode. End the round on that tick, or
|
|
838
|
+
* it ends as a draw.
|
|
839
|
+
*/
|
|
840
|
+
onTimeUp(handler: () => void): void;
|
|
841
|
+
/** Calls `handler` when a player joins the match. */
|
|
842
|
+
onJoin(handler: (player: Player) => void): void;
|
|
843
|
+
/** Calls `handler` when a player leaves the match. Their handle reads as gone from then on. */
|
|
844
|
+
onLeave(handler: (player: Player) => void): void;
|
|
845
|
+
/** Calls `handler` when a player finishes eating something. */
|
|
846
|
+
onEat(handler: (player: Player, food: FoodKind) => void): void;
|
|
847
|
+
/** Calls `handler` when a player is caught, with who caught them, if a player did. */
|
|
848
|
+
onCaught(handler: (player: Player, by: Player | null, how: Catch) => void): void;
|
|
849
|
+
/** Calls `handler` when a player is killed, with who killed them, if a player did. */
|
|
850
|
+
onKilled(handler: (player: Player, by: Player | null) => void): void;
|
|
851
|
+
/**
|
|
852
|
+
* Calls `handler` when a player uses one of the mode's abilities (game.registerAbility), with its
|
|
853
|
+
* id and who it was aimed at. Its cooldown has started; a lunge, if it has one, is on its way.
|
|
854
|
+
*/
|
|
855
|
+
onAbility(handler: (player: Player, ability: string, target: Player) => void): void;
|
|
856
|
+
/** Calls `handler` when an ability's lunge reaches who it was aimed at. */
|
|
857
|
+
onAbilityLand(handler: (player: Player, ability: string, target: Player) => void): void;
|
|
858
|
+
/**
|
|
859
|
+
* Calls `handler` when a player dashes (octopuses only). Heard on the host only. onDash, onInk and onGrab are
|
|
860
|
+
* for octopuses only: a mode's own team's ability keys are heard with onAbility.
|
|
861
|
+
*/
|
|
862
|
+
onDash(handler: (player: Player) => void): void;
|
|
863
|
+
/** Calls `handler` when an octopus squirts ink. Heard on the host only. */
|
|
864
|
+
onInk(handler: (player: Player) => void): void;
|
|
865
|
+
/** Calls `handler` when an octopus grabs at something. Heard on the host only. */
|
|
866
|
+
onGrab(handler: (player: Player) => void): void;
|
|
867
|
+
/** Calls `handler` when a diver fires either gun. Heard on the host only. */
|
|
868
|
+
onShoot(handler: (player: Player) => void): void;
|
|
869
|
+
/**
|
|
870
|
+
* Calls `handler` when a player picks from a menu this script opened (game.menu), with the menu's
|
|
871
|
+
* id, where the choice is in its list (0 for the first) and the choice's text. Each menu a player
|
|
872
|
+
* is shown is picked from once at most; a pick after it closed is never heard.
|
|
873
|
+
*/
|
|
874
|
+
onChoose(handler: (player: Player, menu: string, choice: number, text: string) => void): void;
|
|
875
|
+
}
|
|
876
|
+
|
|
877
|
+
/** The match. */
|
|
878
|
+
declare const game: Game;
|
|
879
|
+
|
|
880
|
+
/** Calls `handler` once, `seconds` from now (0 to 86400; 0 is the next tick). */
|
|
881
|
+
declare function after(seconds: number, handler: () => void): TimerId;
|
|
882
|
+
/** Calls `handler` every `seconds` (0 to 86400; 0 is every tick), until cancelled. */
|
|
883
|
+
declare function every(seconds: number, handler: () => void): TimerId;
|
|
884
|
+
/** Stops a timer after() or every() gave back. Says whether it was still waiting. */
|
|
885
|
+
declare function cancel(timer: TimerId): boolean;
|
|
886
|
+
|
|
887
|
+
// Helpers: plain JavaScript every script has, on the host and on players' PCs alike. They change
|
|
888
|
+
// nothing in the match by themselves.
|
|
889
|
+
|
|
890
|
+
/** Vector maths on points ({x, y, z}). Every call gives back a new point and leaves its inputs alone. */
|
|
891
|
+
declare const Vec: {
|
|
892
|
+
/** A point from its three parts. */
|
|
893
|
+
of(x: number, y: number, z: number): Point;
|
|
894
|
+
/** The point {0, 0, 0}. */
|
|
895
|
+
readonly zero: Point;
|
|
896
|
+
/** The point {0, 1, 0}: one metre straight up. */
|
|
897
|
+
readonly up: Point;
|
|
898
|
+
/** a and b added together. */
|
|
899
|
+
add(a: Point, b: Point): Point;
|
|
900
|
+
/** b taken away from a: the way from b to a. */
|
|
901
|
+
sub(a: Point, b: Point): Point;
|
|
902
|
+
/** a made `by` times as long. */
|
|
903
|
+
scale(a: Point, by: number): Point;
|
|
904
|
+
/** How long a is, in metres. */
|
|
905
|
+
length(a: Point): number;
|
|
906
|
+
/** How far apart a and b are, in metres. */
|
|
907
|
+
distance(a: Point, b: Point): number;
|
|
908
|
+
/** a made 1 long, pointing the same way; or Vec.zero if a has no length. */
|
|
909
|
+
normalize(a: Point): Point;
|
|
910
|
+
/** The dot product of a and b. */
|
|
911
|
+
dot(a: Point, b: Point): number;
|
|
912
|
+
/** The cross product of a and b: a point at right angles to both. */
|
|
913
|
+
cross(a: Point, b: Point): Point;
|
|
914
|
+
/** The point `t` of the way from a to b: t 0 is a, 1 is b, 0.5 halfway. */
|
|
915
|
+
lerp(a: Point, b: Point, t: number): Point;
|
|
916
|
+
/** a with y set to 0: for distances across the map, ignoring depth. */
|
|
917
|
+
flat(a: Point): Point;
|
|
918
|
+
};
|
|
919
|
+
|
|
920
|
+
/** Number helpers the built-in Math lacks. */
|
|
921
|
+
declare const Maths: {
|
|
922
|
+
/** value kept from low to high. */
|
|
923
|
+
clamp(value: number, low: number, high: number): number;
|
|
924
|
+
/** The number `t` of the way from `from` to `to`: t 0 is from, 1 is to. */
|
|
925
|
+
lerp(from: number, to: number, t: number): number;
|
|
926
|
+
/** How far value is from `from` to `to`, as 0 to 1 (not clamped: it can be below 0 or above 1). */
|
|
927
|
+
inverseLerp(from: number, to: number, value: number): number;
|
|
928
|
+
/** value moved from the range inLow to inHigh into the range outLow to outHigh. */
|
|
929
|
+
remap(value: number, inLow: number, inHigh: number, outLow: number, outHigh: number): number;
|
|
930
|
+
/** Degrees to radians. */
|
|
931
|
+
toRadians(degrees: number): number;
|
|
932
|
+
/** Radians to degrees. */
|
|
933
|
+
toDegrees(radians: number): number;
|
|
934
|
+
/** degrees brought into the range above -180 and up to 180. */
|
|
935
|
+
wrapDegrees(degrees: number): number;
|
|
936
|
+
/** current moved towards target by at most step, never past it. */
|
|
937
|
+
approach(current: number, target: number, step: number): number;
|
|
938
|
+
};
|
|
939
|
+
|
|
940
|
+
/**
|
|
941
|
+
* Random numbers from a seed of your own: the same seed gives the same numbers, in the same order,
|
|
942
|
+
* on every PC. Use game.random() for numbers nobody can guess ahead.
|
|
943
|
+
*/
|
|
944
|
+
declare class Random {
|
|
945
|
+
/** A series of random numbers that starts from `seed`. */
|
|
946
|
+
constructor(seed: number);
|
|
947
|
+
/** A number from 0 up to (not including) 1. */
|
|
948
|
+
next(): number;
|
|
949
|
+
/** A number from low up to (not including) high. */
|
|
950
|
+
range(low: number, high: number): number;
|
|
951
|
+
/** A whole number from low to high, both included. */
|
|
952
|
+
int(low: number, high: number): number;
|
|
953
|
+
/** true with the chance `p`: 0 never, 1 always, 0.25 one time in four. */
|
|
954
|
+
chance(p: number): boolean;
|
|
955
|
+
/** One item of the list, or undefined if it is empty. */
|
|
956
|
+
pick<T>(list: readonly T[]): T | undefined;
|
|
957
|
+
/** Shuffles the list in place and gives it back. */
|
|
958
|
+
shuffle<T>(list: T[]): T[];
|
|
959
|
+
}
|
|
960
|
+
|
|
961
|
+
/** An easing curve: takes t from 0 to 1 and gives back the eased value (0 at 0, 1 at 1). */
|
|
962
|
+
type Easing = (t: number) => number;
|
|
963
|
+
|
|
964
|
+
/**
|
|
965
|
+
* Easing curves, for tween() or to call yourself, as in Maths.lerp(a, b, Ease.outQuad(t)). "in"
|
|
966
|
+
* starts slow, "out" ends slow, "inOut" does both. outBack goes a little past the end and settles
|
|
967
|
+
* back, outBounce bounces, outElastic wobbles.
|
|
968
|
+
*/
|
|
969
|
+
declare const Ease: {
|
|
970
|
+
linear: Easing;
|
|
971
|
+
inQuad: Easing;
|
|
972
|
+
outQuad: Easing;
|
|
973
|
+
inOutQuad: Easing;
|
|
974
|
+
inCubic: Easing;
|
|
975
|
+
outCubic: Easing;
|
|
976
|
+
inOutCubic: Easing;
|
|
977
|
+
inSine: Easing;
|
|
978
|
+
outSine: Easing;
|
|
979
|
+
inOutSine: Easing;
|
|
980
|
+
outBack: Easing;
|
|
981
|
+
outBounce: Easing;
|
|
982
|
+
outElastic: Easing;
|
|
983
|
+
};
|
|
984
|
+
|
|
985
|
+
/**
|
|
986
|
+
* Calls `step` every tick for `seconds` (0 to 86400; anything else throws), with how far along it
|
|
987
|
+
* is: 0 to 1, eased (Ease.linear if left out). The last call is always with 1, then `done` is
|
|
988
|
+
* called. Gives back a timer: cancel() it to stop it early.
|
|
989
|
+
*/
|
|
990
|
+
declare function tween(
|
|
991
|
+
seconds: number,
|
|
992
|
+
step: (t: number) => void,
|
|
993
|
+
options?: { ease?: Easing; done?: () => void },
|
|
994
|
+
): TimerId;
|
|
995
|
+
|
|
996
|
+
/** One state of a StateMachine. Each part is optional. */
|
|
997
|
+
interface State {
|
|
998
|
+
/** Called when the machine goes into this state. */
|
|
999
|
+
enter?(): void;
|
|
1000
|
+
/** Called every tick while in this state, with the seconds since it went in. */
|
|
1001
|
+
tick?(seconds: number): void;
|
|
1002
|
+
/** Called when the machine leaves this state. */
|
|
1003
|
+
leave?(): void;
|
|
1004
|
+
}
|
|
1005
|
+
|
|
1006
|
+
/**
|
|
1007
|
+
* A set of named states, in one at a time, ticked every tick by itself, whatever the match's phase
|
|
1008
|
+
* (in the lobby too). It goes into `start` at once. If a state calls go() on its own machine, give the machine's type by hand:
|
|
1009
|
+
* `const phases: StateMachine<"wait" | "play"> = new StateMachine({ ... }, "wait");`.
|
|
1010
|
+
*/
|
|
1011
|
+
declare class StateMachine<S extends string = string> {
|
|
1012
|
+
/** The states by name, and the one to start in. */
|
|
1013
|
+
constructor(states: Record<S, State>, start: S);
|
|
1014
|
+
/** The state it is in. */
|
|
1015
|
+
readonly state: S;
|
|
1016
|
+
/** Seconds since it went into the state it is in. */
|
|
1017
|
+
readonly seconds: number;
|
|
1018
|
+
/** Leaves the state it is in and goes into `state`. Going into the same one starts it again. */
|
|
1019
|
+
go(state: S): void;
|
|
1020
|
+
/** Stops ticking it, for good. */
|
|
1021
|
+
stop(): void;
|
|
1022
|
+
}
|
|
1023
|
+
|
|
1024
|
+
/** Values kept by name: the round's store, and each player's data. */
|
|
1025
|
+
interface Store {
|
|
1026
|
+
/** The value kept under `key`, or `fallback` if there is none. */
|
|
1027
|
+
get<T = unknown>(key: string, fallback?: T): T;
|
|
1028
|
+
/** Keeps `value` under `key`. */
|
|
1029
|
+
set(key: string, value: unknown): void;
|
|
1030
|
+
/** Adds `by` (1 if left out) to the number kept under `key` (0 if none) and gives back the sum. */
|
|
1031
|
+
add(key: string, by?: number): number;
|
|
1032
|
+
/** Whether anything is kept under `key`. */
|
|
1033
|
+
has(key: string): boolean;
|
|
1034
|
+
/** Forgets `key`. Says whether anything was kept under it. */
|
|
1035
|
+
delete(key: string): boolean;
|
|
1036
|
+
/** Every key with something kept under it. */
|
|
1037
|
+
keys(): string[];
|
|
1038
|
+
/** Forgets everything. */
|
|
1039
|
+
clear(): void;
|
|
1040
|
+
}
|
|
1041
|
+
|
|
1042
|
+
/**
|
|
1043
|
+
* A store of values by name, for this round: it is emptied as each round starts, before your
|
|
1044
|
+
* onRoundStart runs. Each set of scripts has its own: the map's and the mode's don't share one, and
|
|
1045
|
+
* each PC's scripts have their own. For values about one player that last the match, use
|
|
1046
|
+
* player.data.
|
|
1047
|
+
*/
|
|
1048
|
+
declare const store: Store;
|
|
1049
|
+
|
|
1050
|
+
/**
|
|
1051
|
+
* Writes a line to the game's log on the PC the script runs on: the host's for scripts on the host,
|
|
1052
|
+
* that player's own for client/ scripts. The log is the console, and the log file in the logs folder
|
|
1053
|
+
* beside the game's settings. Each line starts "map script:" or "mode script:", then the values
|
|
1054
|
+
* joined by spaces, objects as JSON. At most 20 lines a second; more are dropped. Each line is cut
|
|
1055
|
+
* at 200 characters.
|
|
1056
|
+
*/
|
|
1057
|
+
declare function log(...values: unknown[]): void;
|