Sunday 31 May 2009

In praise of libraries

I've just spent the last day and a half avoiding the fact I need to implement a tree view in Unangband.

Let me explain a little. I had planned to spend this weekend wringing out the last few show stopping bugs from the 0.6.3 Unangband release. But I made the mistake of reading this thread on angband.oook.cz discussing the monster list view command ('['). Big Al, one of the contributors to the Unangband code base has ported this useful little command from Angband - the source of the discussion - to allow you to see a list of visible monsters at any time.

So I got to improving it, based on some of the suggestions in the thread. Screenshot below (it's too easy to paste html screen dumps directly into the blog).

You are aware of 16 monsters: (by distance)      ##%xxxxxxxxxxxxxxxx{##########
4 Wild dogs ('C')/('C')x ####xxxxxxxxxxxxxxxx##########
White snake ('J')/('J')x ###%xxxxxxxxxxxxxxxx##########
2 Giant white centipedes ('c')/('c')# ####x%####%'%#################
2 Rock lizards ('R')/('R')# ####x######x##################
Cave lizard ('R')/('R')x ####x######x##################
Grey mold ('m')/('m')# ####x######x##################
5 Jackals ('C')/('C')# ####x######x###...############
####x######x###...############
You are aware of 290 objects: ###%.%####%.%%.....###########
99 Arrows (49 unknown) ('{')/('{')x .............'.@...###########
2 Sets of Leather Gloves (1 unknown) (']')/(']')############.#%.....###########
a Scroll titled "ninhe mik" ('?')/('?')x ###########x###...%###########
17 Iron Shots ('{')/('{')# ###########x###.............##
a Sickly Green Potion ('!')/('!')# ###########x#####%#########.##
5 Hard Leather Caps (2 unknown) (']')/(']')# ###########x###############xx#
a Buckler (')')/(')')# ###########x###############%x#
a Scroll titled "sef ple nagion" ('?')/('?')# ###########x######%#########x#
99 Bolts (22 unknown) ('{')/('{')# ###########xxxxxxxxxxxxxxxxxx#
a Scroll titled "elcos ta fuox" ('?')/('?')# ##################%###########
a Flask of Oil ('!')/('!')# ##############################
-- more --###########xxxxxxxxxxxxxxxxx%####################!!xxxxxxxxxxxxxxxxx#
#####################xxxx<xxxxxxxxx-xx################################%########
There's at least one visible bug in the screenshot and the underlying implementation is horrendous. I knew it was time to stop last night, when I spent five hours trying to figure out why the mouse (x, y) coordinates weren't mapping to grid (x, y) coordinates (hint: try using the translation macro I wrote a year ago instead of searching repeatedly through the entire code base - don't code tired).

I've spent the morning cleaning up the implementation to make it a lot more readable and extendable. Think of yesterday's code (in svn) as the prototype and today's (still to be checked in) as the final code.

But I've ended up in this position again:

/*
* Displays a list of sorted indexes
*/
key_event monlist_display_sorted_indexes(int sort_by, int max, int *total_count, int row, int *line, const char* index_name, int header_offset,
bool *intro, bool *done,
int *monlist_get_index(int idx), bool *monlist_check_grouping(int idx, int group_by),
bool *monlist_check_secondary(int idx), int *monlist_get_order(int idx, int sort_by),
int *monlist_copy_to_screen(int idx, int line, monlist_type *monlist_screen, u16b *index_counts, u16b *index2_counts)

Sound familiar?

The mistake here is similar to the moral simplification I wrote about last time, where I'm trying to mix user interface with game logic (actually data manipulation this time around). I really should prepare the underlying data, then hand it off to a user interface widget to handle the user interaction, and at the moment I'm still not doing this cleanly.

And a tree widget is probably the best for this particular data structure.

If you're thinking about writing a roguelike, you really want a user interface library on top of it...

No comments: