Monday, August 15, 2011

pre-alpha-3 – Day 15

Let me start by thanking again everyone who donated! Your help is greatly appreciated!

You may have noticed that this pre-alpha is longer that the previous ones and the number of altered subsystems and overall polish is higher than usual. One of the reasons why it is taking longer is graphics. During the last 10 days I spent a lot of time trying to find the best way to give DwarvesH a new and original look. During this process I tried several things, including outsourcing, and right now I'm not exactly sure with which artistic direction to continue, but soon you'll see some new samples.

But the main reason is that I have changed the way I work and what I do in such a phase. The initial plan was to go over the 0.1 feature list and make sure that as much as possible is working well and then to adjust the next feature set plan. But I changed this approach to one in which I try to make sure that every single feature that is on track to make it into the final design of the game is perfect and fully implemented, without using any placeholders. I have a vision for most of the features. The implementation of said features varies from zero (combat as an example) to placeholder implementation that will probably be drastically changed (weapons and weapon skills are already in the game, but I am not advertising this because I know that the system will be changed) to good implementation that might lack some depth and polish to finished features that will probably make it 1.0. If one one these finished but lacking polish features is something that I want to have in the final game, during this pre-alpha it will get finished and extensively tested.

In consequence, version 0.1 will have less features, but almost everything will be near final implementation and bug free.

So next time you will see the final shape of the plant system (and a little bit even today).

I am in a hurry to write this post because Firefox is driving me crazy with its Blogger bugs. Using the WYSIWYG editor has been lately a huge pain. I can barely insert an image without everything getting messed up and I can't use bullet points.

Added error reporting
During game start up, if something goes wrong, the game will print some messages on screen. This dialog is probably not the best looking thing out there, but it sure beats the game crashing, freezing or otherwise misbehaving:

Visually countable harvested plants
Now you can tell by looking at them how many harvested plants are left in a square. The graphics are just placeholder right now, and food stockpiles do not yet have this feature:

IPS improved
The Incremental Proxy Storage is my home brewed method of storing maps in a relatively very small space without sacrificing speed. Unlike other methods of squeezing out every single possible byte, this method still maintains an OOP interface to map access and thus is still pleasant to use. But it does have some disadvantages too: it is fairly verbose to create an object inside IPS for the first time, it is not too easy to change properties, it is very hard to change structure and it is vulnerable to order and count changes. The last two points relate to saving the map as a save game. I tried to fix these vulnerabilities: creating items is now very short, changing properties remains at the same difficulty, but now this difficulty applies also to changing structure. For the last two, I need to explain the save system.

I have separated the save file into two files: the first is the ruleset and IPS for your game and the second is your raw map, saved and compressed. DwarvesH is a complex game that is getting more and more complex, thus there is no way for me provide compatibility between save games from different versions. This is where the split into two components helps. If you want to migrate to a new version, you need to create a new map under the new version, copy over the new saved IPS together with only your old raw map from the previous version to a new location, and with a bit of luck, everything should work. This is the maximum level of compatibility that I can provide. Making a save game importer for all versions would be an extremely difficult task.

IPS has an item order vulnerability when doing the above method of updating a save game from a previous version. If you change the order of some items from the same category, this order will cascade and apply to all your derivative items creatable from the original items involved that have changed order. So let's say you have a version 0.3 save game on which you played for weeks. Version 0.4 comes, the IPS migration happens, but version 0.4 has swapped the order of blackberries with a mushroom. When you load, all blackberries will be mushrooms and the other way around. So too will be all the items that have as a base material one of the two items. There is no way around this and this misfeature is not that bad: it is a lot better to be able to load your fortress on which you have worked a lot and risk a few small changes then having to either restart the fortress on the new version or be forced to keep both versions installed on your disk. It is perfectly fine if some people choose two keep more versions, but you shouldn't have to be forced to. So this vulnerability of IPS can not be fixed.

The count vulnerability is similar to the previous one, but this time the number of items changes, either because the new version added some new items, or because you are trying to change the mod loadout on a saved fortress. This vulnerability is fixed, but it does have some limits. IPS now intentionally has "holes" to accommodate more items. I added generous padding, but it is still possible to grow over its limits. This is a mechanism that protects fairly well against accidents, not against intention.

Reimplemented world generator
The old "incline hill" map generator was one of the first things I did with world generation. The code was old and not that easy to change, so I redid it in a way that hopefully bridges the gap between it and the random landscape generator. I still need some testing before I can start using the random one regularly. The new implementation also fixed an old and ugly bug.

New reachability algorithm
Ah yes: this is the star change of this post! As said in the past, A* is a poor choice for determining if two points can be connected by a path. If you know that at least a path exists between those two points, then A* is great not only at finding a path, but the shortest one. Maybe too good. It is sometimes weird to to see dwarves move with near clairvoyant path finding on an optimal path. Back in the day I added a little noise to it to provide a less "robotic" and a more "human" feel to it. Here I go again, ranting. So I use another algorithm that can tell me if two points are reachable and which caches this information for the entire map. I changed the algorithm itself to be faster and limited to the area that dwarves can explore at the current moments, so you can have any number of hidden enemy caves that have yet not been discovered without pathfinding taking a hit. Then I replaced the backbone worked of this algorithm: I went from a "vanilla" flood fill algorithm to a very fast scan line fill algorithm. The end result is that the new system uses barely any memory (while the old one ate it like crazy), and the speed in the reference interval for normal maps went from 35 ms to 8 ms.

As a test, I tried it out on a 6000 square meters map: again, barely any memory used and 270 ms speed. Pretty good! Wait... 6000 meters? That is more that last time. Well, all the performance, memory use and stability improvements that went into this pre-alpha had an indirect effect on the game, and the old limit of 4500 square meters is now exactly 10440 square meters! Again, I do not want to create such large maps. This is only a stress test. But it is good to know that without actively working to achieve this goal, the engine can now run maps with an area 5.3824 times as large as before. And the best part is that while last time I could not go over 4500 square meters area because of a weird segfault, this time the engine fails with a simple out of memory error. This error can traditionally be fixed by installing more RAM, but my case is different because I am near the limits of a 32 bit executable.