Archive

Posts Tagged ‘tcod’

TCOD’s procedural portraits

August 30th, 2010 jice No comments

Source: doryen.eptalys.net


Some of you following this blog since the beginning might remember TCOD’s procedural portraits.
Well the source code is now available on the demos page, along with the complete cheesy 100% developer made artwork. Here are the features :

  • portrait customization

There are 5 templates (male kid, female kid, adult male, adult female, elder male). Each template contains various layers (face, eyes, nose, mouth, …). Each layer can contain versions (to have different haircuts or eye types for a template). There are jewels layers (necklaces, bangles, earrings, …), marks (scars, beauty spots,…).

You can also customize the eyes, nose and mouth position, the complexion and the hair color (everything only works in monochrome though).

  • emotion

Once you defined the portrait (how the character looks like…), you can alter the emotion. Eyes, eyebrows and mouth have several versions. You can change the eyebrows, eyes and pupils position or add tears and “shame blushing”.

Note that not all templates support every feature though. Only the kids have emotion support. The adult female has the most clothes and ornaments layers but no emotion support. The adult male is even simpler and generally looks like a dumb folk singer in pyjama… The elder male has the fewer layers… and no clothes…

The original code uses dynamic font updates to render the portraits but it’s quite buggy. I replaced it with the SDL callback.

TCOD’s weather system !

August 27th, 2010 jice No comments

Source: doryen.eptalys.net

After the cave, it’s now the turn to the original TCOD engine to give away some gems.

For this one, I had to use Linux to squash a nasty memory corruption bug, so the zip contains both windows/mingw and linux binaries and makefiles.
Features :
- day/night cycle
- weather system with
- varying cloud thickness
- varying wind speed and direction
- rain
- lightning

Get it here.

(longish) item gibbering

May 28th, 2010 jice No comments

Source: doryen.eptalys.net

The cave has just went through a major refactoring of the item system. Items are the core of any roguelike and any hack&slash, so you’d better think twice before starting to code their foundation classes. This is the third item system I code and I hope it will last longer than the previous ones.

µstep method (tm)

Fortunately I’ve used advanced µstep method (tm) for this refactoring and it went perfectly smoothly. It took only two evenings and the game never stopped compiling  or even running. So far, there is no visible bug. What I call µstep method is the process of moving the code by tiny steps, having everything compiling and running between every step. Steps should not be bigger than a coding session. For this refactoring, I’ve tried the extreme way and used steps of a few dozens of lines. Of course, you go through some very ugly stage where some items use the new system while the others keep using the old one, but you can stop the refactoring at any moment and work on something else. The game runs, it’s still playable, even releasable even if a nuclear blast is occurring in its core classes. You could believe that it takes longer to do all those steps than blowing everything and rewriting directly some clean new code. Well, my experience showed me that in that case, you may have the first version of the new system sooner, but debugging it will be a real pain and in the end, you’ll have spent more time than with the µstep method.

Item systems

The Chronicles Of Doryen’s system

So what about those three systems ? The first one is from the old “The Chronicles Of Doryen” codebase. I was pretty ambitious then and put all the levers to the max. Of course there is a generic Item class. Each item is associated to an ItemType that describes the item behavior. Item types are organised as a tree, the “root” item type being the, well… root of the tree. Then you have a first level of abstract types of very high level : static, material, general, shields, armors, weapons. Each of these abstract types contains several levels of abstract types before you reach the leafs, actual items. For example, under general, you have food, lights, oils. Food contains ingredient, potions. Weapon contains blades, hammers, staffs, axes. Blades contains daggers, short swords, single handed long blades, two handed long blades.

Organizing the item types in such a hierarchy has several advantages :

  • the game code can easily check if an item belongs to a category. If you want to check if an item is some food, you can simply call item->isA(ItemType::food) instead of having a long list of tests (item->type == carot || item->type == tomato …).
  • abstract types (they could be called ‘categories’) are used to filter the inventory. With this system, you can easily implement an inventory that looks like Windows Explorer, with a hierarchy of directories (abstract types) and files (actual items). In TCOD, the item types config file allows me to define which abstract type is shown in the inventory. I have a few hardcoded filters (all, food, light, armor, shield weapon), but inside a filter, items are still organized as a tree as seen on this screenshot :
  • in the config file, abstract types are not only containers. You can define properties on them that will apply to all sub-types. Maintaining the (huge) config file is easier and there is no duplicated data. Example : a part of the armor configuration :
// ********** ARMORS **********
ItemType "armors" {
abstract
inventory
ascii='['
feature "wear" {}
feature "armor" { when "is_worn" {} }
 ItemType "light armor" {
  abstract
  inventory
  ItemType "leather armor" {
  abstract
    durability=4
    feature "armor" { bonus=10 }
    ItemType "leather leggings" { feature "wear" {body_part="legs"} cost=15 }
    ItemType "leather gloves" { feature "wear" {body_part="hands"} cost=10 }
    ItemType "a leather cuirass" { feature "wear" {body_part="torso"} cost=25 }
    ItemType "a leather helmet" { feature "wear" {body_part="head"} cost=15 }
    ItemType "a leather left bracer" { feature "wear" {body_part="left wrist"} cost=5 }
    ItemType "a leather right bracer" { feature "wear" {body_part="right wrist"} cost=5 }
    ItemType "leather boots" { feature "wear" {body_part="feet"} cost=10 }
  }
}
}

As you can see, the actual item types only use one line because most of the properties are defined on higher level abstract types.

There are no hardcoded item types (like Weapon, Food and so on). ItemType is also a generic class. Distinct behavior in the game come from another class : item features. The item type defines some standard properties of the item : what character is used to represent it, is it stackable and so on. But the most important properties are in the features. Exemple of features are whether the item can be worn or wielded, eaten, can it be de/activated (like a torch), does it deal damages when used, or does it protect it's owner. Each item type contains a list of features and the game checks for known features to implement the correct behaviour.

You can see on the config sample above that armors have two features : "armor" and "wear". Armor means that the owner's armor bonus is increased. "wear" means that it can be worn by the player.

Now TCOD doesn't stop there with a list of hardcoded features like Armor, Wear, Edible, ... No, no. Ambitious I said... Features are also generic! Here is the third level of abstraction. The Feature class defines a generic feature with an id, a name and a list of parameters. That means I can add a new feature in the config file, let's say "BlowIfHit" with some parameters (blowRadius, blowColor) and without changing a line of code (except the config file parser), the feature is available in the game. Of course you have to add some code to actually implement this feature (if item->hasFeature("BlowIfHit") then trigger explosion), but you don't need to code the BlowIfHit class.

Now generic Feature is pretty complex to implements, because a feature has static parameters (defined on the item type) and dynamic parameters (defined on the item because they change over time). For example, a torch light radius is defined on the torch item type, but it has also to be stored on the torch item because it will decrease over time until the torch is burnt away.

Features also have conditions. For example an armor has "armor" and "wear" features, but both features are linked with a condition (when "is_worn"). That means the armor bonus is only active if the item is worn.

This whole stack of generic classes really works pretty well, but that's a lot of code with high level of abstraction. Leave it a few months and you don't understand it anymore. Read it for the first time and you're completely lost.

Pyromancer ! system

Pyromancer ! is a 7DRL so I took the exact opposite direction : straightforward approach with everything hardcoded. A class for each item. For small size projects, you can't make simpler. Of course, you probably still need an Item base class to avoid duplicating all the code.

The cave's items

The cave is based on pyromancer! source code, so it started with the same design. But it reached the size where this design cannot stand the requirements anymore, hence the refactoring. I didn't reimplement the whole TCOD stuff though. I still use Item, ItemType and ItemFeature classes, but now features are hardcoded, with a class for each feature. I also dropped the item type hierarchy is favor of something simpler and more powerful : tags.

The main inconvient with TCOD's hierarchy is that an item belongs only to one branch of the tree. For example, an item can be an ingredient (food branch) or a material, but not both. Tags are more versatile :

  • You can apply any number of tags to each non abstract item type.
  • Tags are used in the config file like preprocessor macros in C. All of the tag's properties are copied into any item type containing the tag.
  • Tags are not necessarily linked to each other. Getting the properties of a blade does not mean that you have to get the properties of a weapon.
  • But you can still organize tags in hierarchy. In that case, you get the same behavior as TCOD's type hierarchy.
  • In the game engine, tags are reduced to a bitfield used to classify the items with a TCOD-like isA() function, but you can now have overlapping hierarchies instead of a single one.

With tags, TCOD armor config file would look like this :

// ********** ARMORS **********

ItemTag "armor" {

    inventory

    ascii='['

    feature "wear" {}

    feature "armor" { when "is_worn" {} }

	ItemTag "light armor" {

        inventory

		ItemTag "leather armor" {

		    durability=4

		    feature "armor" { bonus=10 }
		}
	}
}

ItemType "leather leggings" { tags=["leather armor"] feature "wear" {body_part="legs"} cost=15 }
Or like that :
// ********** ARMORS **********

ItemTag "armor" {

    inventory

    ascii='['

    feature "wear" {}

    feature "armor" { when "is_worn" {} }
}

ItemTag "light armor" {

      inventory
}

ItemTag "leather armor" {

    durability=4

    feature "armor" { bonus=10 }
}

ItemType "leather leggings" { tags=["armor","light armor","leather armor"] feature "wear" {body_part="legs"} cost=15 }
I find this system more powerful, and it has a simpler data structure.

If you’re still reading, you earn a free phoenix flying mount usable in the first release of TCOD, to be released Q3 2046. :D