-
Notifications
You must be signed in to change notification settings - Fork 159
Tasks
Overmind's task system has been repackaged as a plugin and now has its own repository!
A Task
is an object you can hand to a creep that generalizes the concept of "do action X to thing Y until condition Z is met". Tasks persist between ticks, and using them can save a lot of convoluted and redundant code in creep logic. A Task
object contains the necessary logic for traveling to a target, performing an action to the target, and realizing when a task is no longer sensible to continue. Below, we'll cover the basic anatomy and usage of tasks.
Every task has the following basic properties (among others). Refer to the API reference for a full list of properties and methods.
property | type | description | example |
---|---|---|---|
name |
string |
Describes the action the task should do | "build" |
creep |
Creep |
The creep the task is assigned to | [Creep worker_0] |
target |
RoomObject * |
The target to perform an action on (*Exceptions: TaskDrop , TaskGoTo , TaskGoToRoom ) |
[ConstructionSite <id>] |
targetPos |
RoomPosition |
The position of the target, accessible even if the target is not visible | [RoomPosition x y name] |
settings |
Object |
Settings common to a given type of task (e.g. range of an action); shouldn't be modified on a per-instance basis | {targetRange: 3, workOffRoad: true} |
options |
Object |
Options configurable for a specific instance of a task (e.g. don't invalidate task if target visibility is lost) | {blind: true, moveOptions: <options>} |
data |
Object |
Data pertaining to a task instance | {resourceType: "ghodium"} |
parent |
Task|null |
Task to revert to once the current task is finished | null |
Many Screeps bots use a decision tree every tick to determine what a creep should be doing. Tasks streamline this process into two separate processes: task assignment and task execution. Since tasks are persistent, you only need to run the decision tree when a creep finishes what it is doing, rather than on every tick for every creep. Although creep logic built with tasks can get very detailed, almost every role follows the same general structure:
if (creep.isIdle) {
// Task assignment logic
creep.task = newTask;
}
// Execute the assigned task
creep.run();
Every time a task is queried with creep.hasValidTask
or creep.isIdle
(these are complements of each other), a two-part validity check is run. Task.isValidTask()
determines whether or not the task itself is still sensible to continue (for example, a repair task is valid only if the creep it is assigned to has energy > 0). Task.isValidTarget()
determines whether or not the target is still valid (e.g. a repair target is valid until it has full hits). If a task is determined to be invalid, the creep's new task is set to the task's parent, which is null
by default. (See "Parents and manifests" section below.)
All tasks are constructed with a minimum of a name and a target. Tasks are serialized via Task.proto
into lightweight prototask
objects stored in creep.memory.task
. When creep.task
is accessed, if the creep does not already have a Task
object from the current tick stored in creep._task
, it instantiates one from the prototask. Storing prototasks in creep memory also allows you to easily inspect what any creep is doing at a given time.
creep-tasks
adds a Game.TargetCache
object, which is continuously updated to contain the targeting information of all tasks assigned to a creep. By using the included RoomObject.targetedBy
property, you can get a list of all creeps currently targeting an object (or targeting an object in a future task - see below); this can be helpful in many cases, such as determining the least saturated source to harvest from, as demonstrated in the example bot's harvester role.
In some cases it may be helpful to chain tasks together, such as telling a creep to get a resource from storage and then to deposit it in a structure. This can be done either by setting task.parent = newTask
, which queues a newTask
for execution, or by using task.fork(newTask)
, which suspends the current task until newTask
is completed. (Note that using creep.task.fork(newTask)
is fine, but when trying to fork a task which has not yet been assigned to a creep, you will need to use task = task.fork(newTask)
.) The example bot demonstrates using parents in the patroller role.
If you want to access a list of all tasks a creep is currently assigned, you can use Task.manifest
to recursively generate a list of all assigned tasks. Similarly, Task.targetManifest
generates a list of all queued targets, and Task.targetPosManifest
generates a list of all queued target positions (even if targets are not visible). These last two methods are slightly more efficient than using _.map(Task.manifest, task => task.target)
, since the full task objects are not instantiated.