SCRMaps
/
Sign in

Skills that take a target

The build queue tells you a button was pressed. Which route you take depends on whether the target is a unit or a patch of ground, and on whether you charge minerals or energy.

17 min read

The queue method from the last lesson gets you as far as "pressed". But for half of all skills the whole point is where - a teleport, a ground-targeted blast, where a summon appears. You could lay locations and read those, but then you are back at the 255-location problem.

There is already one situation where StarCraft asks the player for a coordinate: placing a building. So make the skill button a Create Building rather than a Create Unit, and the game collects the clicked spot for you and puts it in the caster's CUnit - 0x58 is X and 0x5A is Y.

// 메인 명령으로 감지하고, 좌표를 읽어 로케이션을 옮긴다
// detect on the main order, read the coordinates, move a location
const x, y = posread_epd(caster + 0x58/4);
setloc("SkillTarget", x, y);
What has to be set up for this to work
건물 그래픽Change it to a cursor, a dot, a beacon or something like a start location, so it reads as an indicator.
Build (Protoss) 명령 요구사항Its default limits it to Probes. Widen it or the hero pressing the button does nothing.
감지할 명령Main Order, not Secondary Order.

There is a reason it has to be the main order. Building uses both: the main order walks the unit to the spot and the secondary order makes the building. Reading the main order fires your trigger before the unit starts walking; waiting for the secondary one means the skill goes off after the hero has walked across the map.

This has exactly one drawback: building costs minerals and gas, not energy. To charge energy instead, change the approach - use a real spell, but hollow it out so it does nothing by itself.

  1. 1Set that order's Animation to ReturnToIdle, so the cast never actually happens.
  2. 2Set that spell weapon's cooldown to 100. That is the mark that tells this cast apart from a real one.
  3. 3Condition on Spell Cooldown instead of the main order; when it fires, run the skill and write the cooldown back to 0.
  4. 4Read the coordinates from 0x58 and 0x5A exactly as before.

The engine charges the energy, because a real spell really was cast - it just does nothing, and everything it appears to do is your trigger.

If the target has to be a unit rather than a patch of ground there is a third route. Make the button an ordinary spell button: the cursor changes, the player picks a unit, and the choice lands in the Secondary Order and its target field. Read that, cancel the order, and produce the effect yourself.

The three routes and what each one hands you
건물 건설 버튼Gives you a ground coordinate (0x58, 0x5A). Detect on the main order. Costs minerals and gas.
속을 비운 진짜 마법Gives you a ground coordinate and the engine charges the energy. Detect on the spell cooldown.
보통의 마법 버튼Gives you a unit target. Detect on the secondary order and its target field. You handle the cost.

On that third route you have to charge the energy yourself for a simple reason: as far as the game is concerned the button is not a spell, so the game's own energy check never runs. Read the energy out of the struct, do nothing if it is short, and subtract before firing if it is not.

A note on the source: the third route comes from 2020 Brood War era material that the corpus marks unverified. The addresses used were checked against eud_book's SC:R support levels - CUnit's Secondary Order ID and Build Queue are both Supported - but test it on Remastered anyway.

Where the third route gets used most is "use this item on one of my units", and the shape is fixed enough to be worth memorising whole.

foreach(player : EUDLoopPlayer()) {
    const orb = CUnit.cast(orbEPDs[player]);
    if (orb == 0) continue;
    if (orb.order == "Die") { orbEPDs[player] = 0; continue; }   // 죽은 것 정리 / reap
    if (orb.order == <인식할 명령>) {
        orb.order = "Stop";                       // 한 번만 발동 / consume it
        const target = orb.orderTarget;
        if (orb.owner != target.owner) continue;  // 내 유닛에게만 / my own units only
        if (target.unitType != "Terran Marine") continue;
        ...
    }
}
The four questions these lines answer
아이템마다 마법을 따로 희생해야 하나?No. Several items can share one spell; which item it was is sorted out afterwards from orb.unitType.
'내 유닛에게만'은 어떻게 쓰나?orb.owner != target.owner, and that is all of it - there is no separate check.
아무것도 인식이 안 됩니다Check you stored the item's EPD before the CreateUnit, not after. Store it after and the handle is empty, and the symptom is that nothing happens at all.
인식은 되는데 명령이 안 맞습니다Put a print above the test. Nothing printing means the handle is wrong; printing but never matching means the button is not changing the order - check the weapon and combat auto-response.

And there is a rule about where to spend effort in it. The detection runs every cycle and is worth optimising; what happens after it fires runs rarely and should be written plainly. Optimising both equally only makes the code harder.

Detecting a button press with the build queueThree ways to read the struct wrong
Sign in to track your progress