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);| 건물 그래픽 | 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.
- 1Set that order's Animation to ReturnToIdle, so the cast never actually happens.
- 2Set that spell weapon's cooldown to 100. That is the mark that tells this cast apart from a real one.
- 3Condition on Spell Cooldown instead of the main order; when it fires, run the skill and write the cooldown back to 0.
- 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.
| 건물 건설 버튼 | 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;
...
}
}| 아이템마다 마법을 따로 희생해야 하나? | 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