A script that has the bot's chat module sell wheat for you, at a price from the package settings, with an ad in Trade, an answer giving the stock to whoever asks the price, and a whisper to every buyer, which the script hears.
This script has the bot's chat module sell wheat for you. It posts an ad in Trade every few minutes, answers whoever asks the price with what's left in the bags, and whispers every player who asks for wheat in Trade. The price comes from the package settings, so you change it on the bot's page while the script runs.
The script writes no chat logic of its own: it hands the module a chat profile and a price, and the module does the rest through its guard, waiting out each channel's cooldown and keeping to the game's limits. You need to know how to create a package and run it, as in Create a package.
The script
Create a package named wheat-seller, replace the contents of its index.js with this code, and save:
import { botInfo, botWarn } from "asterobot:bot";
import { itemCount } from "asterobot:character";
import { onAnswer, onChat, setDryRun, setProfiles, setVariable } from "asterobot:chat";
import { values, onChange } from "asterobot:parameters";
// 289 is Wheat.
const WHEAT = 289;
/** @type {BehaviorParameters} */
export const parameters = {
price: {
type: "int",
label: "Price of one wheat",
unit: "kamas",
default: 12,
min: 1,
},
dryRun: {
type: "bool",
label: "Dry run",
description: "Write the messages in the bot's console instead of sending them.",
default: true,
},
};
// The chat profile the bot talks from while the script runs: one ad, and
// one trigger for the buyers in Trade.
const shop = {
version: 1,
name: "Wheat seller",
// The script's own price wins over this one.
variables: { price: "12" },
ads: [
{
name: "Wheat in Trade",
channels: ["SALES"],
messages: ["{Selling|WTS} {item:289} at {price} k each, /w me", "{item:289} for sale, {price} k, /w {name}"],
every: { min: 180, max: 300 },
},
],
triggers: [
{
name: "buyer",
when: {
all: [
{ channel: { is: "SALES" } },
{ "sender.myBot": false },
{ text: { keywords: ["wtb", "buy"] } },
{ any: [{ text: { keywords: ["wheat"] } }, { items: { has: WHEAT } }] },
],
},
do: [{ whisper: ["{Hi|Hello} {sender}, I sell {item:289} at {price} k each"] }, { script: true }],
},
],
};
export default async function behavior() {
setVariable("price", values.price);
setDryRun(values.dryRun);
setProfiles([shop]);
onChange(({ name }) => {
if (name === "price") setVariable("price", values.price);
if (name === "dryRun") setDryRun(values.dryRun);
});
// Asked first about each private message the bot gets. A price question
// gets the stock too; anything else is left to the profiles' replies.
onAnswer(({ kind, line }) => {
if (kind !== "reply" || !/\b(price|how much)\b/i.test(line.content)) return;
const left = itemCount(WHEAT);
if (left === undefined) return;
if (left === 0) return "Sorry {sender}, no wheat left for now";
return `{Hi|Hello} {sender}, ${left} {item:289} left, {price} k each`;
});
onChat((event) => {
if (event.type === "trigger" && event.name === "buyer") {
botInfo(`Buyer in Trade: ${event.line.senderName}: ${event.line.content}`);
}
if (event.type === "soldOut") botWarn("Out of wheat: the ad waits for more");
});
}
How it works
The profile comes from the script
setProfiles([shop]) gives the bot the script's own profile, in place of the ones you picked on its Chat tab, for as long as the script runs. It's an object in the chat profile format, which Asterobot checks as it checks a saved profile: a mistake throws a TypeError naming the field. When the script stops, the bot goes back to your profiles.
The ad links the wheat with {item:289}, as the game links an item, from the character's inventory. While the character has none, the ad waits, and the Chat tab says why. {Selling|WTS} picks one wording at random each time, and the ad says one of its two messages at random, never the same twice in a row.
The price is a variable
The messages read {price}, which setVariable() sets from the package setting. When you apply a new price on the bot's page, onChange() sets the variable again, and the next message says it. The profile, the ad's counts and its next send stay as they were.
The script's variables win over the profile's, so the profile's own price is never said while the script runs. It's there because Asterobot checks the profile on its own, and warns in the console about a variable the profile reads but doesn't set.
The trigger
The trigger fires on a line said in Trade, by a player who isn't one of your bots, with the word wtb or buy, and either the word wheat or a link to wheat. all and any combine the tests as in a fight rule. Keywords are whole words, capitals and accents ignored, so WTB Wheat fires it and wheatgrass doesn't.
Its actions run in order. The whisper waits the time a person would take to read the line and type the answer, and {sender} names who said the line. Then script: true tells the script: onChat() gets { type: "trigger", name: "buyer", line }. A player fires it at most once an hour, the default.
The answer
onAnswer() is asked about each private message before the profile's reply rules. A text answers: the bot whispers it back after the reading and typing time, filled in like any message, so {sender}, {price} and the item link work. return with nothing leaves the message to the reply rules, and this profile has none, so the bot says nothing.
itemCount() is undefined until the game has sent the inventory. The handler then answers nothing rather than say a wrong number.
The dry run
The Dry run setting starts on: the bot writes every message in its console, such as Dry run: would say in Trade: ..., instead of sending it. Everything else runs as if they were sent, the ad's wait and the trigger's limit included. Turn it off once the messages read well.
Run it
Try it on a MITM bot whose character is in the game, with some wheat in its bags, as Your first bot sets up.
- On the bot's page, open the Chat tab and turn on Chat module. On a relayed session only your switch counts: a script can't turn the module on there. Leave Ads, Replies and Triggers on.
- In the editor, pick the bot and click Run.
- Back on the Chat tab, the tab says the running script sets the profile Wheat seller and the dry run, and the Ads section shows Wheat in Trade with its next send.
- Open the Console. Within a few seconds, a line starting
Dry run: would say in Trade:writes the ad.
The replies and the triggers answer neither your own bots nor yourself, so try them with a friend, or with an account this Asterobot has never played:
- Have them whisper the bot
price?. A few seconds later,Dry run: would say totheir name writes the answer, with the stock. - Have them say
wtb wheatin Trade. The console saysTrigger buyer:with their name and line, then, a few seconds later, the whisper, then the script'sBuyer in Trade:line. - On the bot's Settings tab, under Package settings, change Price of one wheat and click Apply. The next ad says the new price.
- Turn off Dry run and click Apply. The bot now sends for real.
Click Stop: the Chat tab goes back to your own profiles, and the ad stops.
Ideas to take it further
- Sell more than wheat. Make the price a
mapsetting of item ids to prices, set one variable per item, and give the profile an ad per item. - Open hours. Add
when: { flag: "open" }to the ad, and have the script callsetFlag("open")andsetFlag("open", false)when it decides the shop opens and closes. - Get notified. Add
{ raise: "buyer" }to the trigger's actions, and a rule on the Alarms page that takes thetrigger:buyerevent and notifies Asteroboard. - Ship the profile. Save the profile as
chatprofiles/wheat-seller.jsonin the package, as Package layout shows, and pass its name tosetProfiles(): people can then copy it and make it their own.
The asterobot:chat reference covers every function used here.