Skip to content
Ben Bartlett edited this page Apr 27, 2018 · 1 revision

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.

Basic task components

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

Using tasks

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();

Determining task validity

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.)

Prototasks

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.

Target lookup

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.

Parents and manifests

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.