character(), items(), itemCount() and jobLevel(), which tell a script its character's level, kamas, energy, life, pods, whether it's in a fight, its items and its jobs, with when each one is known and every error.
asterobot:character tells your script what the game has said about its character: level, kamas, energy, life, how full its bags are, whether it's in a fight, its items and its job levels. Use it to decide what to do next, such as going to the bank when the bags are nearly full or resting when life is low.
import { character, items, itemCount, jobLevel } from "asterobot:character";
These are the module's only exports. There's no character object grouping them.
| Export | Returns | What it gives you |
|---|---|---|
character() |
An object, right away | Level, kamas, energy, life, pods, and whether a fight is under way |
items() |
An array or undefined, right away |
Every stack the character has, worn or in its bags |
itemCount() |
A number or undefined, right away |
How many of an item the character has |
jobLevel() |
A number or undefined, right away |
The level of one of its jobs |
None of the functions returns a promise, and none of them changes anything in the game.
Where the values come from
Asterobot follows the character itself, for the whole game session, from the messages the server sends: the character's selection, its characteristics, its inventory and the weight of its bags, its job list, and when it enters or leaves a fight. So a script started or reloaded in the middle of a session reads the character as it is, not only what it saw since it started.
A value the game hasn't sent yet is missing, never guessed. character() leaves the property out, and items(), itemCount() and jobLevel() return undefined. A missing value is never 0 or null, so a script can always tell "zero" from "not known yet".
Every call asks again and returns a new value. Nothing updates by itself: read it again when you need it.
character()
character() returns an object with the properties below. Each one is a number, except inFight, and each one is absent until the game has sent it.
| Property | Type | Value |
|---|---|---|
level |
number | The character's level |
kamas |
number | The kamas it carries, not those in its bank |
energy |
number | Its energy points |
life |
number | Its life points. See Life. |
maxLife |
number | The most life points it can have, erosion taken off |
weight |
number | What its bags weigh, in pods |
maxWeight |
number | The most its bags can weigh, in pods |
inFight |
boolean | true while a fight is under way, false otherwise |
import { botInfo, botWarn } from "asterobot:bot";
import { character } from "asterobot:character";
const { weight, maxWeight, life, maxLife } = character();
if (weight !== undefined && maxWeight) {
botInfo(`Bags: ${Math.round((100 * weight) / maxWeight)}%`);
}
if (life !== undefined && maxLife && life < maxLife / 2) {
botWarn("Below half life");
}
For a character carrying 98 pods out of 1075 with full life, the console shows Bags: 9%.
The object is the script's own: changing it changes nothing, neither in Asterobot nor in the next call's answer.
Life
life and maxLife come from the character's characteristics, which the server sends as the character enters the world and later on. Asterobot works them out the way the Dofus client's character sheet does: the health points of the character's level and its vitality make the full amount, erosion takes the maximum down, and the life lost takes life down.
Between two of these messages, life follows the regeneration the way the Dofus client counts it. LifePointsRegenBeginEvent starts it, at one life point every regenRate tenths of a second, and a new rate, as the character sits down or stands up, goes on from there. UpdateLifePointsEvent stops it. life never goes past maxLife. The damage the character takes during a fight isn't followed: life is the last value until the next characteristics.
Pods
weight and maxWeight come from InventoryWeightEvent, which the server sends with both numbers whenever what the character carries changes. They're up to date as long as the session lasts. weight can be above maxWeight: the character is then overloaded.
Fights
inFight becomes true when the server switches the character into a fight, and false again when it switches it back to the world. Both switches come with ContextCreationEvent. It's false from the moment the character is selected, so a character that has entered the world and hasn't fought yet reads false, not "not known".
travel() waits for the end of a fight by watching the same switch.
items()
items() returns every stack of items the character has, worn or in its bags, sorted by uid, or undefined until the inventory is known. Each call returns a new array.
| Property | Type | Value |
|---|---|---|
uid |
number | The stack's own id, which the requests about it name, such as ObjectUseRequest and ObjectSetPositionRequest |
itemId |
number | The item's id, a key of the game data's items table |
quantity |
number | How many the stack holds |
position |
number | Where the character wears it: 0 amulet, 1 weapon, 2 and 4 rings, 3 belt, 5 boots, 6 hat, 7 cape, 8 pet, 9 to 14 the Dofus, 15 shield. 63 for the bags |
The list follows what the server says: stacks gained, used up or thrown away, moved in or out of a slot, and their quantities.
import { items } from "asterobot:character";
import { send } from "asterobot:protocol";
// 468 is Incarnam Bread.
const bread = items()?.find((stack) => stack.itemId === 468 && stack.position === 63);
if (bread) await send("ObjectUseRequest", { objectUid: bread.uid });
itemCount()
itemCount(itemId) returns how many of an item the character has, worn or in its bags, or undefined until the inventory is known.
| Parameter | Type | Description |
|---|---|---|
itemId |
number | The item's id: a key of the game data's items table, as search() returns it |
import { botInfo } from "asterobot:bot";
import { itemCount } from "asterobot:character";
// 303 is Ash Wood.
const ash = itemCount(303);
if (ash !== undefined) botInfo(`Ash Wood: ${ash}`);
An item the character has none of gives 0. It follows the updates the server sends, so a stack gained, used up or that grows or shrinks is counted at once.
Note
Until the server sends the whole inventory again, which it does when the character enters the world, two changes aren't seen. An item the character gains in a new stack during the session, such as the first piece of a resource it didn't carry, isn't counted. And a stack it loses whole, such as one it puts entirely in the bank, sells or uses up, is still counted at its last quantity. The server adds and removes a stack with messages Asterobot doesn't read.
jobLevel()
jobLevel(jobId) returns the level of one of the character's jobs, 0 for a job it doesn't have, or undefined until the job list is known.
| Parameter | Type | Description |
|---|---|---|
jobId |
number | The job's id: a key of the game data's jobs table, such as 2 for Lumberjack or 24 for Miner |
import { botInfo } from "asterobot:bot";
import { jobLevel } from "asterobot:character";
const lumberjack = jobLevel(2);
if (lumberjack === 0) botInfo("This character isn't a lumberjack.");
When the values are known
The server sends most of these values as the character enters the world, before it's placed on its first map:
| Value | Known from |
|---|---|
level, inFight |
The character's selection |
kamas, items(), itemCount() |
The inventory, which follows the selection |
weight, maxWeight |
The weight of the bags, sent with the inventory |
jobLevel() |
The job list |
energy, life, maxLife, and kamas again |
The characteristics sent as the character enters the world |
In a recorded world entry, every value was known before the character was placed on its first map.
Before the selection, character() is empty, except for a brief moment: the server sends the character's characteristics right before selecting it, and the selection then forgets them. In that recording, they gave the character 0 life and 0 energy, and the ones sent a moment later gave it full life and 10000 energy. So don't decide anything from character() until level is there.
Values last as long as the game connection. They survive the script being stopped and played again, and they're forgotten when the bot connects again, until the server sends them for the new session.
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). There's no character then: character() returns an empty object, and items(), itemCount() and jobLevel() return undefined, whatever you pass them. None of them throws, so importing asterobot:character at the top of a file is always safe.
Errors
| Error | Type | Cause |
|---|---|---|
character.itemCount itemId must be an integer item id |
TypeError |
itemId isn't a whole number from -2147483648 to 2147483647, or isn't a number at all, such as a string or a BigInt |
character.jobLevel jobId must be an integer job id |
TypeError |
The same for jobId |
String(error) gives TypeError: followed by the text. character() never throws.
The Dofus protocol reference describes the messages these values come from, if you'd rather follow one yourself.