SkoolKit

Spectrum game disassembly toolkit

It cuts one way

One way saw

More than a year has passed since the last disassembly-related announcement on this website, so in an attempt to make up for lost time, here is an update on the Manic Miner and Jet Set Willy disassemblies, new versions of which have recently been released.

In the previous announcement concerning these disassemblies it was Manic Miner that got the lion’s share of the limelight (such as it was), but this time it’s Jet Set Willy that deserves most of the attention, with its five new bugs and seven new trivia entries. Among those bugs are the one where Willy can effectively teleport from the top of a room to the bottom by jumping off a rope, and also the one where Willy can become imprisoned inside a bunch of wall tiles at head height. Among the trivia entries are the story of the saw guardian that never turns round, and instructions on how to make Willy jump a little higher than the regulation 20 pixels. In comparison to these riches, the Manic Miner disassembly has gained a paltry one new bug and one new trivia entry since it was last mentioned here.

In addition to these obvious changes, there have also been some more subtle improvements to the disassemblies to make them read better when they are rendered in hexadecimal. For example, cavern numbers and entity numbers are now shown in hexadecimal instead of decimal, so as not to jar with the mass of hexadecimal addresses and DEFB statements.

Anyway, as always you can consult the changelog page for each disassembly for details on the new bugs and trivia entries (however great or small their number), and the download page to grab copies for offline viewing.

No assembler required

skool2bin2sna

SkoolKit 5.2 has been released. In keeping with the principle of least surprise, copies of 5.2 are available from the download page , the Python Package Index, and the Ubuntu PPA.

So, as the poet once asked, what is new in 5.2? Well, there is the bin2sna.py command, which converts a binary file into a Z80 snapshot. This, coupled with skool2bin.py’s new ability to write to standard output, could lead to some streamlining of some workflows in one’s day-to-day reverse engineering. For example, let’s say (you think) you’ve fixed a bug in a game, and you’ve added the corresponding @bfix directives to your skool file. In days gone by, you might have done something like this to test your fix:

$ skool2asm.py -f 2 game.skool > game.asm
$ pasmo game.asm game.bin
$ bin2tap.py game.bin
$ fuse game.tap

But now, in SkoolKit 5.2, you have the option of doing something like this:

$ skool2bin.py -b game.skool - | bin2sna.py - game.z80
$ fuse game.z80

I know which approach I prefer. And, by the way, bin2tap.py can now read a binary file from standard input as well, so if you’d rather still load a TAP file than a Z80 snapshot into your emulator in the last step, you also have that choice.

That pretty much covers the main new features. But there is also the #N macro, which is useful for rendering numbers in either decimal or hexadecimal format depending on whether the --hex option is used with skool2asm.py or skool2html.py. And there is also the @rfix directive (non-block version), which rounds out the family of mode-related ASM directives.

Details of the other changes not significant enough to merit a mention in this article can be found, as always, in the changelog. When you’re finished there, consider taking the SkoolKit 5.2 challenge: throw away your assembler for a bit and see if you can live with just skool2bin.py and bin2sna.py!

Keeping it SMPL

#FOR1,100($n,I will not...)

SkoolKit 5.1 has been released. Even though it goes without saying, I will say that copies of 5.1 are available from the download page (as usual), the Python Package Index (as usual), and the Ubuntu PPA (as usual).

Before we embark on a tour of the new features in this release, allow me to divulge a small piece of previously unrevealed history. Back in January 2012 - between 2.4 and 2.4.1 in SkoolKit time, if that’s how you prefer to measure dates - I added an item to my SkoolKit TODO list about making it possible to define a new skool macro in terms of existing skool macros without writing any Python code. At the time, it was just an idea that I hadn’t really fleshed out. And it stayed that way until fairly recently - between 5.0 and 5.1 in SkoolKit time, as it happens - when I finally decided on a scheme that would bring the idea to fruition.

Enter 5.1 with the @replace directive, the ability to evaluate arithmetic expressions in macro parameters, and seven new skool macros: #(), #EVAL, #FOR, #FOREACH, #IF, #MAP and #PEEK. Together they constitute the Skool Macro Programming Language - SMPL (pronounced ‘simple’, I’ve just decided) for short. With them you can effectively define new macros that are shorthand for complex forms or combinations of the classic skool macros, or that fill in gaps in their capabilities.

For example, let’s look at the good old #UDG macro. It’s fine as far as it goes, but one thing it has lacked all these years is the ability to specify an address from which to collect the desired attribute byte; instead we’ve had to hard code the attribute value into the #UDG macro’s parameter string. Now, though, with the advent of the #PEEK macro, that has changed. Suppose the game we’re disassembling arranges tiles in groups of nine bytes: the attribute byte first, followed by the eight graphic bytes. Then we could create an image of the tile at 30000 like this:

#UDG(30001,#PEEK30000)

Which is nice, but perhaps not a great improvement over hard coding the attribute value. Now suppose that we want to create images of the tiles at 30009, 30018 and so on:

#UDG(30001,#PEEK30000)
#UDG(30010,#PEEK30009)
#UDG(30019,#PEEK30018)
...

This is getting tiresome. However, the nascent SMPL programmer within you should be noticing a pattern to these macros; they are all of the form:

#UDG(addr+1,#PEEKaddr)

where addr is the address of the tile’s attribute byte. Having identified the pattern, we can now embody it in a @replace directive, which replaces one regular expression with another:

@replace=/#udg\i/#UDG(\1+1,#PEEK\1)

With this directive in place, we can now create images of the tiles with the appropriate attribute values thus:

#udg30000
#udg30009
#udg30018
...

Which, I hope you will agree, is actually starting to look somewhat handy. But still, typing out all these #udg macros is a pain when there are 20 of them (say). So let’s use a #FOR loop instead to cut down on the typing:

#FOR30000,30171,9||n|#UDG(n+1,#PEEKn)||

If you’re still not convinced of the merits of SMPL, try this control file snippet on a snapshot of Hungry Horace:

@ 28663 replace=/#maze\i/#UDGARRAY#(32#FOR(\1,\1+767)||n|;#tile||)
@ 28663 replace=/#tile/(31735+8*#PEEKn),#MAP(#PEEKn)(61,2:60,3:56)
b 28663 Maze layouts
N 28663 #maze28663(maze2)
N 29431 #maze29431(maze1)
N 30199 #maze30199(maze3)
N 30967 #maze30967(maze4)
i 31815

Now take a look at the data block at 28663, with its correctly coloured images of the mazes in the game, each one composed of 32x24 tiles. All without a single line of custom Python code in a SkoolKit extension module.

Well, I’ve done my best to showcase SMPL in this brief introduction. The rest is now up to you.

For details of the other (boring by comparison) changes in 5.1, see the changelog. But after that, go forth and define new macros.