Aller au contenu
Afficher dans l'application

Une meilleure façon de naviguer. En savoir plus.

Asterobot

Une application plein écran sur votre écran d'accueil avec notifications push, badges et plus encore.

Pour installer cette application sur iOS et iPadOS
  1. Appuyez sur Icône de partage dans Safari
  2. Faites défiler le menu et appuyez sur Ajouter à l'écran d'accueil.
  3. Appuyez sur Ajouter dans le coin supérieur droit.
Pour installer cette application sur Android
  1. Appuyez sur le menu à trois points (⋮) dans le coin supérieur droit du navigateur.
  2. Appuyez sur Ajouter à l'écran d'accueil ou Installer l'application.
  3. Confirmez en appuyant sur Installer.

asterobot:chat

Say things in the game chat from a script through the bot's chat guard, which waits out a channel's cooldown and keeps to the server's limits, with templates that pick random wording, fill in the character's level, map or kamas, and link items from its inventory; switch the bot's chat module and pick its chat profiles while the script runs; answer the private messages the bot gets, and hear what the module does.

asterobot:chat lets your script say things in the game chat through the bot's chat module, and set the module while it runs. Every message the bot sends goes through the module's guard, which keeps to the limits the game server sets and says: your script's messages, the ones typed in the bot's Console, the module's ads, replies and triggers' messages, and the alarms' lines.

import {
  say, whisper, pause, resume,
  setVariable, variables, setFlag, flags, setDryRun, dryRun,
  enable, disable, enabled, setParts, parts, setProfiles, profiles,
  onChat, offChat, onAnswer, offAnswer,
} from "asterobot:chat";

These are the module's only exports. There's no chat object grouping them.

Export Returns What it does
say() A promise Say a message in a channel
whisper() A promise Whisper a message to a character
pause(), resume() Nothing Stop sending for a while, or start again
setVariable(), variables() Nothing, an object Set or read your own {variables}
setFlag(), flags() Nothing, an array Set the flags the profiles' conditions test
setDryRun(), dryRun() Nothing, a boolean Write messages to the console instead of sending them
enable(), disable(), enabled() Nothing, a boolean Switch the chat module on or off
setParts(), parts() Nothing, an object Switch parts of the module, such as its ads
setProfiles(), profiles() Nothing, an array Pick the chat profiles the bot talks from
onChat(), offChat() A subscription, nothing Hear what the module does
onAnswer(), offAnswer() A subscription, nothing Answer the private messages the bot gets

say() and whisper() return a promise. The other functions are synchronous.

The guard

The guard is the bot's one queue for chat messages. It sends one message at a time, and waits for the server's answer before the next: the server saying the message back, a refusal, or 5 seconds without an answer, which count as sent.

Rule What happens
A channel's cooldown When the server answers "Use of this channel is restricted. You will be able to post again in 37 seconds.", the guard waits 37 seconds and 1 more, then sends the message once more. Messages to other channels go on meanwhile. Refused a second time, the message is dropped.
At most 6 messages a minute Counted for the bot, whispers included, 6 unless the bot's Chat tab sets another number, from 1 to 30. A message past the limit waits its turn.
"Too much spam!" Nothing is sent for 5 minutes, then 10, 20, 40, and 60 at most for each warning after it. An hour without a warning starts over at 5.
A mute When a member of staff mutes the character, nothing is sent until the mute ends, plus a minute. The game's "is letting you speak again" ends it at once.
A channel that refuses the character No guild, no group, a level or a subscription short, a beginners' channel, prison: your messages to that channel are refused for the rest of the game session. "This channel cannot be used on this map" lasts until the next map.
Items that can't be shown When the channel refuses item links, the message goes again with each item written as [its name], and so do the next messages to that channel this session.

The person's messages, typed in the Console, go first. A pause, a back-off or the limit doesn't hold them back: only a channel's cooldown does. The alarms' lines come next, and a pause doesn't hold them back either. Then come the answers to commands, the replies and the triggers' messages, and last your script's messages and the ads.

say() and whisper()

say(channel, text) says a message in a channel. whisper(name, text) whispers it to the character of that name.

Argument What it is
channel A channel as the protocol names it: "SALES" is Trade, "SEEK" Recruitment, "GLOBAL" General, "GUILD", "PARTY" the group, "ALLIANCE"...
name The name of the character to whisper
text A template

The promise resolves once the server took the message, with { dryRun: false }, or { dryRun: true } in a dry run. It rejects with an Error whose reason says why the message wasn't sent:

reason Why
"notInGame" The character isn't in the game
"paused" Sending is paused
"spam" The guard is backing off after "Too much spam!"
"muted" A member of staff muted the character
"cooldown" The channel was still in its cooldown when the message went once more
"refused" The server refused the message or its channel, or the whisper's recipient isn't connected
"tooLong" The message is past the game's 256 characters or 16 item links
"template" The template can't be read
"missingVariable" A variable has no value
"missingItem" An item to link isn't in the inventory
"stopped" The script stopped before the message went
"sendFailed" The message didn't reach the server
import { say, setVariable } from "asterobot:chat";
import { botWarn } from "asterobot:bot";

setVariable("price", 12);

try {
  await say("SALES", "{Selling|WTS} {item:289} at {price} k each, /w me");
} catch (error) {
  if (error.reason === "missingItem") botWarn("No more wheat to sell");
  else throw error;
}

When the script stops, its messages that are still waiting are dropped. A message already sent waits for its answer.

Templates

A template is the text of a message with parts that are filled in each time it is said.

Write Says
{Hi|Hello|Hey} One of the choices, at random each time. Choices can be nested, {Hi|Hello {there|you}}, and empty, {!|}.
{item:289} A link to that item, from the character's inventory, as the game makes one. An item in the bags is linked before a worn one.
{name} The character's name
{level} Its level
{server} Its server's name
{subarea}, {area} Where it is, in the bot's language
{position} A link to its map, as the game makes [4,-19] typed in its chat box: {{map,4,-19,1}} in the text, which the game shows as [4,-19]
{kamas} Its kamas
{pods} Its pods, used and maximum, such as 1200/3400
{time} The computer's time, HH:MM
{anything else} A variable you set with setVariable()

Nothing broken goes out: a message isn't sent when one of its variables has no value, an item it links isn't in the inventory, or, filled in, it's longer than the game's 256 characters or links more than 16 items. The length counts each item link as the game's code for it, which is longer than the item's name, so that the server never finds the message too long.

A template can't be read when a { has no } or the reverse, when {} is empty, when a part like {a {name}} nests without a |, or when it has a colon that isn't an item link, such as {a:b}.

pause() and resume()

pause(seconds) stops the module's and your scripts' messages for that many seconds. Without seconds, it lasts until resume(). The messages waiting are dropped with "paused", and so are the ones said while it lasts. The person's messages from the Console still go.

A pause outlives the script that set it, like a button the person pressed.

import { pause } from "asterobot:chat";

// Nothing more for ten minutes.
pause(600);

setVariable() and variables()

setVariable(name, value) sets a variable your messages read as {name}. A number or a boolean is written as text; null or undefined deletes the variable. variables() returns your variables, as a copy.

The character's own variables, such as {name} or {level}, win over yours of the same name, and yours win over the bot's chat profiles'. Your variables last until the script stops, or until a newer script, after a reload, sets its own. The module's ads read them too.

setFlag() and flags()

setFlag(name) sets a flag, which the flag test of the bot's chat profiles reads (Conditions); setFlag(name, false) clears it. flags() returns the names of the flags set. Your flags last until the script stops, or until a newer script sets its own.

import { setFlag } from "asterobot:chat";

// The profile's "shop open" ad runs from now on.
setFlag("shopOpen");

setDryRun() and dryRun()

setDryRun(true) writes the module's and your scripts' messages to the bot's console instead of sending them: Dry run: would say in Trade: Selling [Wheat] at 12 k each. Everything else goes on as if they were sent, the limit of 6 a minute included. The person's messages from the Console are always sent. dryRun() says whether a dry run is on.

The dry run lasts until the script stops, or until a newer script sets its own.

enable(), disable() and enabled()

enable() switches the bot's chat module on while the script runs, and disable() off: with the module off, the bot posts no ad, answers no private message, fires no trigger, obeys no command and leaves its status alone. enabled() says whether the module runs now. The switch the person saved on the Chat tab comes back when the script stops.

On a relayed session, only the person's switch counts: enable() and disable() change nothing there, and enabled() says what the person set.

setParts() and parts()

setParts(parts) switches the parts it names while the script runs, the others staying as they are: setParts({ ads: false }) keeps the module on but stops its ads. parts() returns every part, on or off: { ads, replies, triggers, commands, status }.

setProfiles() and profiles()

setProfiles(list) sets the bot's chat profiles while the script runs, in order, in place of the person's. Each item is the name of a profile, as the bot's Chat tab lists it, or a profile object in the chat profile format, which crosses into Asterobot as JSON.stringify() writes it and is checked as a saved profile is. profiles() returns the profiles in effect, as plain objects in that format, copies: changing one changes nothing until you pass it to setProfiles().

import { setProfiles, setVariable } from "asterobot:chat";

setVariable("price", 11);
setProfiles([
  "Sell wheat in Astrub",
  {
    version: 1,
    name: "Script ad",
    ads: [{ channels: ["SALES"], messages: ["{item:289} at {price} k"], every: { min: 300, max: 600 } }],
  },
]);

The ads of a new list start over: their sends counted from zero, their first send as soon as they can. Setting the same profiles again keeps their counts. A profile's warnings, such as a variable no profile sets, go to the bot's console as chat.setProfiles[1]: <warning>.

onChat() and offChat()

onChat(handler) has handler hear what the module does, in the order it happens, until offChat(subscription) or the end of the script. Each event is an object:

Field What it holds
type "sent": a line went, or was written to the console in a dry run. "replied": a reply went. "refused": a line wasn't sent. "stopped": an ad's stop ended it. "soldOut": an item an ad links ran out. "backoff": every line waits, after "Too much spam!" or a mute.
dryRun Whether the line was written to the console instead of sent
who Who said the line: "person", "alarm", "command", "reply", "trigger", "script" or "ad"
where In which channel, or to whom; for a stop or an item sold out, the ad
text The line
reason, detail Why a line wasn't sent, as say() rejects; which stop ended an ad; which item ran out; why every line waits

Each field without a value is left out. The handler only observes: what it returns is ignored, and it can be async. A handler that throws stops the script.

A trigger with the script action gives an event of its own when that action's turn comes, after the actions before it are done, { type: "trigger", name, line }: the trigger's name, and the line it fired on, { senderName, senderAccountId, senderCharacterId, content, channel }, the ids as BigInts. A trigger without that action fires without the script hearing it.

import { onChat, whisper } from "asterobot:chat";

onChat(async (event) => {
  if (event.type !== "trigger" || event.name !== "wtb") return;

  const wanted = event.line.content.match(/\d+/)?.[0] ?? "some";
  await whisper(event.line.senderName, `{Hi|Hello} ${event.line.senderName}, I can sell you ${wanted}`);
});
import { onChat } from "asterobot:chat";
import { botWarn } from "asterobot:bot";

onChat(({ type, where, detail }) => {
  if (type === "soldOut") botWarn(`${where}: ${detail} sold out, restocking`);
});

onAnswer() and offAnswer()

onAnswer(handler) has handler asked first about each private message the bot's replies get, until offAnswer(subscription) or the end of the script. It's asked with { kind: "reply", line }, line being the message: { senderName, senderAccountId, senderCharacterId, content, channel }, the ids as BigInts. It answers:

Answer What the bot does
A text Whispers it back, as a template where {sender} names who wrote, after the time a person would take to read and type it
{ skip: true } Says nothing
Nothing, null, undefined or an empty text The next handler is asked, then the profiles' reply rules decide

The handler can be async: the bot waits up to 30 seconds for its answer, the reading and typing time running meanwhile. Past that, or when it throws or answers something else, the reply rules decide and the console says so. Its answers aren't counted by the profiles' answers per player, so it can hold a conversation. It's never asked about a message from one of your own bots or from a member of staff.

It's also asked about a command a profile takes but doesn't know, with { kind: "command", line, command, args }: !sell 10 wheat from a trusted sender is command "sell", args ["10", "wheat"]. A text answers the sender; nothing leaves the command ignored.

import { onAnswer } from "asterobot:chat";
import { memory } from "asterobot:bot";

onAnswer(({ kind, line }) => {
  if (kind !== "reply" || !/price|prix/i.test(line.content)) return;

  return `{Hi|Hello} {sender}, ${memory.get("wheatPrice") ?? 12} k each`;
});

While Asterobot reads declarations

When Asterobot reads a package's settings, steps and conditions, it runs the top level of its modules without a bot (see Declarations). Every function of asterobot:chat then throws, or rejects for say() and whisper(), since there's no chat module to talk through.

Errors

These are thrown at once, or reject the promise of say() and whisper():

Error Type Cause
chat.say channel "<name>" isn't a channel: write it as the protocol does, "SALES" for Trade TypeError The channel name is unknown
chat: PRIVATE isn't a channel to say something in Error A whisper's channel, or one the game doesn't show: use whisper()
chat.say must be a string, chat.whisper must be a string, chat.whisper name must be a string TypeError An argument isn't a string
chat.pause seconds must be a positive number TypeError Seconds that are 0, negative, or not a number
chat.setVariable name must be a string TypeError The name isn't a string
chat.setVariable value must be a string, a number or a boolean TypeError An object, an array or a function as the value
chat.setFlag name must be a string TypeError The name isn't a string
chat.onChat handler must be callable, chat.onAnswer handler must be callable TypeError The handler isn't a function
maximum behavior handlers reached TypeError The script holds as many handlers as a script can
chat.setParts takes an object, { ads: false } TypeError The parts aren't an object
chat.setParts: chat: invalid settings: "<part>" isn't a part: write ads, replies, triggers, commands or status TypeError An unknown part
chat.setProfiles takes an array of profiles' names or profile objects TypeError The list isn't an array
chat.setProfiles[<i>] must be a profile's name or a profile object TypeError An item that is neither
chat.setProfiles[<i>]: chat: malformed profile: <field>: <why> TypeError A profile object Asterobot can't accept, naming the field
chat.setProfiles: chatprofiles: no profile has this name: "<name>" Error A name no profile has
chat.setProfiles: chat: malformed profile: <field>: <why> Error A saved profile, named in the list, that can't be used
chat.<function>: this bot has no chat module Error Asterobot is reading declarations

The bot's Console shows these lines:

Line Cause
Dry run: would say in Trade: <message> A message in a dry run
Waiting 38 s for the cooldown in Trade, then sending the line once more The server answered that the channel is in its cooldown
The server said "Too much spam!": nothing is sent for 5 minutes A spam warning
<moderator> muted the character for 15 minutes: nothing is sent until 21:40 A mute
The mute is lifted: lines are sent again The mute ended
Not said in Trade: <reason> A message typed in the Console, a reply or a command's answer that couldn't be sent
Not answered <sender>: <reason> A reply whose message can't be filled
Command !stop from <sender>: the script is stopped A command, and what the bot did
Trigger wtb: <sender> in Trade: <line> A trigger fired
Trigger wtb: whisper not done: <reason> One of a trigger's actions failed
Trigger wtb: the chat is paused for 600 s A trigger's pauseChat
Dry run: would invite <sender> to the party, Dry run: would ignore <sender>, Dry run: would play smiley 3 A trigger's action in a dry run
Couldn't ignore <sender>: the list is full The game refused a trigger's ignore
Status set to away by the chat profiles The status part set the character's status
The status changed elsewhere: the chat profiles leave it The status changed from the bot's header, the person's client or a script
Status not set: <reason>, Status not set back: <reason> The status part couldn't set the status, or take back the one before
The answer hook didn't answer <sender> within 30 s: left to the rules An onAnswer() handler took too long
chat answer hook failed: <error>: the reply rules decide, chat answer hook rejected: <error>: the reply rules decide An onAnswer() handler threw, or its promise rejected
chat answer hook answered something else than a text, { skip: true } or nothing: the reply rules decide An onAnswer() handler's answer of another kind

Compte

Navigation

Recherche

Recherche

Configurer les notifications push du navigateur

Chrome (Android)
  1. Appuyez sur l'icône de cadenas à côté de la barre d'adresse.
  2. Tap Autorisations → Notifications.
  3. Ajustez vos préférences.
Chrome (Desktop)
  1. Cliquez sur l'icône représentant un cadenas dans la barre d'adresse..
  2. Select Paramètres du site.
  3. Find Notifications et ajustez vos préférences.