As I continue working on the combat engine, finishing up other portions of “temporary” code has come up. One particular one is the use of battlemaps.
Most of the 2D CRPG tactical combat games feature some kind of varied terrain to conduct battles on. Ultima’s III-V all had them, one for each different terrain type. So obviously I intended to follow suit here.
But, since I have the disk space for it, I intended to go much further than any of those games. Ultima V only features 16 unique battle maps. My CRPG? Oh, probably around 300+.
I started battlemap design several years ago, when I was still working in the MESS emulator. I actually had to port my work off an old work disk to continue it, and update the tiles, which had changed a few times since I made the original file. Now I’ve gone one step further and made a separate battlemap set for each tile set. That way I can have as many as I need to make combats always potentially interesting.
One complication I had to correct was the loading of different tile sets. Originally I had only a single set for combat. Now I’ve expanded it so that there’s a tied-in tile set for each of the major travel types. That lets me have maximum character space to do interesting features. If you’re in a town battle, lamp posts, crates, barrels, may show up on the map. A dungeon has manacles, skeletons, and other macabre items. All fun!
An added bonus with my approach is that battlemaps will be alterable by player action. Spells exist that let you create barriers, area effects of damage spells can destroy the landscape, and so forth. I don’t think any classic CRPG offered this kind of feature, keeping most of the terrain fairly static.
Battlemaps are stored in two 128 byte records. The first 8 bytes are a compressed mini-map that indicates if the spaces are empty or occupied. The rest of the space stores the maps in RLE compression, using values lower than 128 to indicate a count of the next tile. My battlemap editor warns me if I exceed the record size. This usually happens if I get overzealous with spreading unique tiles around. (I don’t use RLE for the travel maps, because the high-byte is used to indicate lit/unlit squares on dark maps. No real need to compress those files anyway.)
One particular problem to solve is the placement of units on the battle map. I considered at first an array of common positions to just iterate through, but it was quickly adding up to a lot of bytes of data to store. So then I realized I could do this algorithmically with tools the code already has: the trigonometric functions.
Using that code, all I have to supply for the map is two things: a set of coordinates and a radius. Because I want units to spread out a bit, I actually supply two sets. The number of units is divided in half, and then each half is placed in a circle around that coordinate, with the angle being based on the number of units. (4 = 90 degrees, 3=120 degrees, and so forth.) For an ambush scenario, a single set of coordinates is used for both sides, with different radius’s, so one is surrounding the other.
What to do if the chosen space is occupied? Well, first it will check all adjacent squares to that square for any open spots. If it finds one it takes it. If all four cardinal directions have nothing, then I just default to selecting completely random coordinates until an empty space is found. This means there’s a potential for a stray unit to end up in some bizarre place, but hey, that’s the fog of war…
I wrote up the necessary code to do the positioning this afternoon on paper, now I just need to get it written in code and incorporated into the source. I may also need to refactor my trigonometric functions a bit; they were assuming whole word values and I’m pretty much exclusively in bytes, for sprites and coordinates.
Oh yeah, the trigonometric functions. No, I’m not using the ROM routines. They’re difficult to implement and use, plus I’d have to convert everything to Radix 100 floating point. Instead I use whole integers, with a base of 256, and stored the main 90 degree set as values 0-255 in a data table. Ratios are then calculated by multiplying the angle by the data table value and dividing by 256. It’s obviously nowhere near as accurate as a floating-point method, but for what I’m using it for, it works pretty well.
When I get battlemaps loading and positioning of units working, I will probably move on to getting combat ending debugged and sorted out. I’d like to have the end-to-end of it mostly done before I get into the long arduous process of spell FX.