What you will complete in this lesson
Start with one Creep that already carries Energy. You will make it walk to a named Spawn, transfer its Energy, and then connect that delivery step to the harvesting loop from the previous lesson.
Finished loop: Source → Creep Store → Spawn → back to the Source.
This lesson controls one named Creep, the first active Source it can find, and one named Spawn. Extension priorities and multi-Creep logistics come later.
Before you run the delivery code
Complete the previous Energy harvesting lesson first. For the one-way delivery test, the Creep needs CARRY and MOVE, must have finished spawning, and must already carry some Energy. The complete round trip also needs an active WORK part so the Creep can harvest again after delivery.
Find your real object names in the Console:
Object.keys(Game.creeps);
Object.keys(Game.spawns);
The examples below use Harvester1 and Spawn1. Replace both names exactly; Screeps names are case-sensitive.
Make one Creep deliver Energy
This is the smallest useful delivery loop. It tries transfer() first and only moves when the Spawn is out of range:
const CREEP_NAME = 'Harvester1';
const SPAWN_NAME = 'Spawn1';
module.exports.loop = function () {
const creep = Game.creeps[CREEP_NAME];
const spawn = Game.spawns[SPAWN_NAME];
if (!creep || !spawn || creep.spawning) return;
const transferResult = creep.transfer(
spawn,
RESOURCE_ENERGY
);
if (transferResult === ERR_NOT_IN_RANGE) {
creep.moveTo(spawn);
}
};
transfer() moves resources from the Creep to the target. The Spawn must be adjacent to the Creep, so ERR_NOT_IN_RANGE means “move closer and retry on a later tick.”
If the call returns OK, the transfer was scheduled successfully. When you need to confirm the processed result, inspect the Creep and Spawn Stores on a later tick.
Keep delivery mode until the Creep is empty
A repeating worker needs to remember whether it is currently harvesting or delivering. If you switch direction whenever the Creep merely has some free capacity, a partial unload can make it leave the Spawn while it still carries Energy.
Use one boolean in Creep Memory:
const usedEnergy =
creep.store.getUsedCapacity(RESOURCE_ENERGY) ?? 0;
const freeEnergyCapacity =
creep.store.getFreeCapacity(RESOURCE_ENERGY) ?? 0;
if (usedEnergy === 0) {
creep.memory.delivering = false;
} else if (freeEnergyCapacity === 0) {
creep.memory.delivering = true;
}
The rule is:
- empty Store → harvest;
- full Store → deliver;
- partially full Store → keep the previous mode.
Once delivery starts, the Creep stays in delivery mode until its Energy reaches zero.
Run the first complete Energy round trip
The following beginner version combines the harvest and delivery phases. It waits when the Spawn has no free Energy capacity instead of abandoning delivery mode.
State impact: it calls harvest(), transfer(), and moveTo(), and writes creep.memory.delivering.
const CREEP_NAME = 'Harvester1';
const SPAWN_NAME = 'Spawn1';
module.exports.loop = function () {
const creep = Game.creeps[CREEP_NAME];
const spawn = Game.spawns[SPAWN_NAME];
if (!creep || !spawn || creep.spawning) return;
const usedEnergy =
creep.store.getUsedCapacity(RESOURCE_ENERGY) ?? 0;
const freeEnergy =
creep.store.getFreeCapacity(RESOURCE_ENERGY) ?? 0;
if (usedEnergy === 0) {
creep.memory.delivering = false;
} else if (freeEnergy === 0) {
creep.memory.delivering = true;
}
if (creep.memory.delivering) {
const spawnFreeEnergy =
spawn.store.getFreeCapacity(RESOURCE_ENERGY) ?? 0;
if (spawnFreeEnergy === 0) return;
const transferResult = creep.transfer(
spawn,
RESOURCE_ENERGY
);
if (transferResult === ERR_NOT_IN_RANGE) {
creep.moveTo(spawn, { reusePath: 5 });
}
return;
}
const source =
creep.pos.findClosestByPath(FIND_SOURCES_ACTIVE);
if (!source) return;
const harvestResult = creep.harvest(source);
if (harvestResult === ERR_NOT_IN_RANGE) {
creep.moveTo(source, { reusePath: 5 });
}
};
This loop deliberately uses the simplest beginner phase boundary: harvest until the Energy Store is full, then deliver until it is empty. The previous harvesting lesson explains the optional larger-body capacity guard for workers whose next Source harvest batch may be larger than their remaining Store space.
What the round trip looks like across ticks
| Start-of-tick state | Mode | What the code does |
|---|---|---|
| The Creep has free Energy capacity. | Harvest | Find an active Source, harvest when adjacent, or move toward it. |
| The Creep starts a tick with no free Energy capacity. | Deliver | Set creep.memory.delivering = true. |
| The Spawn is out of range. | Deliver | transfer() returns ERR_NOT_IN_RANGE, then the Creep moves toward the Spawn. |
| The Creep is beside a Spawn with free Energy capacity. | Deliver | transfer() can return OK; verify the Store change later if needed. |
| The Spawn is full. | Deliver | The Creep waits and keeps its delivery state. |
| The Creep starts a tick with zero Energy. | Harvest | Set delivering = false and return to a Source. |
Four transfer results to understand first
| Return code | What it means | What to do |
|---|---|---|
OK | The transfer was scheduled successfully. | Continue the loop; inspect later Store state when you need proof of the processed result. |
ERR_NOT_IN_RANGE | The Spawn is too far away. | Move toward the Spawn and retry on a later tick. |
ERR_FULL | The target cannot receive more of that resource. | Check spawn.store.getFreeCapacity(RESOURCE_ENERGY). |
ERR_NOT_ENOUGH_RESOURCES | The Creep does not have the requested resource amount. | Re-read the Creep Store before retrying. |
If another code appears, use the English Screeps return-code reference and keep the exact result instead of replacing it with a generic success/failure boolean.
Confirm that delivery actually happened
The value returned by transfer() describes the current action request. OK means the operation was scheduled successfully; it is not a same-line receipt for the later processed Store values.
For this lesson, the practical check is simple: after a successful delivery tick, inspect a later tick and confirm that the Creep carries less Energy and the Spawn stores more Energy. Other Creeps can change the Spawn at the same time, so those Store values prove the observed state change, not unique causality.
Fix the common beginner problems
The Creep or Spawn is not found
Run Object.keys(Game.creeps) and Object.keys(Game.spawns) again. Replace both example names exactly, including capitalization.
The Creep waits beside the Spawn
Check spawn.store.getFreeCapacity(RESOURCE_ENERGY). If it is zero, the Spawn is full; the worker should stay in delivery mode and wait rather than treating this as a movement failure.
The Creep turns back to the Source too early
Do not set delivering = false merely because the Creep has free capacity after a partial unload. Switch back to harvesting only when usedEnergy === 0.
A larger worker reaches the Source with only a little free capacity
Keep this delivery lesson simple and apply the larger-body capacity hardening from the harvesting lesson. That Source-specific boundary belongs to the acquisition phase rather than the delivery phase.
Completion check
You have completed this lesson when you can:
- replace the example Creep and Spawn names with real objects;
- explain that
transfer()moves Energy from the Creep to the Spawn; - handle
ERR_NOT_IN_RANGEby moving toward the Spawn; - recognize
OKas a scheduled action rather than same-line proof of the processed amount; - keep
creep.memory.deliveringtrue while the Creep still carries Energy; - confirm a later decrease in Creep Energy and increase in Spawn Energy;
- watch the worker return to harvesting only after it becomes empty.
Continue to Creep body parts
Your first worker can now complete a basic Energy round trip. The next lesson explains why missing or damaged body parts can stop harvesting, carrying, or movement.
Understand WORK, CARRY, and MOVE →
Return to the English beginner roadmap to review the complete twelve-lesson sequence.