RESOURCES · BOOST TARGET IDENTITY

How to Use StructureLab.boostCreep() in Screeps

CURATED PATH

These links are maintained for a concrete prerequisite, failure mode, debugging step, or next lesson instead of generic topic similarity.

Market / Industry

Recommended next steps

Prepare the correct reaction compound firstUpstream productionTrace boost minerals to their sourceResource sourceConfirm the body parts being boostedPrerequisite concept
Verification statusChinese source article: Reviewed in full · Official documentation: Checked August 14, 2026 — StructureLab.boostCreep(), BOOSTS, LAB_BOOST_MINERAL, LAB_BOOST_ENERGY, bodyPartsCount, part order and return codes · Official implementation source: Checked current screeps/engine boostCreep validation and processor — engine eligibility does not require part.hits > 0; the Lab is ownership-gated, target ownership is not an API precondition, and processing continues only while per-part Lab resources remain

VERIFICATION

Evidence and test status

Chinese source article
Reviewed in full
Official documentation
Checked August 14, 2026 — StructureLab.boostCreep(), BOOSTS, LAB_BOOST_MINERAL, LAB_BOOST_ENERGY, bodyPartsCount, part order and return codes
Official implementation source
Checked current screeps/engine boostCreep validation and processor — engine eligibility does not require part.hits > 0; the Lab is ownership-gated, target ownership is not an API precondition, and processing continues only while per-part Lab resources remain
Static code review
Passed — destroyed-part eligibility, TOUGH/other part order, strict project budgets, partial-resource outcome, exact indexes, body identity and Lab Store deltas reviewed
Screeps Console test
Pending
Live multi-tick verification
Pending
Live boundary test
Pending — Live Creep replacement, part-order, exclusive-window and Lab Store delta test; no live destroyed-part or partial-resource boost trace was collected
Evidence level
Official documentation, official implementation source, repository review, JavaScript review and static lifecycle analysis only
Last editorial review
August 14, 2026

Quick answer: Use lab.boostCreep(creep, bodyPartsCount) when the target Creep is adjacent to the owned Lab, the Lab mineral can boost eligible parts on that Creep, and the Lab has enough mineral and Energy. Omit bodyPartsCount to boost all eligible parts; provide it to limit how many matching parts are boosted.

Return codes: OK means the operation was scheduled successfully. ERR_NOT_FOUND means the Lab mineral cannot boost any matching Creep body part; ERR_NOT_ENOUGH_RESOURCES means mineral or Energy is short; ERR_INVALID_TARGET means the target is not a valid Creep; ERR_NOT_IN_RANGE means it is too far away. Ownership and RCL failures return ERR_NOT_OWNER and ERR_RCL_NOT_ENOUGH.

Verify afterward: Do not turn OK into a body-change claim. Preserve the exact Creep ID and expected body-part indexes, then compare the resulting part.boost values and Lab Store deltas after the tick is processed.

Use this guide when

Use this workflow when a Lab should boost a known Creep and you need to prove which body entries changed. Two boundaries matter more than the usual “mineral + Energy + range” checklist: the current engine does not require an eligible body entry to have hits > 0, and an accepted request does not by itself prove every requested part was actually boosted.

Separate the API contract from stricter project policy

BoundaryWhat the current engine does
Lab ownershipThe Lab that calls boostCreep() must be yours.
Target ownershipThe API validates a Creep target, range, spawning state and eligibility; target ownership is not the engine's ownership precondition.
Eligible part damageEligibility is based on body type, boost mapping and whether the entry is already boosted. It does not filter on part.hits > 0.
Requested part countIf bodyPartsCount exceeds eligible entries, the call can return ERR_NOT_FOUND.
Resource precheckThe API requires enough mineral and Energy to process at least one eligible part; the processor then continues while resources remain.

For your own empire, requiring creep.my === true is usually a good safety policy. It is still project policy, not the same thing as the method's ownership check.

Count engine-eligible entries without a hits filter

function getBoostBodyType(mineralType) {
  if (typeof mineralType !== 'string') return null;

  for (const bodyType of BODYPARTS_ALL) {
    if (BOOSTS[bodyType]?.[mineralType]) {
      return bodyType;
    }
  }

  return null;
}

function getEligibleBoostParts(creep, bodyType, mineralType) {
  return creep.body
    .map((part, index) => ({ part, index }))
    .filter(({ part }) =>
      part.type === bodyType
      && !part.boost
      && BOOSTS[part.type]?.[mineralType]
    );
}

Do not add part.hits > 0 to this engine-eligibility count. A destroyed WORK, MOVE, TOUGH, or other matching body entry can still be selected by the current boost processor. “Active body part” is a different concept used by APIs such as getActiveBodyparts(); it is not the boost eligibility rule.

Predict the body indexes the processor will visit

function getExpectedBoostIndexes(
  eligible,
  bodyType,
  count
) {
  const ordered = bodyType === TOUGH
    ? [...eligible]
    : [...eligible].reverse();

  return ordered
    .slice(0, count)
    .map(item => item.index);
}

The current processor handles TOUGH from left to right and other body types from right to left. This matters when bodyPartsCount is smaller than the eligible set or when damaged body entries are mixed with intact ones.

Choose between API acceptance and an all-or-nothing project budget

The method's acceptance check and a production scheduler's desired guarantee are not identical. If your scheduler wants exactly N parts or nothing, preflight the full budget yourself:

function getStrictBoostBudget(bodyPartsCount) {
  if (
    !Number.isInteger(bodyPartsCount)
    || bodyPartsCount <= 0
  ) {
    return null;
  }

  return {
    mineral: LAB_BOOST_MINERAL * bodyPartsCount,
    energy: LAB_BOOST_ENERGY * bodyPartsCount
  };
}

This full-N requirement is a project safeguard. The current API validation only needs enough mineral and Energy for at least one part before accepting the intent. During processing, each boosted entry consumes one LAB_BOOST_MINERAL and one LAB_BOOST_ENERGY unit bundle until the requested count, eligible set, or available resources stop the loop.

Build a strict boost plan before changing state

function buildStrictBoostPlan(lab, creep, bodyPartsCount) {
  if (!lab || !creep || creep.spawning === true) {
    return { ready: false, reason: 'object-unavailable' };
  }

  const mineralType = lab.mineralType;
  const bodyType = getBoostBodyType(mineralType);

  if (!mineralType || !bodyType) {
    return { ready: false, reason: 'boost-mineral-invalid' };
  }

  const eligible = getEligibleBoostParts(
    creep,
    bodyType,
    mineralType
  );
  const count = bodyPartsCount == null
    ? eligible.length
    : bodyPartsCount;

  if (
    !Number.isInteger(count)
    || count <= 0
    || count > eligible.length
  ) {
    return {
      ready: false,
      reason: 'part-count-invalid',
      eligibleCount: eligible.length
    };
  }

  const budget = getStrictBoostBudget(count);

  if (
    lab.store.getUsedCapacity(mineralType) < budget.mineral
    || lab.store.getUsedCapacity(RESOURCE_ENERGY) < budget.energy
  ) {
    return {
      ready: false,
      reason: 'strict-budget-insufficient',
      mineralType,
      bodyType,
      ...budget
    };
  }

  if (!lab.pos.isNearTo(creep)) {
    return { ready: false, reason: 'creep-out-of-range' };
  }

  return {
    ready: true,
    reason: 'ready',
    mineralType,
    bodyType,
    partCount: count,
    expectedIndexes: getExpectedBoostIndexes(
      eligible,
      bodyType,
      count
    ),
    ...budget
  };
}

If you intentionally allow partial boosting, do not use this strict budget gate. Instead, model “accepted but fewer parts changed” as an explicit outcome.

Snapshot Creep identity, body state, and Lab resources before one call

function submitBoostRequest(request) {
  const lab = Game.getObjectById(request.labId);
  const creep = Game.getObjectById(request.creepId);

  if (
    !lab
    || lab.structureType !== STRUCTURE_LAB
    || lab.my !== true
    || lab.isActive() !== true
    || !creep
    || creep.spawning === true
  ) {
    return { status: 'object-unavailable' };
  }

  // Owning the target Creep is a project safety policy here.
  if (creep.my !== true) {
    return { status: 'target-not-owned-by-policy' };
  }

  const plan = buildStrictBoostPlan(
    lab,
    creep,
    request.bodyPartsCount
  );

  if (!plan.ready) {
    return { status: plan.reason };
  }

  request.enabled = false;
  request.snapshot = {
    labId: lab.id,
    creepId: creep.id,
    creepName: creep.name,
    bodyLength: creep.body.length,
    mineralType: plan.mineralType,
    bodyType: plan.bodyType,
    partCount: plan.partCount,
    expectedIndexes: plan.expectedIndexes,
    boostsBefore: creep.body.map(part => part.boost ?? null),
    mineralBefore:
      lab.store.getUsedCapacity(plan.mineralType),
    energyBefore:
      lab.store.getUsedCapacity(RESOURCE_ENERGY),
    exclusiveWindow: request.exclusiveWindow === true
  };

  const result = lab.boostCreep(creep, plan.partCount);

  request.result = result;
  request.resultAt = Game.time;
  request.status = result === OK
    ? 'accepted-pending-boost'
    : 'failed-review-required';

  return { status: request.status, result };
}

Using the Creep ID as well as the name avoids silently verifying a replacement Creep that reused the same name after the original died.

Verify exact body indexes and Lab Store deltas

function verifyBoost(request) {
  const snapshot = request?.snapshot;

  if (!snapshot || request.result !== OK) {
    return { status: 'submission-not-accepted' };
  }

  if (snapshot.exclusiveWindow !== true) {
    return { status: 'not-exclusive' };
  }

  const lab = Game.getObjectById(snapshot.labId);
  const creep = Game.getObjectById(snapshot.creepId);

  if (!lab || !creep) {
    return { status: 'object-unavailable' };
  }

  if (
    creep.name !== snapshot.creepName
    || creep.body.length !== snapshot.bodyLength
  ) {
    return { status: 'body-identity-mismatch' };
  }

  const changedIndexes = creep.body
    .map((part, index) => ({
      index,
      before: snapshot.boostsBefore[index],
      after: part.boost ?? null
    }))
    .filter(item => item.before !== item.after)
    .map(item => item.index);

  const mineralDelta =
    lab.store.getUsedCapacity(snapshot.mineralType)
      - snapshot.mineralBefore;
  const energyDelta =
    lab.store.getUsedCapacity(RESOURCE_ENERGY)
      - snapshot.energyBefore;
  const expectedMineralDelta =
    -LAB_BOOST_MINERAL * snapshot.partCount;
  const expectedEnergyDelta =
    -LAB_BOOST_ENERGY * snapshot.partCount;

  const exactIndexes =
    changedIndexes.length === snapshot.expectedIndexes.length
    && changedIndexes.every((index, position) =>
      index === snapshot.expectedIndexes[position]
    );

  if (
    exactIndexes
    && mineralDelta === expectedMineralDelta
    && energyDelta === expectedEnergyDelta
  ) {
    return {
      status: 'verified-exact-boost',
      changedIndexes,
      expectedIndexes: snapshot.expectedIndexes,
      mineralDelta,
      energyDelta
    };
  }

  return {
    status: changedIndexes.length > 0
      ? 'partial-or-ambiguous-boost'
      : 'pending-no-body-delta',
    changedIndexes,
    expectedIndexes: snapshot.expectedIndexes,
    mineralDelta,
    energyDelta
  };
}

In the strict workflow, OK plus a later partial body change is evidence that the all-or-nothing assumptions were violated by another actor, resource change, or unsupported timing assumption. In a deliberately permissive workflow, partial change can simply be the expected processor outcome when the Lab lacked full resources for the requested count.

Do not collapse partial change into success

StatusMeaning
accepted-pending-boostThe method returned OK; body and Store evidence is still pending.
body-identity-mismatchThe observed Creep is not the same body snapshot the request targeted.
partial-or-ambiguous-boostSome body entries changed, but not the exact indexes and resource signature expected by the strict plan.
verified-exact-boostExact targeted indexes changed and the Lab lost exactly the matching mineral and Energy budget.

Preserve the current return-code boundary

Documented results include ERR_NOT_OWNER, ERR_NOT_FOUND, ERR_NOT_ENOUGH_RESOURCES, ERR_INVALID_TARGET, ERR_NOT_IN_RANGE, and ERR_RCL_NOT_ENOUGH. In particular, ERR_NOT_FOUND covers a Lab mineral that cannot boost any eligible part on the target, including an excessive bodyPartsCount request against the eligible set.

Keep Lab loading, queues, and combat policy separate

This page owns one boost request and its evidence. Lab mineral loading, boost queues, boost selection strategy, body design, combat deployment, and unboosting should be separate systems. The verification layer should remain useful even when those policies change.

Official documentation and source

SOURCE AND SCOPE

Review the source, evidence, or next system

This English guide keeps the technical scope and verification boundaries of its Chinese source. The verification record shows which checks were completed and which runtime observations are still pending.