Interactions¶
Things players use by walking up to them, as the game's vending machines: every map object of some models (vending machines, payphones, ticket machines) or a spot. On foot, close to one and facing it, a player sees its prompt in the help box (top left); the enter/exit key (F/Enter) uses it, and the server decides what happens.
The game's own vending machines, payphones and so on do nothing in SAGL (their scripts were the game's mission script): add them here.
server.interactions.add(options)¶
For everyone, players joining later too.
| Option | Type | Description |
|---|---|---|
models |
number[] |
Every map object of these models (up to 16). |
at |
Vector3 |
Or one spot. |
radius |
number |
How close they must be (m), facing it. Default 1.5, at most 3. |
prompt |
string |
In the help box while they can use it. Game codes work: ~k~~VEHICLE_ENTER_EXIT~ is their key. gxt() text too. Left out: no help box (show your own with onReach). |
to |
Player[] |
Only these players can see and use it (others never hear of it). Default everyone. |
Returns an Interaction:
| Member | Description |
|---|---|
onUse(fn) |
fn(player, use) when a player uses it. use.model, use.position and use.heading (the way it faces, degrees) say which object (model 0: the spot). The server has checked they're there. Returns it. |
onReach(fn) |
fn(player, use, inReach) when it comes in a player's reach (true) and goes (false): to show a UI of your own instead of the prompt. Returns it. |
remove() |
Takes it away for everyone. |
Some of the game's models:
| Models | |
|---|---|
| Vending machines: drinks | 955, 1209, 1302, 1775 |
| Vending machines: snacks | 956, 1776, 1977 |
| Payphones | 1216 |
| Ticket machines | 1779 |
// A dollar for a drink, and some health back.
server.interactions.add({ models: [955, 1209, 1302, 1775], prompt: gxt("SLOT_05") }) // "Buy Drink: $1"
.onUse((player) => {
if (player.money < 1) return server.audio.playGame(1053, { at: player.position, to: [player] }); // the game's "no"
player.money -= 1;
player.health = Math.min(100, player.health + 30);
});
server.interactions.add({ models: [1216], prompt: "Press ~k~~VEHICLE_ENTER_EXIT~ to make a call" })
.onUse((player) => player.ui.open("ui/phone.rml"));
Your own prompt or UI¶
Leave out prompt and show your own when it's in reach, from the server:
const atm = server.interactions.add({ at: { x: 2412, y: -1240, z: 24 } });
const shown = new Map<Player, Drawn>();
atm.onReach((player, use, inReach) => {
if (inReach) shown.set(player, player.draw.text("~g~ATM~w~ - press ~y~F~w~", 0, -80, { anchor: "bottom", align: "center", outline: 1 }));
else shown.get(player)?.remove();
});
atm.onUse((player) => player.ui.open("ui/atm.rml"));
or from a client script, which can draw it at once: returning true from
sagl.interactions.onReach (see sagl) replaces the
prompt for any interaction.
Animations, freezing and sounds¶
Interactions usually come with an animation, maybe the player held still,
and a sound: see player.playAnim(),
player.frozen and server.audio. The
freeroam example's payphone (examples/freeroam/payphone.ts) rings from
where it is, and when answered plays the phone animations with the player
frozen:
player.frozen = true;
await player.playAnim("PED", "phone_in", { ms: 1200 });
player.playAnim("PED", "phone_talk", { loop: true });
player.subtitle("~y~Caller:~w~ Watch your back, homie.", 5000);
The game's own machines did all this in their scripts, and the freeroam
example's vending machines (examples/freeroam/vending.ts) do it as the
game's vending script did: the player slid in front of the machine (by its
use.heading; slideTo, not a
teleport) and held, its sound from them, its animations, then the
health:
const h = (use.heading * Math.PI) / 180; // 1 m in front of it, 0.2 m right
player.frozen = true;
await player.slideTo({ x: use.position.x + 0.2 * Math.cos(h) + Math.sin(h), y: use.position.y + 0.2 * Math.sin(h) - Math.cos(h), z: player.position.z }, use.heading);
server.audio.playMission(42600, { at: player }); // the machine's clunk (42601: snacks)
await player.playAnim("VENDING", "VEND_Use", { ms: 2600 });
await player.playAnim("VENDING", "VEND_Use_pt2", { ms: 400 });
await player.playAnim("VENDING", "VEND_Drink2_P", { ms: 3330 }); // snacks: VEND_Eat_P, 1670
player.health = Math.min(100, player.health + 30);
player.frozen = false;