SPAWNING · BODY BUDGET POLICY

Build a Dynamic Creep Body Without Spending Energy Blindly

CURATED PATH

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

Spawn

Recommended next steps

spawnCreep basicsPrimary API pathWhy room.energyAvailable gets stuckEnergy failureBody-part cost and capabilityDesign basis
Verification statusChinese source article: Reviewed in full · Official documentation: Checked against Room Energy, body-cost, body-limit, and spawning documentation · Technical correction: Minimum capability, target budget, emergency scaling, and Spawn submission are separate decisions

VERIFICATION

Evidence and test status

Chinese source article
Reviewed in full
Official documentation
Checked against Room Energy, body-cost, body-limit, and spawning documentation
Technical correction
Minimum capability, target budget, emergency scaling, and Spawn submission are separate decisions
JavaScript syntax
Passed by the editorial batch gate
Evidence level
Official documentation review, repository review, syntax checks, and static analysis only
Screeps Console test
Pending
Live multi-tick verification
Pending
Live replacement and emergency-spawn test
Pending
Last editorial review
July 31, 2026

Use this guide when

Use this page when one role needs a body that can scale with room Energy. The body planner should answer one question: what legal body can this Spawn afford under the current policy? It should not also decide role quotas, replacement timing, Spawn priority, or whether the room is in an emergency.

Use the spawnCreep() return-code guide when a finished body already exists but the Spawn rejects it.

Define minimum, target, and emergency plans

PlanPurposeEnergy rule
MinimumSmallest body that can perform the roleNever return a body below this capability
TargetNormal body for an established roomWait when current workers make waiting safe
EmergencyReduced body used to restore essential incomeScale from current energyAvailable

A dynamic body is not automatically an emergency body. Normal replacements may wait for the target budget, while a room with no income Creep may need the smallest useful body immediately.

Current Energy and capacity answer different questions

room.energyAvailable is the Energy currently loaded in Spawns and Extensions. room.energyCapacityAvailable is the maximum those structures can hold. Capacity does not prove that the target body is affordable now.

function chooseBodyBudget(room, policy) {
  if (!room || !policy) {
    return { status: 'input-missing', budget: 0 };
  }

  const targetBudget = Math.min(
    room.energyCapacityAvailable,
    policy.maximumEnergy
  );

  if (policy.emergency === true) {
    return {
      status: 'emergency-budget',
      budget: room.energyAvailable,
      targetBudget
    };
  }

  if (room.energyAvailable < policy.minimumEnergy) {
    return {
      status: 'minimum-not-affordable',
      budget: room.energyAvailable,
      targetBudget
    };
  }

  return {
    status: room.energyAvailable >= targetBudget
      ? 'target-affordable'
      : 'wait-or-scale',
    budget: Math.min(room.energyAvailable, targetBudget),
    targetBudget
  };
}

The returned status leaves the wait-or-spawn decision visible. A body function should not silently treat every partial refill as an emergency.

Validate the body parts and derive cost

const VALID_BODY_PARTS = new Set([
  MOVE,
  WORK,
  CARRY,
  ATTACK,
  RANGED_ATTACK,
  HEAL,
  TOUGH,
  CLAIM
]);

function getBodyCost(body) {
  if (
    !Array.isArray(body)
    || body.length < 1
    || body.some(part => !VALID_BODY_PARTS.has(part))
  ) {
    throw new TypeError('Invalid Creep body');
  }

  return body.reduce(
    (total, part) => total + BODYPART_COST[part],
    0
  );
}

Derive costs from BODYPART_COST. Hard-coded totals become easy to break when templates change.

Scale from a minimum body with complete repeat units

function buildScaledBody(input) {
  const {
    energyBudget,
    minimumBody,
    repeatUnit,
    maximumParts = 50,
    maximumEnergy = Infinity
  } = input;

  if (
    !Number.isFinite(energyBudget)
    || energyBudget < 0
    || !Array.isArray(minimumBody)
    || minimumBody.length < 1
    || !Array.isArray(repeatUnit)
    || repeatUnit.length < 1
    || !Number.isInteger(maximumParts)
    || maximumParts < 1
    || maximumParts > 50
    || (
      maximumEnergy !== Infinity
      && !Number.isFinite(maximumEnergy)
    )
    || maximumEnergy < 0
  ) {
    return {
      status: 'invalid-input',
      body: []
    };
  }

  const minimumCost = getBodyCost(minimumBody);
  const unitCost = getBodyCost(repeatUnit);
  const budget = Math.min(
    energyBudget,
    maximumEnergy
  );

  if (
    minimumBody.length > maximumParts
    || minimumCost > budget
  ) {
    return {
      status: 'minimum-not-affordable',
      body: [],
      minimumCost,
      budget
    };
  }

  const body = [...minimumBody];
  let bodyCost = minimumCost;
  let unitsAdded = 0;

  while (
    body.length + repeatUnit.length <= maximumParts
    && bodyCost + unitCost <= budget
  ) {
    body.push(...repeatUnit);
    bodyCost += unitCost;
    unitsAdded += 1;
  }

  return {
    status: bodyCost === budget
      ? 'budget-filled'
      : 'body-ready',
    body,
    bodyCost,
    budget,
    unitsAdded,
    unusedEnergy: budget - bodyCost,
    spawnTime: body.length * CREEP_SPAWN_TIME
  };
}

Only complete repeat units are appended. Leftover Energy is normal; spending every last unit is less important than preserving the role's body ratio and part ordering.

Keep the template specific to one role

function planWorkerBody(room, emergency) {
  const budgetResult = chooseBodyBudget(room, {
    emergency,
    minimumEnergy: 200,
    maximumEnergy: 1200
  });

  if (budgetResult.status === 'minimum-not-affordable') {
    return {
      status: budgetResult.status,
      body: []
    };
  }

  const plan = buildScaledBody({
    energyBudget: budgetResult.budget,
    minimumBody: [WORK, CARRY, MOVE],
    repeatUnit: [WORK, CARRY, MOVE],
    maximumParts: 18,
    maximumEnergy: 1200
  });

  return {
    ...plan,
    budgetStatus: budgetResult.status,
    targetBudget: budgetResult.targetBudget
  };
}

This is a general worker example, not a universal body. A fixed miner, road hauler, upgrader, reserver, healer, and attacker need different minimum capabilities, repeat units, movement ratios, caps, and part order.

Make the wait decision outside the builder

Spawn a reduced body when losing more time is more dangerous than losing efficiency. Wait for the target body when the existing workforce can keep the room stable until the refill completes. Record the reason as policy data such as income-collapse, replacement-safe-to-wait, or target-affordable; do not infer emergency status merely from low Energy.

Use the emergency recovery guide for room-collapse detection and duplicate Spawn prevention.

Validate and submit spawning separately

function submitBodyPlan(spawn, name, plan, memory) {
  if (!spawn || !plan || plan.body.length < 1) {
    return { status: 'plan-not-ready' };
  }

  const dryRunResult = spawn.spawnCreep(
    plan.body,
    name,
    { memory, dryRun: true }
  );

  if (dryRunResult !== OK) {
    return {
      status: 'dry-run-failed',
      dryRunResult,
      bodyCost: plan.bodyCost
    };
  }

  const spawnResult = spawn.spawnCreep(
    plan.body,
    name,
    { memory }
  );

  return {
    status: spawnResult === OK
      ? 'spawn-submitted'
      : 'spawn-failed-after-dry-run',
    dryRunResult,
    spawnResult,
    bodyCost: plan.bodyCost,
    spawnTime: plan.spawnTime
  };
}

OK means the Spawn accepted the request. The Creep still requires body.length × CREEP_SPAWN_TIME ticks to finish, so replacement lead time belongs in the scheduler rather than the body builder.

Body order and MOVE ratio remain policy

Two bodies with the same parts and cost can lose abilities in a different order when damaged. Repeating a unit is easy to inspect, but it is not automatically optimal. Also check how loaded non-MOVE parts generate fatigue on roads, plains, and swamps. Use the movement-ratio guide for that calculation.

Verify the plan and the Spawn on different ticks

Log the budget status, body array, cost, unused Energy, and expected spawn time before submission. On later ticks, inspect spawn.spawning and confirm the resulting Creep Memory. This revision contains static analysis and syntax checks only; live replacement and emergency-spawn observations remain pending.

Official documentation

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.