added saving native BDCFF file with cheat code ":save-native-level"
[rocksndiamonds.git] / src / game_bd / bd_cavedb.c
index 781deab58949ccc0d34508397ec6e9f727cf4009..ac334aeaac73a69e7a7c838b1380817b5248e2a2 100644 (file)
@@ -14,9 +14,6 @@
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
-#include <glib.h>
-#include <glib/gi18n.h>
-
 #include "main_bd.h"
 
 
@@ -314,11 +311,11 @@ GdElements gd_elements[] =
   { O_PRE_DIA_3, N_("Diamond birth (3)"), 0, "DIAMONDBIRTH3", 0, 58, 58, 58, 280 },    /* has ckdelay */
   { O_PRE_DIA_4, N_("Diamond birth (4)"), 0, "DIAMONDBIRTH4", 0, 59, 59, 59, 280 },    /* has ckdelay */
   { O_PRE_DIA_5, N_("Diamond birth (5)"), 0, "DIAMONDBIRTH5", 0, 60, 60, 60, 280 },    /* has ckdelay */
-  { O_EXPLODE_1, N_("Explosion (1)"), P_EXPLOSION_FIRST_STAGE, "EXPLOSION1", 0, 43, 43, 43, 280 },    /* has ckdelay */
-  { O_EXPLODE_2, N_("Explosion (2)"), 0, "EXPLOSION2", 0, 44, 44, 44, 280 },    /* has ckdelay */
-  { O_EXPLODE_3, N_("Explosion (3)"), 0, "EXPLOSION3", 0, 45, 45, 45, 280 },    /* has ckdelay */
-  { O_EXPLODE_4, N_("Explosion (4)"), 0, "EXPLOSION4", 0, 46, 46, 46, 280 },    /* has ckdelay */
-  { O_EXPLODE_5, N_("Explosion (5)"), 0, "EXPLOSION5", 0, 47, 47, 47, 280 },    /* has ckdelay */
+  { O_EXPLODE_1, N_("Explosion (1)"), P_EXPLOSION | P_EXPLOSION_FIRST_STAGE, "EXPLOSION1", 0, 43, 43, 43, 280 },    /* has ckdelay */
+  { O_EXPLODE_2, N_("Explosion (2)"), P_EXPLOSION, "EXPLOSION2", 0, 44, 44, 44, 280 },    /* has ckdelay */
+  { O_EXPLODE_3, N_("Explosion (3)"), P_EXPLOSION, "EXPLOSION3", 0, 45, 45, 45, 280 },    /* has ckdelay */
+  { O_EXPLODE_4, N_("Explosion (4)"), P_EXPLOSION, "EXPLOSION4", 0, 46, 46, 46, 280 },    /* has ckdelay */
+  { O_EXPLODE_5, N_("Explosion (5)"), P_EXPLOSION, "EXPLOSION5", 0, 47, 47, 47, 280 },    /* has ckdelay */
   { O_PRE_STONE_1, N_("Stone birth (1)"), P_EXPLOSION_FIRST_STAGE, "BOULDERBIRTH1", 0, 36, 36, 36, 280 },    /* has ckdelay */
   { O_PRE_STONE_2, N_("Stone birth (2)"), 0, "BOULDERBIRTH2", 0, 37, 37, 37, 280 },    /* has ckdelay */
   { O_PRE_STONE_3, N_("Stone birth (3)"), 0, "BOULDERBIRTH3", 0, 38, 38, 38, 280 },    /* has ckdelay */
@@ -327,26 +324,26 @@ GdElements gd_elements[] =
   { O_PRE_STEEL_2, N_("Steel birth (2)"), 0, "STEELWALLBIRTH2", 0, 25, 25, 25, 280 },    /* has ckdelay */
   { O_PRE_STEEL_3, N_("Steel birth (3)"), 0, "STEELWALLBIRTH3", 0, 26, 26, 26, 280 },    /* has ckdelay */
   { O_PRE_STEEL_4, N_("Steel birth (4)"), 0, "STEELWALLBIRTH4", 0, 27, 27, 27, 280 },    /* has ckdelay */
-  { O_GHOST_EXPL_1, N_("Ghost explosion (1)"), P_EXPLOSION_FIRST_STAGE, "GHOSTEXPLOSION1", 0, 80, 80, 80, 280 },    /* has ckdelay */
-  { O_GHOST_EXPL_2, N_("Ghost explosion (2)"), 0, "GHOSTEXPLOSION2", 0, 81, 81, 81, 280 },    /* has ckdelay */
-  { O_GHOST_EXPL_3, N_("Ghost explosion (3)"), 0, "GHOSTEXPLOSION3", 0, 82, 82, 82, 280 },    /* has ckdelay */
-  { O_GHOST_EXPL_4, N_("Ghost explosion (4)"), 0, "GHOSTEXPLOSION4", 0, 83, 83, 83, 280 },    /* has ckdelay */
-  { O_BOMB_EXPL_1, N_("Bomb explosion (1)"), P_EXPLOSION_FIRST_STAGE, "BOMBEXPLOSION1", 0, 84, 84, 84, 280 },    /* has ckdelay */
-  { O_BOMB_EXPL_2, N_("Bomb explosion (2)"), 0, "BOMBEXPLOSION2", 0, 85, 85, 85, 280 },    /* has ckdelay */
-  { O_BOMB_EXPL_3, N_("Bomb explosion (3)"), 0, "BOMBEXPLOSION3", 0, 86, 86, 86, 280 },    /* has ckdelay */
-  { O_BOMB_EXPL_4, N_("Bomb explosion (4)"), 0, "BOMBEXPLOSION4", 0, 87, 87, 87, 280 },    /* has ckdelay */
-  { O_NITRO_EXPL_1, N_("Nitro pack explosion (1)"), P_EXPLOSION_FIRST_STAGE, "NITROEXPLOSION1", 0, 44, 44, 44, 280 },    /* has ckdelay */
-  { O_NITRO_EXPL_2, N_("Nitro pack explosion (2)"), 0, "NITROEXPLOSION2", 0, 45, 45, 45, 280 },    /* has ckdelay */
-  { O_NITRO_EXPL_3, N_("Nitro pack explosion (3)"), 0, "NITROEXPLOSION3", 0, 46, 46, 46, 280 },    /* has ckdelay */
-  { O_NITRO_EXPL_4, N_("Nitro pack explosion (4)"), 0, "NITROEXPLOSION4", 0, 47, 47, 47, 280 },    /* has ckdelay */
-  { O_AMOEBA_2_EXPL_1, N_("Amoeba 2 explosion (1)"), P_EXPLOSION_FIRST_STAGE, "AMOEBA2EXPLOSION1", 0, 292, 292, 292, 280 },    /* has ckdelay */
-  { O_AMOEBA_2_EXPL_2, N_("Amoeba 2 explosion (2)"), 0, "AMOEBA2EXPLOSION2", 0, 293, 293, 293, 280 },    /* has ckdelay */
-  { O_AMOEBA_2_EXPL_3, N_("Amoeba 2 explosion (3)"), 0, "AMOEBA2EXPLOSION3", 0, 294, 294, 294, 280 },    /* has ckdelay */
-  { O_AMOEBA_2_EXPL_4, N_("Amoeba 2 explosion (4)"), 0, "AMOEBA2EXPLOSION4", 0, 295, 295, 295, 280 },    /* has ckdelay */
-  { O_NUT_EXPL_1, N_("Nut explosion (1)"), P_SLOPED | P_EXPLOSION_FIRST_STAGE, "NUTEXPLOSION1", 0, 360, 360, 360, 280 },    /* has ckdelay */
-  { O_NUT_EXPL_2, N_("Nut explosion (2)"), P_SLOPED, "NUTEXPLOSION2", 0, 361, 361, 361, 280 },    /* has ckdelay */        /* these are rounded!! */
-  { O_NUT_EXPL_3, N_("Nut explosion (3)"), P_SLOPED, "NUTEXPLOSION3", 0, 362, 362, 362, 280 },    /* has ckdelay */
-  { O_NUT_EXPL_4, N_("Nut explosion (4)"), P_SLOPED, "NUTEXPLOSION4", 0, 363, 363, 363, 280 },    /* has ckdelay */
+  { O_GHOST_EXPL_1, N_("Ghost explosion (1)"), P_EXPLOSION | P_EXPLOSION_FIRST_STAGE, "GHOSTEXPLOSION1", 0, 80, 80, 80, 280 },    /* has ckdelay */
+  { O_GHOST_EXPL_2, N_("Ghost explosion (2)"), P_EXPLOSION, "GHOSTEXPLOSION2", 0, 81, 81, 81, 280 },    /* has ckdelay */
+  { O_GHOST_EXPL_3, N_("Ghost explosion (3)"), P_EXPLOSION, "GHOSTEXPLOSION3", 0, 82, 82, 82, 280 },    /* has ckdelay */
+  { O_GHOST_EXPL_4, N_("Ghost explosion (4)"), P_EXPLOSION, "GHOSTEXPLOSION4", 0, 83, 83, 83, 280 },    /* has ckdelay */
+  { O_BOMB_EXPL_1, N_("Bomb explosion (1)"), P_EXPLOSION | P_EXPLOSION_FIRST_STAGE, "BOMBEXPLOSION1", 0, 84, 84, 84, 280 },    /* has ckdelay */
+  { O_BOMB_EXPL_2, N_("Bomb explosion (2)"), P_EXPLOSION, "BOMBEXPLOSION2", 0, 85, 85, 85, 280 },    /* has ckdelay */
+  { O_BOMB_EXPL_3, N_("Bomb explosion (3)"), P_EXPLOSION, "BOMBEXPLOSION3", 0, 86, 86, 86, 280 },    /* has ckdelay */
+  { O_BOMB_EXPL_4, N_("Bomb explosion (4)"), P_EXPLOSION, "BOMBEXPLOSION4", 0, 87, 87, 87, 280 },    /* has ckdelay */
+  { O_NITRO_EXPL_1, N_("Nitro pack explosion (1)"), P_EXPLOSION | P_EXPLOSION_FIRST_STAGE, "NITROEXPLOSION1", 0, 44, 44, 44, 280 },    /* has ckdelay */
+  { O_NITRO_EXPL_2, N_("Nitro pack explosion (2)"), P_EXPLOSION, "NITROEXPLOSION2", 0, 45, 45, 45, 280 },    /* has ckdelay */
+  { O_NITRO_EXPL_3, N_("Nitro pack explosion (3)"), P_EXPLOSION, "NITROEXPLOSION3", 0, 46, 46, 46, 280 },    /* has ckdelay */
+  { O_NITRO_EXPL_4, N_("Nitro pack explosion (4)"), P_EXPLOSION, "NITROEXPLOSION4", 0, 47, 47, 47, 280 },    /* has ckdelay */
+  { O_AMOEBA_2_EXPL_1, N_("Amoeba 2 explosion (1)"), P_EXPLOSION | P_EXPLOSION_FIRST_STAGE, "AMOEBA2EXPLOSION1", 0, 292, 292, 292, 280 },    /* has ckdelay */
+  { O_AMOEBA_2_EXPL_2, N_("Amoeba 2 explosion (2)"), P_EXPLOSION, "AMOEBA2EXPLOSION2", 0, 293, 293, 293, 280 },    /* has ckdelay */
+  { O_AMOEBA_2_EXPL_3, N_("Amoeba 2 explosion (3)"), P_EXPLOSION, "AMOEBA2EXPLOSION3", 0, 294, 294, 294, 280 },    /* has ckdelay */
+  { O_AMOEBA_2_EXPL_4, N_("Amoeba 2 explosion (4)"), P_EXPLOSION, "AMOEBA2EXPLOSION4", 0, 295, 295, 295, 280 },    /* has ckdelay */
+  { O_NUT_EXPL_1, N_("Nut explosion (1)"), P_SLOPED | P_EXPLOSION | P_EXPLOSION_FIRST_STAGE, "NUTEXPLOSION1", 0, 360, 360, 360, 280 },    /* has ckdelay */
+  { O_NUT_EXPL_2, N_("Nut explosion (2)"), P_SLOPED | P_EXPLOSION, "NUTEXPLOSION2", 0, 361, 361, 361, 280 },    /* has ckdelay */        /* these are rounded!! */
+  { O_NUT_EXPL_3, N_("Nut explosion (3)"), P_SLOPED | P_EXPLOSION, "NUTEXPLOSION3", 0, 362, 362, 362, 280 },    /* has ckdelay */
+  { O_NUT_EXPL_4, N_("Nut explosion (4)"), P_SLOPED | P_EXPLOSION, "NUTEXPLOSION4", 0, 363, 363, 363, 280 },    /* has ckdelay */
 
   { O_PLAYER_PNEUMATIC_LEFT, NULL /* Player using hammer, left */, P_BLOWS_UP_FLIES | P_EXPLODES_BY_HIT | P_PLAYER, "GUYHAMMERl", 0, 265, 265, 265 },
   { O_PLAYER_PNEUMATIC_RIGHT, NULL /* Player using hammer, right */, P_BLOWS_UP_FLIES | P_EXPLODES_BY_HIT | P_PLAYER, "GUYHAMMERr", 0, 268, 268, 268 },
@@ -410,40 +407,40 @@ const GdStructDescriptor gd_cave_properties[] =
 {
   /* default data */
   {"", GD_TAB, 0, N_("Cave data")},
-  {"Name", GD_TYPE_STRING, 0, N_("Name"), G_STRUCT_OFFSET(GdCave, name), 1, N_("Name of game")},
-  {"Description", GD_TYPE_STRING, 0, N_("Description"), G_STRUCT_OFFSET(GdCave, description), 1, N_("Some words about the game")},
-  {"Author", GD_TYPE_STRING, 0, N_("Author"), G_STRUCT_OFFSET(GdCave, author), 1, N_("Name of author")},
-  {"Date", GD_TYPE_STRING, 0, N_("Date"), G_STRUCT_OFFSET(GdCave, date), 1, N_("Date of creation")},
-  {"WWW", GD_TYPE_STRING, 0, N_("WWW"), G_STRUCT_OFFSET(GdCave, www), 1, N_("Web page or e-mail address")},
-  {"Difficulty", GD_TYPE_STRING, 0, N_("Difficulty"), G_STRUCT_OFFSET(GdCave, difficulty), 1, N_("Difficulty (informative)")},
-
-  {"Selectable", GD_TYPE_BOOLEAN, 0, N_("Selectable as start"), G_STRUCT_OFFSET(GdCave, selectable), 1, N_("This sets whether the game can be started at this cave.")},
-  {"Intermission", GD_TYPE_BOOLEAN, GD_ALWAYS_SAVE, N_("Intermission"), G_STRUCT_OFFSET(GdCave, intermission), 1, N_("Intermission caves are usually small and fast caves, which are not required to be solved. The player will not lose a life if he is not successful. The game always proceeds to the next cave.")},
-  {"IntermissionProperties.instantlife", GD_TYPE_BOOLEAN, 0, N_("   Instant life"), G_STRUCT_OFFSET(GdCave, intermission_instantlife), 1, N_("If true, an extra life is given to the player, when the intermission cave is reached.")},
-  {"IntermissionProperties.rewardlife", GD_TYPE_BOOLEAN, 0, N_("   Reward life"), G_STRUCT_OFFSET(GdCave, intermission_rewardlife), 1, N_("If true, an extra life is given to the player, when the intermission cave is successfully finished.")},
-  {"Size", GD_TYPE_INT, GD_ALWAYS_SAVE, N_("Width"), G_STRUCT_OFFSET(GdCave, w), 1, N_("Width of cave. The standard size for a cave is 40x22, and 20x12 for an intermission."), 12, 128},
-  {"Size", GD_TYPE_INT, GD_ALWAYS_SAVE, N_("Height"), G_STRUCT_OFFSET(GdCave, h), 1, N_("Height of cave. The standard size for a cave is 40x22, and 20x12 for an intermission."), 12, 128},
-  {"Size", GD_TYPE_INT, GD_ALWAYS_SAVE|GD_DONT_SHOW_IN_EDITOR, N_("Visible, left"), G_STRUCT_OFFSET(GdCave, x1), 1, N_("Visible parts of the cave, upper left and lower right corner."), 0, 127},
-  {"Size", GD_TYPE_INT, GD_ALWAYS_SAVE|GD_DONT_SHOW_IN_EDITOR, N_("Visible, upper"), G_STRUCT_OFFSET(GdCave, y1), 1, N_("Visible parts of the cave, upper left and lower right corner."), 0, 127},
-  {"Size", GD_TYPE_INT, GD_ALWAYS_SAVE|GD_DONT_SHOW_IN_EDITOR, N_("Visible, right"), G_STRUCT_OFFSET(GdCave, x2), 1, N_("Visible parts of the cave, upper left and lower right corner."), 0, 127},
-  {"Size", GD_TYPE_INT, GD_ALWAYS_SAVE|GD_DONT_SHOW_IN_EDITOR, N_("Visible, lower"), G_STRUCT_OFFSET(GdCave, y2), 1, N_("Visible parts of the cave, upper left and lower right corner."), 0, 127},
-  {"Charset", GD_TYPE_STRING, 0, N_("Character set"), G_STRUCT_OFFSET(GdCave, charset), 1, N_("Theme used for displaying the game. Not used by GDash.")},
-  {"Fontset", GD_TYPE_STRING, 0, N_("Font set"), G_STRUCT_OFFSET(GdCave, fontset), 1, N_("Font used during the game. Not used by GDash.")},
+  {"Name", GD_TYPE_STRING, 0, N_("Name"), STRUCT_OFFSET(GdCave, name), 1, N_("Name of game")},
+  {"Description", GD_TYPE_STRING, 0, N_("Description"), STRUCT_OFFSET(GdCave, description), 1, N_("Some words about the game")},
+  {"Author", GD_TYPE_STRING, 0, N_("Author"), STRUCT_OFFSET(GdCave, author), 1, N_("Name of author")},
+  {"Date", GD_TYPE_STRING, 0, N_("Date"), STRUCT_OFFSET(GdCave, date), 1, N_("Date of creation")},
+  {"WWW", GD_TYPE_STRING, 0, N_("WWW"), STRUCT_OFFSET(GdCave, www), 1, N_("Web page or e-mail address")},
+  {"Difficulty", GD_TYPE_STRING, 0, N_("Difficulty"), STRUCT_OFFSET(GdCave, difficulty), 1, N_("Difficulty (informative)")},
+
+  {"Selectable", GD_TYPE_BOOLEAN, 0, N_("Selectable as start"), STRUCT_OFFSET(GdCave, selectable), 1, N_("This sets whether the game can be started at this cave.")},
+  {"Intermission", GD_TYPE_BOOLEAN, GD_ALWAYS_SAVE, N_("Intermission"), STRUCT_OFFSET(GdCave, intermission), 1, N_("Intermission caves are usually small and fast caves, which are not required to be solved. The player will not lose a life if he is not successful. The game always proceeds to the next cave.")},
+  {"IntermissionProperties.instantlife", GD_TYPE_BOOLEAN, 0, N_("   Instant life"), STRUCT_OFFSET(GdCave, intermission_instantlife), 1, N_("If true, an extra life is given to the player, when the intermission cave is reached.")},
+  {"IntermissionProperties.rewardlife", GD_TYPE_BOOLEAN, 0, N_("   Reward life"), STRUCT_OFFSET(GdCave, intermission_rewardlife), 1, N_("If true, an extra life is given to the player, when the intermission cave is successfully finished.")},
+  {"Size", GD_TYPE_INT, GD_ALWAYS_SAVE, N_("Width"), STRUCT_OFFSET(GdCave, w), 1, N_("Width of cave. The standard size for a cave is 40x22, and 20x12 for an intermission."), 12, 128},
+  {"Size", GD_TYPE_INT, GD_ALWAYS_SAVE, N_("Height"), STRUCT_OFFSET(GdCave, h), 1, N_("Height of cave. The standard size for a cave is 40x22, and 20x12 for an intermission."), 12, 128},
+  {"Size", GD_TYPE_INT, GD_ALWAYS_SAVE|GD_DONT_SHOW_IN_EDITOR, N_("Visible, left"), STRUCT_OFFSET(GdCave, x1), 1, N_("Visible parts of the cave, upper left and lower right corner."), 0, 127},
+  {"Size", GD_TYPE_INT, GD_ALWAYS_SAVE|GD_DONT_SHOW_IN_EDITOR, N_("Visible, upper"), STRUCT_OFFSET(GdCave, y1), 1, N_("Visible parts of the cave, upper left and lower right corner."), 0, 127},
+  {"Size", GD_TYPE_INT, GD_ALWAYS_SAVE|GD_DONT_SHOW_IN_EDITOR, N_("Visible, right"), STRUCT_OFFSET(GdCave, x2), 1, N_("Visible parts of the cave, upper left and lower right corner."), 0, 127},
+  {"Size", GD_TYPE_INT, GD_ALWAYS_SAVE|GD_DONT_SHOW_IN_EDITOR, N_("Visible, lower"), STRUCT_OFFSET(GdCave, y2), 1, N_("Visible parts of the cave, upper left and lower right corner."), 0, 127},
+  {"Charset", GD_TYPE_STRING, 0, N_("Character set"), STRUCT_OFFSET(GdCave, charset), 1, N_("Theme used for displaying the game. Not used by GDash.")},
+  {"Fontset", GD_TYPE_STRING, 0, N_("Font set"), STRUCT_OFFSET(GdCave, fontset), 1, N_("Font used during the game. Not used by GDash.")},
 
   /* notes - a tab on its own */
-  {"Story", GD_TYPE_LONGSTRING, 0, N_("Story"), G_STRUCT_OFFSET(GdCave, story), 1, N_("Story for the cave. It will be shown when the cave is played.")},
+  {"Story", GD_TYPE_LONGSTRING, 0, N_("Story"), STRUCT_OFFSET(GdCave, story), 1, N_("Story for the cave. It will be shown when the cave is played.")},
 
   /* remark - also a tab on its own */
-  {"Remark", GD_TYPE_LONGSTRING, 0, N_("Remark"), G_STRUCT_OFFSET(GdCave, remark), 1, N_("Remark (informative). Can contain supplementary information about the design of the cave. It is not shown during the game, only when the user requests the cave info dialog, so can also contain spoilers and hints.")},
+  {"Remark", GD_TYPE_LONGSTRING, 0, N_("Remark"), STRUCT_OFFSET(GdCave, remark), 1, N_("Remark (informative). Can contain supplementary information about the design of the cave. It is not shown during the game, only when the user requests the cave info dialog, so can also contain spoilers and hints.")},
 
   {"", GD_TAB, 0, N_("Colors")},
-  {"Colors", GD_TYPE_COLOR, GD_ALWAYS_SAVE, N_("Border color"), G_STRUCT_OFFSET(GdCave, colorb), 1, N_("Border color for C64 graphics. Only for compatibility, not used by GDash.")},
-  {"Colors", GD_TYPE_COLOR, GD_ALWAYS_SAVE, N_("Background color"), G_STRUCT_OFFSET(GdCave, color0), 1, N_("Background color for C64 graphics")},
-  {"Colors", GD_TYPE_COLOR, GD_ALWAYS_SAVE, N_("Color 1 (dirt)"), G_STRUCT_OFFSET(GdCave, color1), 1, N_("Foreground color 1 for C64 graphics")},
-  {"Colors", GD_TYPE_COLOR, GD_ALWAYS_SAVE, N_("Color 2 (steel wall)"), G_STRUCT_OFFSET(GdCave, color2), 1, N_("Foreground color 2 for C64 graphics")},
-  {"Colors", GD_TYPE_COLOR, GD_ALWAYS_SAVE, N_("Color 3 (brick wall)"), G_STRUCT_OFFSET(GdCave, color3), 1, N_("Foreground color 3 for C64 graphics")},
-  {"Colors", GD_TYPE_COLOR, GD_ALWAYS_SAVE, N_("Amoeba color"), G_STRUCT_OFFSET(GdCave, color4), 1, N_("Amoeba color for C64 graphics")},
-  {"Colors", GD_TYPE_COLOR, GD_ALWAYS_SAVE, N_("Slime color"), G_STRUCT_OFFSET(GdCave, color5), 1, N_("Slime color for C64 graphics")},
+  {"Colors", GD_TYPE_COLOR, GD_ALWAYS_SAVE, N_("Border color"), STRUCT_OFFSET(GdCave, colorb), 1, N_("Border color for C64 graphics. Only for compatibility, not used by GDash.")},
+  {"Colors", GD_TYPE_COLOR, GD_ALWAYS_SAVE, N_("Background color"), STRUCT_OFFSET(GdCave, color0), 1, N_("Background color for C64 graphics")},
+  {"Colors", GD_TYPE_COLOR, GD_ALWAYS_SAVE, N_("Color 1 (dirt)"), STRUCT_OFFSET(GdCave, color1), 1, N_("Foreground color 1 for C64 graphics")},
+  {"Colors", GD_TYPE_COLOR, GD_ALWAYS_SAVE, N_("Color 2 (steel wall)"), STRUCT_OFFSET(GdCave, color2), 1, N_("Foreground color 2 for C64 graphics")},
+  {"Colors", GD_TYPE_COLOR, GD_ALWAYS_SAVE, N_("Color 3 (brick wall)"), STRUCT_OFFSET(GdCave, color3), 1, N_("Foreground color 3 for C64 graphics")},
+  {"Colors", GD_TYPE_COLOR, GD_ALWAYS_SAVE, N_("Amoeba color"), STRUCT_OFFSET(GdCave, color4), 1, N_("Amoeba color for C64 graphics")},
+  {"Colors", GD_TYPE_COLOR, GD_ALWAYS_SAVE, N_("Slime color"), STRUCT_OFFSET(GdCave, color5), 1, N_("Slime color for C64 graphics")},
 
   /* difficulty */
   {"", GD_TAB, 0, N_("Difficulty")},
@@ -676,17 +673,17 @@ const GdStructDescriptor gd_replay_properties[] =
 {
   /* default data */
   {"", GD_TAB, 0, N_("Replay")},
-  {"Level", GD_TYPE_INT, 0, NULL, G_STRUCT_OFFSET(GdReplay, level), 1, NULL},
-  {"RandomSeed", GD_TYPE_INT, 0, NULL, G_STRUCT_OFFSET(GdReplay, seed), 1, NULL},
-  //    {"Saved", GD_TYPE_BOOLEAN, 0, NULL, G_STRUCT_OFFSET(GdReplay, saved), 1, NULL},        /* no need to state in bdcff, as saved replays are saved ones :) */
-  {"Player", GD_TYPE_STRING, 0, NULL, G_STRUCT_OFFSET(GdReplay, player_name), 1, NULL},
-  {"Date", GD_TYPE_STRING, 0, NULL, G_STRUCT_OFFSET(GdReplay, date), 1, NULL},
-  {"Comment", GD_TYPE_LONGSTRING, 0, NULL, G_STRUCT_OFFSET(GdReplay, comment), 1, NULL},
-  {"RecordedWith", GD_TYPE_STRING, 0, NULL, G_STRUCT_OFFSET(GdReplay, recorded_with), 1, NULL},
-  {"Score", GD_TYPE_INT, 0, NULL, G_STRUCT_OFFSET(GdReplay, score), 1, NULL},
-  {"Duration", GD_TYPE_INT, 0, NULL, G_STRUCT_OFFSET(GdReplay, duration), 1, NULL},
-  {"Success", GD_TYPE_BOOLEAN, 0, NULL, G_STRUCT_OFFSET(GdReplay, success), 1, NULL},
-  {"Checksum", GD_TYPE_INT, 0, NULL, G_STRUCT_OFFSET(GdReplay, checksum), 1, NULL},
+  {"Level", GD_TYPE_INT, 0, NULL, STRUCT_OFFSET(GdReplay, level), 1, NULL},
+  {"RandomSeed", GD_TYPE_INT, 0, NULL, STRUCT_OFFSET(GdReplay, seed), 1, NULL},
+  //    {"Saved", GD_TYPE_BOOLEAN, 0, NULL, STRUCT_OFFSET(GdReplay, saved), 1, NULL},        /* no need to state in bdcff, as saved replays are saved ones :) */
+  {"Player", GD_TYPE_STRING, 0, NULL, STRUCT_OFFSET(GdReplay, player_name), 1, NULL},
+  {"Date", GD_TYPE_STRING, 0, NULL, STRUCT_OFFSET(GdReplay, date), 1, NULL},
+  {"Comment", GD_TYPE_LONGSTRING, 0, NULL, STRUCT_OFFSET(GdReplay, comment), 1, NULL},
+  {"RecordedWith", GD_TYPE_STRING, 0, NULL, STRUCT_OFFSET(GdReplay, recorded_with), 1, NULL},
+  {"Score", GD_TYPE_INT, 0, NULL, STRUCT_OFFSET(GdReplay, score), 1, NULL},
+  {"Duration", GD_TYPE_INT, 0, NULL, STRUCT_OFFSET(GdReplay, duration), 1, NULL},
+  {"Success", GD_TYPE_BOOLEAN, 0, NULL, STRUCT_OFFSET(GdReplay, success), 1, NULL},
+  {"Checksum", GD_TYPE_INT, 0, NULL, STRUCT_OFFSET(GdReplay, checksum), 1, NULL},
 
   {NULL}  /* end of array */
 };
@@ -930,7 +927,7 @@ GdElement gd_element_get_hammered(GdElement elem)
 void gd_cave_db_init(void)
 {
   int i;
-  GHashTable *pointers;
+  HashTable *pointers;
   boolean lowercase_names = TRUE;
 
   /* TRANSLATORS: some languages (for example, german) do not have lowercase nouns. */
@@ -949,10 +946,10 @@ void gd_cave_db_init(void)
     lowercase_names = FALSE;
 
   /* check element database for faults. */
-  for (i = 0; gd_elements[i].element!=-1; i++)
+  for (i = 0; gd_elements[i].element != -1; i++)
   {
     if (gd_elements[i].element != i)
-      Error("element: i:0x%x!=0x%x", i, gd_elements[i].element);
+      Error("element: i:0x%x != 0x%x", i, gd_elements[i].element);
 
     /* if it has a name, create a lowercase name (of the translated one).
        will be used by the editor */
@@ -960,20 +957,20 @@ void gd_cave_db_init(void)
     {
       if (lowercase_names)
        /* the function allocates a new string, but it is needed as long as the app is running */
-       gd_elements[i].lowercase_name = g_utf8_strdown(gettext(gd_elements[i].name), -1);
+       gd_elements[i].lowercase_name = getStringToLower(gettext(gd_elements[i].name));
       else
        /* only translate, no lowercase. */
        gd_elements[i].lowercase_name = gettext(gd_elements[i].name);
     }
 
     /* we do not like generated pixbufs for games. only those that are in the png. */
-    if (ABS(gd_elements[i].image_game)>GD_NUM_OF_CELLS_X*GD_NUM_OF_CELLS_Y)
+    if (ABS(gd_elements[i].image_game) > GD_NUM_OF_CELLS_X * GD_NUM_OF_CELLS_Y)
       Error("game pixbuf for element %x (%s) bigger than png size", i, gd_elements[i].name);
 
     if (gd_elements[i].image < 0)
       Error("editor pixbuf for element %x (%s) should not be animated", i, gd_elements[i].name);
 
-    if (gd_elements[i].properties&P_CAN_BE_HAMMERED && gd_element_get_hammered((GdElement) i) == O_NONE)
+    if (gd_elements[i].properties & P_CAN_BE_HAMMERED && gd_element_get_hammered((GdElement) i) == O_NONE)
       Error("element %x (%s) can be hammered, but get_hammered_element does not define another one", i, gd_elements[i].name);
   }
 
@@ -1000,7 +997,7 @@ void gd_cave_db_init(void)
   */
 
   /* check the cave property database for faults. */
-  pointers = g_hash_table_new(g_direct_hash, g_direct_equal);
+  pointers = create_hashtable(get_hash_from_integer, hash_key_integers_are_equal, NULL, NULL);
 
   for (i = 0; gd_cave_properties[i].identifier != NULL; i++)
   {
@@ -1072,14 +1069,15 @@ void gd_cave_db_init(void)
       /* other types */
       /* check if its pointer is not the same as another one's */
       /* +1 is added so it is never zero */
-      if (!(gd_cave_properties[i].flags&GD_DONT_SAVE) && strcmp(gd_cave_properties[i].identifier, "") == 0)
+      if (!(gd_cave_properties[i].flags & GD_DONT_SAVE) && strcmp(gd_cave_properties[i].identifier, "") == 0)
       {
        Error ("property should have a bdcff identifier: line %d, name %s",
               i, gd_cave_properties[i].name);
       }
 
-      another_prop = g_hash_table_lookup(pointers, GINT_TO_POINTER(gd_cave_properties[i].offset + 1));
-      if (another_prop!=NULL)
+      another_prop = hashtable_search(pointers, INT_TO_PTR(gd_cave_properties[i].offset + 1));
+
+      if (another_prop != NULL)
       {
        Error("property %s has the same pointer as property %s",
              gd_cave_properties[i].identifier, another_prop);
@@ -1087,11 +1085,11 @@ void gd_cave_db_init(void)
       else
       {
        /* value is the identifier, so we can report the OLD one if the check fails */
-       g_hash_table_insert(pointers, GINT_TO_POINTER(gd_cave_properties[i].offset + 1),
-                           gd_cave_properties[i].identifier);
+       hashtable_insert(pointers, INT_TO_PTR(gd_cave_properties[i].offset + 1),
+                        gd_cave_properties[i].identifier);
       }
     }
   }
 
-  g_hash_table_destroy(pointers);
+  hashtable_destroy(pointers);
 }