A proposal for moving Angband's UI forward
Angband is, by any standards, a rather old computer game. It started off as an entirely terminal-based affair, and it remains to this day implemented entirely in terms of operations on a grid of characters.
There are some limitations to this approach. First of all, if you want to do anything other than plain-text display, you have to introduce massive hacks. This is the case with the 'solid block' walls which the SDL and Windows use (a special character is encoded into a font), and with tile support (which is just plain icky).
Second, it means that if you want to add graphical touches to the game, such as allowing an overlay map in the top corner of the screen, allowing scrollable (as in, with a scrollbar) object or monster recall, displaying the map at a different text size than the surrounding panels, or using semi-opaque backgrounds behind menus instead of plain black. you are pretty much screwed.
Some years ago now, ajps (Antony Sidwell) proposed that a split between the UI of the game and the core took place, with the game proper running entirely through a queue of commands (such as "move left", "inscribe x with y", "cast magic missile") which manipulate the game state. On state changes, the game issues various events which the UI uses to keep its display up-to-date.
ajps completed quite a significant amount of work towards this goal, but in part because Angband is essentially a lot of hacks piled upon other hacks, progress is slow and difficult.
The core/UI split is pretty essential for the future of the game, since it is both conceptually a lot cleaner than the current mess, and because it allows UIs to do much more novel things just by hooking into the relevant events.
However, whatever the underlying code/UI split is, if the UI is confined to a grid of monospaced text, we cannot hope for any advances. For example, if we wanted to display chunks of text in variable-width fonts where possible (e.g. monster or object recall), we have to switch away from the pure-terminal model.
The future of the text UI
Urgh, you say, what about the curses port? What will become of our ASCII-purist game if we add graphical 'touches' here and there?
textui, as the standard UI is currently called in the code, is not going to go away. However, since we definitely want such things as better tile support that is not limited by font size, and maybe things like variable-width fonts or miniature overlay maps in the top right hand corner, we will have to find a way to make them work together.
So, my proposal is as follows:
- Non-console frontends implement a graphics surface interface instead of a terminal emulator interface.
- Each UI element (map, status bar, side panel, message line) is printed to its own virtual terminal window, containing just that UI element.
- We create compositors, which take the various UI elements and:
- for curses ports, just plots them to the real terminal
- for graphics ports, plots them to a graphics surface.
After this is done, we have a good framework to move forward from, one which allows both a text backend and a graphics backend. In order to add graphical features, we just write code that the graphics compositor pays attention to while keeping the textui code around.
This has a few advantages, namely that we get graphical touches without sacrificing old ports, and we can test all possible UIs from one port (rather than frontends going off and doing their own thing with the new hooks, a la main-gtk's extra term windows). We also would be centralising processing of graphics, which means most redraw issues would be reproducible on all graphical ports thus easing testing.
From here we can do all sorts:
- Write tile-based map code, and code a switch for the compositor to use tiles instead of ASCII when we want graphics (in the meantime eliminating fake transparency and bigfile in the z-term package)
- Write a graphical implementation of the ui-menu API for people who like that kind of thing
- Make variable-width font versions of object and monster recall (already close to being possible because of the new textblock code)
- Make the 'M' map command display a scaled-down version of the map on graphical ports and the current horrible mess for text-only ports.
- Overlay menus on the game with a graphical border rather than just two spaces of padding.
- and so on...
A diagram showing it all of this fits together
What the graphic surface API would look like
I have little experience of graphics programming, but my guess would be at minimum:
- load/save state
- plot rectangle at (x,y)
- plot text at (x,y)
- plot tile at (x,y)