DEFENSE · TOWER HEAL PRIORITY

How to Make Towers Heal the Creep That Needs It Most

Find injured owned Creeps, rank lower hit ratios before missing hits and nearest-Tower range, require active owned Towers with TOWER_ENERGY_COST, save heal() results, avoid caching stale targets, and leave over-heal optimization to a later dispatcher.

Verification statusChinese source article: Reviewed in full · Official docs: Checked — StructureTower.heal(), whole-room range, falloff, TOWER_ENERGY_COST and return codes · Priority boundary: Hit ratio, missing hits and range are a project ordering policy, not an official medical or combat priority

VERIFICATION

Evidence and test status

Chinese source article
Reviewed in full
Official docs
Checked — StructureTower.heal(), whole-room range, falloff, TOWER_ENERGY_COST and return codes
Priority boundary
Hit ratio, missing hits and range are a project ordering policy, not an official medical or combat priority
Execution boundary
OK schedules healing; target hits and actual range-adjusted effect require later observation
JavaScript syntax
Passed
Offline healing review
Passed — valid injuries, hit ratio, missing hits, nearest-Tower range, stable ties, Energy and activity states
Screeps Console test
Pending
Live Tower heal, falloff, boost, over-heal and multi-target allocation test
Pending
Last verified
July 26, 2026

Quick answer

Find owned regular Creeps with 0 < hits < hitsMax, select the lowest hit ratio first, then the largest missing-hit count, nearest available Tower range and name as a stable tie-breaker. Let only owned active Towers with at least TOWER_ENERGY_COST Energy call tower.heal(target), save every result, and verify target hits on a later tick.

Filter valid injured Creeps

function getInjuredOwnedCreeps(room) {
  return room.find(FIND_MY_CREEPS, {
    filter: creep =>
      Number.isFinite(creep.hits)
      && Number.isFinite(creep.hitsMax)
      && creep.hits > 0
      && creep.hitsMax > 0
      && creep.hits < creep.hitsMax
  });
}

This scope excludes Power Creeps intentionally. It also ignores dead or malformed objects and avoids wasting actions on full-health targets.

Rank urgency before distance

function selectTowerHealTarget(towers, creeps) {
  const injured = creeps.filter(creep =>
    Number.isFinite(creep.hits)
    && Number.isFinite(creep.hitsMax)
    && creep.hits > 0
    && creep.hitsMax > 0
    && creep.hits < creep.hitsMax
  );

  if (towers.length === 0 || injured.length === 0) {
    return null;
  }

  return [...injured].sort((left, right) => {
    const ratioDifference =
      left.hits / left.hitsMax
      - right.hits / right.hitsMax;

    if (ratioDifference !== 0) {
      return ratioDifference;
    }

    const missingDifference =
      (right.hitsMax - right.hits)
      - (left.hitsMax - left.hits);

    if (missingDifference !== 0) {
      return missingDifference;
    }

    const leftRange = Math.min(
      ...towers.map(tower =>
        tower.pos.getRangeTo(left)
      )
    );
    const rightRange = Math.min(
      ...towers.map(tower =>
        tower.pos.getRangeTo(right)
      )
    );

    if (leftRange !== rightRange) {
      return leftRange - rightRange;
    }

    return left.name.localeCompare(right.name);
  })[0] || null;
}

These priorities are explainable but not universal. A combat system may consider incoming damage, role, boosts, retreat state, Rampart position or defender importance.

Require active Towers with Energy

function getAvailableHealingTowers(room) {
  return room.find(FIND_MY_STRUCTURES, {
    filter: structure =>
      structure.structureType === STRUCTURE_TOWER
      && structure.isActive() === true
      && structure.store.getUsedCapacity(
        RESOURCE_ENERGY
      ) >= TOWER_ENERGY_COST
  });
}

A Tower action uses Energy and one Tower should have one dispatcher per tick. Preflight cannot stop a separate module from assigning attack or repair afterward.

Complete Tower healing example

function runTowerHealing(room) {
  if (!room) {
    return { status: 'room-not-visible' };
  }

  const towers = getAvailableHealingTowers(room);
  if (towers.length === 0) {
    return { status: 'no-available-tower' };
  }

  const target = selectTowerHealTarget(
    towers,
    getInjuredOwnedCreeps(room)
  );
  if (!target) {
    return { status: 'no-injured-creep' };
  }

  const snapshot = {
    gameTick: Game.time,
    targetId: target.id,
    targetName: target.name,
    hits: target.hits,
    hitsMax: target.hitsMax,
    hitRatio: target.hits / target.hitsMax,
    missingHits: target.hitsMax - target.hits
  };
  const results = towers.map(tower => ({
    towerId: tower.id,
    range: tower.pos.getRangeTo(target),
    energyBefore: tower.store.getUsedCapacity(
      RESOURCE_ENERGY
    ),
    result: tower.heal(target)
  }));

  return {
    status: results.some(item => item.result === OK)
      ? 'heal-scheduled'
      : 'heal-rejected',
    snapshot,
    results
  };
}
module.exports.loop = function () {
  const room = Game.rooms.W1N1;
  if (!room) {
    return;
  }

  const outcome = runTowerHealing(room);
  if (
    outcome.status === 'heal-rejected'
    || Game.time % 100 === 0
  ) {
    console.log(JSON.stringify({
      type: 'tower-heal-status',
      roomName: room.name,
      ...outcome
    }));
  }
};

Understand multi-Tower over-heal

This baseline focuses every available Tower on the same injured Creep. That is easy to inspect but can spend more Energy than necessary when one Tower would fill the missing hits.

function getMissingHits(creep) {
  return Math.max(0, creep.hitsMax - creep.hits);
}

A more advanced allocator needs the range-adjusted healing amount, active power effects, already assigned healing and expected incoming damage. This article does not claim focus healing is optimal.

Keep one Tower action dispatcher

A common room policy is attack before heal before repair. That order is not enforced by the Tower API; your code must select one action for each Tower.

function chooseTowerMode(input) {
  if (input.attackTarget) {
    return 'attack';
  }

  if (input.healTarget) {
    return 'heal';
  }

  if (input.repairTarget) {
    return 'repair';
  }

  return 'idle';
}

Refresh targets every tick

The target may heal to full, die, leave the room, move closer to another Tower or receive new damage. Save only IDs and snapshots for diagnostics; run the selection again from current visible objects.

Verify healing later

Compare the saved hit count with the recovered Creep on a later tick. Healing may be partly or fully offset by damage in the same resolution window, so a final hit difference is evidence of net state rather than a perfect measurement of one Tower's contribution.

Handle return codes

CodeMeaningReview
OKHealing scheduledTarget hits later
ERR_NOT_OWNERTower not yoursSelection and ownership
ERR_NOT_ENOUGH_ENERGYInsufficient EnergyStore and competing Tower actions
ERR_INVALID_TARGETCreep invalidRefresh current target
ERR_RCL_NOT_ENOUGHTower inactiveRCL and isActive()

Debugging checklist

  • Use FIND_MY_CREEPS for this scope.
  • Require valid positive hits and hitsMax.
  • Exclude full-health Creeps.
  • Document the hit-ratio policy.
  • Use stable tie-breakers.
  • Require active owned Towers.
  • Check TOWER_ENERGY_COST.
  • Use one action dispatcher.
  • Save every heal return code.
  • Verify net hits later.

Scope and next steps

This guide does not include Power Creeps, exact range healing, boost effects, incoming-damage prediction, split healing or over-heal prevention. Continue with Tower repair thresholds and reserves.

Frequently asked questions

Why not always heal the nearest Creep?

The nearest Creep may have only minor damage while a farther defender is close to death. This policy ranks urgency before distance.

Why use the name as the final tie-breaker?

It makes otherwise equal target selection stable without pretending the name has combat value.

Can attack and heal functions both run?

Separate functions can both be called, but a controlled system should choose one intended action per Tower and preserve the final return code.

Official documentation

SOURCE AND SCOPE

Review the source, evidence, or next system

This English guide is rewritten for a focused search intent while preserving the technical scope and verification boundaries of its Chinese source. Live-room evidence is claimed only when the verification record says it exists.