saga20101119 - simondotm/stardot-wiki GitHub Wiki
Three days and I'm back to where I was on the 16th. Well, not quite, I've updated the compression routines which required quite a bit of a rewrite. There's also been a bit of tuning for handling messages.
First off, the compression. The ScottFree format of rooms is:
byte northexit
byte southexit
byte eastexit
byte westexit
byte upexit
byte downexit
string description
Which is generally wasteful as very few locations have all six cardinal directions open. The easiest way to compress this is a have an exit count, followed by only those exits that are open. Of course we need a way of the direction of each exit. It'd be great if we had enough spare bits to munge this into a single exit byte; but there are 6 directions (so 3 bits required) and the SAGA engine allows up to 150 rooms (8 bits), so this won't work. What we can have is an exit status byte (similar to that used by the Robico engine), which uses a bit for each direction, e.g. bit 0 = north, bit 1 = south etc. This gives us a count and the order of exits in one byte.
It does mean that we have to be a tad more complex on using the exits. Fortunately, RichTW came to my aid with the difficult bit of how to map a given exit (e.g. North) to its location.
The other compression step was on conditions, I fixed a bug in my compression code, which may have lost some conditions. Whilst doing this I notice a potential for another saving: the most common condition is 0 (push), which pushes a parameter onto a stack for the actions to use later. The parameters could be a counter (up to 8), a flag (up to 16) or a room or object (up to 150) and there are up to 20 conditions. As we only have 20 conditions, we have 3 spare bits that we can use. If we make a special condition where if the condition is 0 and the parameter is less that 127, we store this in a byte with bit 8 set. Most condition 0's I've seen are less than 127, so it will save us quite a few bytes.
One side effect of this is that it will be better to change the count of conditions/actions to be a count of bytes representing conditions/actions, so any find functions don't have to try to parse them. We also have 2 spare bits that we could use to compress other conditions similarly!
On to the big change: until now I'd been using zero terminated strings (I'm too used to C programming). The problem with this technique is that if you need to search for a message you have to touch every byte from the string start to the string end. If we change this slightly so each string is preceded by a count to the next bit of information, we have a net byte difference of 0, but our loops to locate a string are quicker and require less code! The only disadvantage to this is I had to roll back a change to the objects, which used the terminator byte to store information to make some minor shrinkages in object data. Below is the same code as used above, now simplified:
.objectloop lda objectlocs,x
cmp astore
beq printobject
.nextobject inx
cpx nitems
bne objectloop
jmp leave
.printobject stx xstore
txa
jsr findobject
.prtobj jsr copymessage
ldx #workbuffer MOD 256
ldy #workbuffer DIV 256
jsr printbuf
ldx xstore
jmp nextobject
Finally, I've moved the system messages to a table at the end of the code. As the messages change for different games, this makes it easier to allow template loads. To save code I made a second entry point in my currently existing findmessage routine, so it could just use that!