SCRMaps
/
Sign in

Building a UI out of text

StarCraft has no UI widgets. It has eleven lines of chat.

6 min read

Every menu, shop panel and scoreboard you have seen in an EUD map is made of one thing: the chat messages that stack in the top-left of the screen. There are no widgets, no windows and no buttons. Once you accept that, the rest is a question of how completely you can own those eleven lines.

StarCraft keeps thirteen text slots. Slots 0 through 10 - eleven of them - are the lines actually drawn, and slot 12 is the status message that appears in the centre of the screen. That is why a well-made EUD menu is almost always exactly eleven lines: it is not a style choice, it is the hardware.

The screen text memory
0x640B60The text lines themselves: 218 bytes each, thirteen slots. 0-10 are drawn, 12 is the status message.
0x640B58Which line gets written next. Pin it to 0 and the same text lands in the same rows every time.
0x640B24When a message expires. Unsupported on SC:R - writing it throws an EUD ERROR.

The key is 0x640B58. Ordinary chat pushes older messages up as new ones arrive and then times them out. A UI cannot do that. Reset this value to 0 every cycle and redraw all eleven lines, and the text neither scrolls nor expires - it stops being a message and becomes a screen.

dwwrite(0x640B58, 0);   // 다음 줄을 맨 위로 되돌림 / rewind to the top line
DisplayTextAll("\x13\x1F【 \x04메뉴 \x1F】");
Redrawn every cycle, so this screen never times out.

Never write 0x640B24. Extending a message's lifetime to hold the screen looks like the obvious approach, but that address is Unsupported on SC:R and the map dies with an EUD ERROR on the spot. You hold a screen by rewinding the line counter, not by extending a lifetime.

Clearing works the same way. There is no clear function, so you print twelve blank lines at once and push the previous screen off the top.

DisplayTextAll(" \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n ");
The idiom for pushing eleven lines off at once.

Layout inside a line is done with control characters: \x13 centres, \r\n breaks, and \x01 to \x1F set colour. A long panel is usually emitted as one string with several \r\n in it rather than line by line - printed separately, another trigger can interleave between them and the order breaks.

To interpolate values use f_eprintf: {} for a number, {:n} for a player name. The number of placeholders must match the number of arguments exactly, and the build fails if it does not - which is a kindness.

One more thing: Hangul renders about twice as wide as Latin. To keep a line from wrapping on a 4:3 screen you have to measure in Hangul widths - and translating the same panel into English usually gives you more characters at a similar total width.

The full colour and alignment table
Sign in to track your progress