Friday, 7 March 2014

Mask map class

I'm back to Kaduria. It's useful to switch projects when something gets boring and you feel stuff is not going to proceed. Returning to project after a break often works, because it's then easier to get new ideas and solutions to problems.

Currently I'm working on the mask map problem and as terrain map it really needs a derived map class with a set of routines to return abstracted (the verbose public interface I have mentioned often) information rather than using enum mask values everywhere.

I have also developed a slightly different kind of way to look at todo list items and evaluate their importance and also the ways how to solve them. I think I'm now much less concerned about good (or even perfect) solutions. I've started to use a kind of sketch solution just to make something work. I believe it's much better than just staring at some item in the list and getting nowhere with it.

Thursday, 6 February 2014

Action mode

One of the artificial intelligence ideas I have is action mode which has one selected at a time. In basic mode the character is adventuring or walking. Then there are modes like running and also sleeping (in voluntary way rather than fainting). The action mode has a big impact on what you can do at the moment so if you are climbing up from a pit you can't do anything else.

There might be a problem when you are floating on air and try to sleep. I was thinking of how to do that, but I guess the location itself can be an indicator that you are floating. Without it the floating could also be an action mode which would then make sleeping impossible when floating. Well, that's the stuff we roguelike developers need to think.

I like the idea of action mode, because you can choose between walking and running etc. Running will spend stamina (and food) faster, but you can use the faster moving speed when needed. The action mode will be displayed on screen all the time so you don't have to check it out from some stats screen.

I've tried to concentrate on AI programming and action mode is hopefully going to clear some confusion in that part. Sometimes it can be difficult to figure out what belongs where, because there are stats, then affects (illness, burn wounds, etc.), different motivations for creatures, current task and action mode. It's possible that I forgot something. Most of that stuff has effect on something else. It's not obvious that the gelatinous cube is on fire while swimming and at the same time eating bisquits and tea.

Friday, 24 January 2014

Data-driven class design

As if my normal posts weren't boring enough, this one is about programming. I'm a big fan of OOP (object-oriented programming) and have tried to apply it in my projects. But working with a legacy project like this I'm constantly fixing style mismatches with traditional C's linear programming style.

One of the basic ideas and building blocks in Kaduria is a data-type class that has a simple value stored (usually with accompanying enum list) and a verbose public interface. As an example there is a problem I'm working on right now. It's the mask value for mask map. In plain old C you would use enums like this:

if (mask_map->Get(x, y)==maskWall) Do_Something();

(Actually I'm using coordinate parameter for location, and x, y is used here for clarity.)

That maskWall is a "linear" or plain data. Using a datatype class things change a bit:

K_Mask_Type m=mask_map->Get(x, y);
if (m.Is_Wall()) Do_Something();

It's doing exactly the same thing, just with minor difference of using class and a getter routine. The m value is simply the mask value in the map, stored into K_Mask_Type as the only variable which then can point to the data associated to mask value. Is_Wall() can look something like this:

bool K_Mask_Type::Is_Wall()
{
  return mask_data[type].is_wall;
}

But it can also be a switch statement or any other way to handle data.

The problem with first way, old school C, is that you might want to add another mask type which is also a wall. When you do it you need to write changes in all places using that statement, for example like this:

int m=mask_map->Get(x, y);
if (m==maskWall || m==maskCorridor_Wall) Do_Something();

As you can guess, the great thing in class style is that you can add the new mask type, but Is_Wall() can include it and you don't have to search for those if statements in the source code.

It's not all good, because you can have legacy code that has both styles mixed and it can require more than just simple if statements to be changed. Also, the way the class itself is written can become complex as you add verbose functions for each of features. In this case the getter/setter syndrome is not actually that big problem, because that's the way it is supposed to work anyway. You can go wrong with class functions, too. But often they hold a logic which works through the project and when you add something it's less likely that something breaks elsewhere.

The verbosity of class functions is not something I would have thought means anything when I was still learning OOP, but it's of course a powerful way to write source code along with "class as type" classes. Often when people think of classes they are already thinking inheritance and other more advanced things that in my opinion are less important! In fact when you get to the next level you try to avoid inheritance at all costs, because it's a complex topic in which many things can go wrong, starting from the way you plan the class hierarchy. For some people it goes as far as inventing their own meta-language using templates.

I think many C++ books are to be blamed on how we see classes and immediately associate inheritance and "easy" re-use to them. Far more important is the data-driven idea: hide the raw data in the class and use (verbose) public interface to avoid refactoring through the source code when something changes. And as we know in case of roguelikes there always will be changes.

Wednesday, 22 January 2014

The hatch

On halfway of nine selected todo items I ran into a problem. There are some door type (lid) objects on top of stairs or sewers. Those objects are created on the same map as other objects that don't move, including stairs. When you create a hatch lid on stairs and open it the stairs are not displayed. More than that it also affects to object interactions (collision detection etc.).

The layer system of maps is already complex, but I could solve this by creating another layer for door type objects. Or I could create a stacked object map with std::list for each tile. Whatever the solution were it would also include collision detection logic etc. In other words a lot of work.

I was thinking of this for a while and decided to skip it. Just skip it for now. Lids are needed for sewers and in rare cases for stairs. It's not an important feature right now and because it's pretty big change to the engine I want to make sure that other more basic features are done first.

Wednesday, 15 January 2014

Update areas rewrite

There are rectangle areas dividing screen in parts and update each of them when their flag is set. At least with software mode of SDL this is a good idea, because it certainly does speed up the game compared to full screen update. Besides not only updates, the background graphics are also re-drawn when something happens in that area.

I've been refactoring those areas, because I needed to change message output to 5 lines and scrolling mode. The ancient nature of GUI was revealed when I noticed that almost all actual output to those areas were hard wired with another set of coordinates. So.. this is how it looks now:


Those purple dotted lines show the areas as debug method to actually see where they are. I already fixed the small map, but as you can see the gameview is in wrong place and stats also (and some areas itself), displaying only the last line: Water. This is a minor fix however. From now on the content coordinates are retrieved from the area data only and in future I can easily change the locations of areas if needed. One possible option I can think of already is switching the places of location (bottom line) and messages.

Saturday, 11 January 2014

When it's done

The first item of 10 hour todo list was easy. Then I realized before doing anything else I have to fix the message routine, just like I did for Teemu. This time of course I can use new parts of Teemu's routine, but even then there are work to do with Kaduria's message system. Like with level generation I once thought it would be nice to create a complete engine for messages, but it became too complex and unwieldy for what it was supposed to do. So, rather than trying to make the system work in one way I'm using several different ways that all ultimately use the core routine.

People often ask when Kaduria is ready. It's getting annoying. For a long time I've planned to release the game without telling anyone. Just download the first version in the homepage of Kaduria and let it be there until someone finds it. Let people keep asking when it's released and all the time it's there.

Wednesday, 8 January 2014

News

I have a new plan for Kaduria which is choose some items in todo-list and give them an id and estimated development time. Then follow that order and try to implement them. It should be easy and I already chose ten hours of programming for nine items.

Some items can't be implemented without knowing stuff related to them. It's the difficult part of game programming when you don't have a detailed plan or you don't yet know how stuff is going work with other stuff. It's also something I have to concentrate on better.

Those 9 items are about 20% of all unfinished items in the list, not counting level themes. The reason for that is that level themes are too big to be in todo list anyway, first they have to be broken into smaller pieces, because many level generation techniques are reused in other themes. That 20% is not accurate also because there are more "todos" written in the source code directly.

This new plan should be better than just looking at the source code puzzled what to do next.