Another thing I'm still wondering is why each character class has the entire tileset with clones of terrain tiles etc. It's taking much more space that it should (making the download also bigger). I guess it's easier(?) to manage tiles that way, you need only one large file for tiles, no need to split them to terrain etc. tilesets.
Historically grown, as all the other bad coding, idiosyncrasies, inconsistencies, imperfections, and "wrong" priorities.
When I draw a tile, I actually print an ASCII character and the tileset is just the "font" used for drawing. The tile to draw is selected based on the ord of the char:
OrigRect.x := (Ord(c) - 32) * 40; // for the big 40x80 tiles
where "c" is the char I want to print.
So, for example drawing a "player" tile in line 10, row 5 of my "virtual" terminal, I could write something like CharXY(5, 10, '@') and the function will select the 40x80 part of the tileset that corresponds to the ord of the char.
In the actual game, the player graphic is on chr(143) -- don't ask me why, I don't remember why I did not simply use the actual @ ... and even worse, because in the console mode I of course want to have a regular @ I transform the "chr (143)" back to a "@" before output happens.
A bit confusing, but it works, and the end user does not notice anything of this. Of course it has several disadvantages (such as no easy way of dynamically displaying equipment, and the total restriction to 255 characters of the ordinary ASCII table), but as I don't strive for perfection, and have no "I want to be a better programmer" goals or anything like that, it's fine. Finally, all tilesets together are just 5 MB.