20081227
[gdash.git] / src / cavedb.c
blobc8fbc938184abb2666b8730c1b11c71d445babf6
1 /*
2 * Copyright (c) 2007, 2008 Czirkos Zoltan <cirix@fw.hu>
4 * Permission to use, copy, modify, and distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 #include <glib.h>
18 #include <glib/gi18n.h>
19 #include <string.h>
20 #include "cavedb.h"
24 /* elements description array. do not miss an index!
25 the game will check if one is missing and stop the game.
26 the identifier in the saved file might also not match, reading an "outbox" from
27 the file should store an O_PRE_OUTBOX.
29 images are: image in editor, image in editor - animated, game image
31 GdElements gd_elements[] = {
32 {O_SPACE, N_("Space"), P_AMOEBA_CONSUMES, "SPACE", ' ', 0, 0, 0},
33 {O_DIRT, N_("Dirt"), P_AMOEBA_CONSUMES|P_VISUAL_EFFECT|P_DIRT, "DIRT", '.', 2, 2, 2},
34 {O_DIRT_SLOPED_UP_RIGHT, N_("Sloped dirt (up & right)"), P_DIRT|P_SLOPED_UP|P_SLOPED_RIGHT|P_AMOEBA_CONSUMES, "DIRTSLOPEDUPRIGHT", 0, 280, 280, 280},
35 {O_DIRT_SLOPED_UP_LEFT, N_("Sloped dirt (up & left)"), P_DIRT|P_SLOPED_UP|P_SLOPED_LEFT|P_AMOEBA_CONSUMES, "DIRTSLOPEDUPLEFT", 0, 281, 281, 281},
36 {O_DIRT_SLOPED_DOWN_LEFT, N_("Sloped dirt (down & left)"), P_DIRT|P_SLOPED_DOWN|P_SLOPED_LEFT|P_AMOEBA_CONSUMES, "DIRTSLOPEDDOWNLEFT", 0, 282, 282, 282},
37 {O_DIRT_SLOPED_DOWN_RIGHT, N_("Sloped dirt (down & right)"), P_DIRT|P_SLOPED_DOWN|P_SLOPED_RIGHT|P_AMOEBA_CONSUMES, "DIRTSLOPEDDOWNRIGHT", 0, 283, 283, 283},
38 {O_DIRT2, N_("Dirt 2"), P_DIRT|P_AMOEBA_CONSUMES, "DIRT2", 0, 3, 3, 3},
39 {O_BRICK, N_("Brick wall"), P_SLOPED|P_BLADDER_SLOPED|P_CAN_BE_HAMMERED, "WALL", 'w', 5, 5, 5},
40 {O_BRICK_SLOPED_UP_RIGHT, N_("Sloped brick wall (up & right)"), P_SLOPED_UP|P_SLOPED_RIGHT|P_BLADDER_SLOPED|P_CAN_BE_HAMMERED, "WALLSLOPEDUPRIGHT", 0, 276, 276, 276},
41 {O_BRICK_SLOPED_UP_LEFT, N_("Sloped brick wall (up & left)"), P_SLOPED_UP|P_SLOPED_LEFT|P_BLADDER_SLOPED|P_CAN_BE_HAMMERED, "WALLSLOPEDUPLEFT", 0, 277, 277, 277},
42 {O_BRICK_SLOPED_DOWN_LEFT, N_("Sloped brick wall (down & left)"), P_SLOPED_DOWN|P_SLOPED_LEFT|P_BLADDER_SLOPED|P_CAN_BE_HAMMERED, "WALLSLOPEDDOWNLEFT", 0, 278, 278, 278},
43 {O_BRICK_SLOPED_DOWN_RIGHT, N_("Sloped brick wall (down & right)"), P_SLOPED_DOWN|P_SLOPED_RIGHT|P_BLADDER_SLOPED|P_CAN_BE_HAMMERED, "WALLSLOPEDDOWNRIGHT", 0, 279, 279, 279},
44 {O_BRICK_NON_SLOPED, N_("Non-sloped brick wall"), P_CAN_BE_HAMMERED, "WALLNONSLOPED", 0, 352, 352, 5},
45 {O_MAGIC_WALL, N_("Magic wall"), P_CAN_BE_HAMMERED, "MAGICWALL", 'M', 184, -184, -184},
46 {O_PRE_OUTBOX, N_("Outbox"), 0, "OUTBOX", 'X', 351, -364, 22}, /* 364, 365, 366, 367, 368, 369, 370, 371 */
47 {O_OUTBOX, N_("Outbox (open)"), 0, "OUTBOXopen", 0, 372, 372, 22},
48 {O_PRE_INVIS_OUTBOX, N_("Invisible outbox"), 0, "HIDDENOUTBOX", 'H', 361, 361, 22},
49 {O_INVIS_OUTBOX, N_("Invisible outbox (open)"), 0, "HIDDENOUTBOXopen", 0, 373, 373, 22},
50 {O_STEEL, N_("Steel wall"), P_NON_EXPLODABLE, "STEELWALL", 'W', 4, 4, 4},
51 {O_STEEL_SLOPED_UP_RIGHT, N_("Sloped steel wall (up & right)"), P_SLOPED_UP|P_SLOPED_RIGHT|P_NON_EXPLODABLE, "STEELWALLSLOPEDUPRIGHT", 0, 284, 284, 284},
52 {O_STEEL_SLOPED_UP_LEFT, N_("Sloped steel wall (up & left)"), P_SLOPED_UP|P_SLOPED_LEFT|P_NON_EXPLODABLE, "STEELWALLSLOPEDUPLEFT", 0, 285, 285, 285},
53 {O_STEEL_SLOPED_DOWN_LEFT, N_("Sloped steel wall (down & left)"), P_SLOPED_DOWN|P_SLOPED_LEFT|P_NON_EXPLODABLE, "STEELWALLSLOPEDDOWNLEFT", 0, 286, 286, 286},
54 {O_STEEL_SLOPED_DOWN_RIGHT, N_("Sloped steel wall (down & right)"), P_SLOPED_DOWN|P_SLOPED_RIGHT|P_NON_EXPLODABLE, "STEELWALLSLOPEDDOWNRIGHT", 0, 287, 287, 287},
55 {O_STEEL_EXPLODABLE, N_("Explodable steel wall"), P_CAN_BE_HAMMERED, "STEELWALLDESTRUCTABLE", 'E', 72, 72, 4},
56 {O_STEEL_EATABLE, N_("Eatable steel wall"), 0, "STEELWALLEATABLE", 0, 339, 339, 4},
57 {O_BRICK_EATABLE, N_("Eatable brick wall"), 0, "WALLEATABLE", 0, 340, 340, 5},
58 {O_STONE, N_("Stone"), P_SLOPED, "BOULDER", 'r', 1, 1, 1, 156}, /* has ckdelay */
59 {O_STONE_F, N_("Stone, falling"), 0, "BOULDERf", 'R', 314, 314, 1, 156}, /* has ckdelay */
60 {O_MEGA_STONE, N_("Mega stone"), P_SLOPED, "MEGABOULDER", 0, 272, 272, 272, 156}, /* has ckdelay */
61 {O_MEGA_STONE_F, N_("Mega stone, falling"), 0, "MEGABOULDERf", 0, 345, 345, 272, 156}, /* has ckdelay */
62 {O_DIAMOND, N_("Diamond"), P_SLOPED, "DIAMOND", 'd', 248, -248, -248, 156}, /* has ckdelay */
63 {O_DIAMOND_F, N_("Diamond, falling"), 0, "DIAMONDf", 'D', 315, 315, -248, 156}, /* has ckdelay */
64 {O_BLADDER_SPENDER, N_("Bladder Spender"), 0, "BLADDERSPENDER", 0, 6, 6, 6, 20}, /* has ckdelay */
65 {O_INBOX, N_("Inbox"), 0, "INBOX", 'P', 35, 35, 22},
66 {O_H_EXPANDING_WALL, N_("Expanding wall, horizontal"), P_VISUAL_EFFECT | P_CAN_BE_HAMMERED, "HEXPANDINGWALL", 'x', 316, 316, 5, 111}, /* has ckdelay */
67 {O_V_EXPANDING_WALL, N_("Expanding wall, vertical"), P_VISUAL_EFFECT | P_CAN_BE_HAMMERED, "VEXPANDINGWALL", 'v', 326, 326, 5, 111}, /* has ckdelay */
68 {O_EXPANDING_WALL, N_("Expanding wall"), P_VISUAL_EFFECT | P_CAN_BE_HAMMERED, "EXPANDINGWALL", 'e', 343, 343, 5, 111}, /* has ckdelay */
69 {O_EXPANDING_WALL_SWITCH, N_("Expanding wall switch"), 0, "EXPANDINGWALLSWITCH", 0, 40, 40, 40},
70 {O_CREATURE_SWITCH, N_("Creature direction switch"), 0, "FIREFLYBUTTERFLYSWITCH", 0, 18, 18, 18},
71 {O_BITER_SWITCH, N_("Biter switch"), 0, "BITERSWITCH", 0, 12, 12, 12},
72 {O_ACID, N_("Acid"), 0, "ACID", 0, 20, 20, 20, 128}, /* has ckdelay */
73 {O_FALLING_WALL, N_("Falling wall"), P_CAN_BE_HAMMERED, "FALLINGWALL", 0, 342, 342, 5, 80}, /* has ckdelay */
74 {O_FALLING_WALL_F, N_("Falling wall, falling"), P_CAN_BE_HAMMERED, "FALLINGWALLf", 0, 344, 344, 5, 80}, /* has ckdelay */
75 {O_BOX, N_("Box"), 0, "SOKOBANBOX", 0, 21, 21, 21},
76 {O_TIME_PENALTY, N_("Time penalty"), P_NON_EXPLODABLE, "TIMEPENALTY", 0, 346, 346, 9},
77 {O_GRAVESTONE, N_("Gravestone"), P_NON_EXPLODABLE, "GRAVESTONE", 'G', 9, 9, 9},
78 {O_STONE_GLUED, N_("Glued stone"), P_SLOPED, "GLUEDBOULDER", 0, 334, 334, 1},
79 {O_DIAMOND_GLUED, N_("Glued diamond"), P_SLOPED, "GLUEDDIAMOND", 0, 341, 341, -248},
80 {O_DIAMOND_KEY, N_("Diamond key"), 0, "DIAMONDRELEASEKEY", 0, 11, 11, 11},
81 {O_TRAPPED_DIAMOND, N_("Trapped diamond"), P_NON_EXPLODABLE, "TRAPPEDDIAMOND", 0, 10, 10, 10},
82 {O_CLOCK, N_("Clock"), 0, "CLOCK", 0, 16, 16, 16},
83 {O_DIRT_GLUED, N_("Glued dirt"), 0, "GLUEDDIRT", 0, 321, 321, 2},
84 {O_KEY_1, N_("Key 1"), 0, "KEY1", 0, 67, 67, 67},
85 {O_KEY_2, N_("Key 2"), 0, "KEY2", 0, 68, 68, 68},
86 {O_KEY_3, N_("Key 3"), 0, "KEY3", 0, 69, 69, 69},
87 {O_DOOR_1, N_("Door 1"), 0, "DOOR1", 0, 64, 64, 64},
88 {O_DOOR_2, N_("Door 2"), 0, "DOOR2", 0, 65, 65, 65},
89 {O_DOOR_3, N_("Door 3"), 0, "DOOR3", 0, 66, 66, 66},
91 {O_POT, N_("Pot"), 0, "POT", 0, 63, 63, 63},
92 {O_GRAVITY_SWITCH, N_("Gravity switch"), 0, "GRAVITY_SWITCH", 0, 274, 274, 274},
93 {O_PNEUMATIC_HAMMER, N_("Pneumatic hammer"), 0, "PNEUMATIC_HAMMER", 0, 62, 62, 62},
94 {O_TELEPORTER, N_("Teleporter"), 0, "TELEPORTER", 0, 61, 61, 61},
95 {O_SKELETON, N_("Skeleton"), 0, "SKELETON", 0, 273, 273, 273},
96 {O_WATER, N_("Water"), 0, "WATER", 0, 96, -96, -96, 100}, /* has ckdelay */
97 {O_WATER_1, N_("Water (1)"), 0, "WATER1", 0, 96, -96, -96},
98 {O_WATER_2, N_("Water (2)"), 0, "WATER2", 0, 96, -96, -96},
99 {O_WATER_3, N_("Water (3)"), 0, "WATER3", 0, 96, -96, -96},
100 {O_WATER_4, N_("Water (4)"), 0, "WATER4", 0, 96, -96, -96},
101 {O_WATER_5, N_("Water (5)"), 0, "WATER5", 0, 96, -96, -96},
102 {O_WATER_6, N_("Water (6)"), 0, "WATER6", 0, 96, -96, -96},
103 {O_WATER_7, N_("Water (7)"), 0, "WATER7", 0, 96, -96, -96},
104 {O_WATER_8, N_("Water (8)"), 0, "WATER8", 0, 96, -96, -96},
105 {O_WATER_9, N_("Water (9)"), 0, "WATER9", 0, 96, -96, -96},
106 {O_WATER_10, N_("Water (10)"), 0, "WATER10", 0, 96, -96, -96},
107 {O_WATER_11, N_("Water (11)"), 0, "WATER11", 0, 96, -96, -96},
108 {O_WATER_12, N_("Water (12)"), 0, "WATER12", 0, 96, -96, -96},
109 {O_WATER_13, N_("Water (13)"), 0, "WATER13", 0, 96, -96, -96},
110 {O_WATER_14, N_("Water (14)"), 0, "WATER14", 0, 96, -96, -96},
111 {O_WATER_15, N_("Water (15)"), 0, "WATER15", 0, 96, -96, -96},
112 {O_WATER_16, N_("Water (16)"), 0, "WATER16", 0, 96, -96, -96},
113 {O_COW_1, N_("Cow (left)"), P_CCW, "COWl", 0, 317, -88, -88, 384}, /* has ckdelay */
114 {O_COW_2, N_("Cow (up)"), P_CCW, "COWu", 0, 318, -88, -88, 384}, /* has ckdelay */
115 {O_COW_3, N_("Cow (right)"), P_CCW, "COWr", 0, 319, -88, -88, 384}, /* has ckdelay */
116 {O_COW_4, N_("Cow (down)"), P_CCW, "COWd", 0, 320, -88, -88, 384}, /* has ckdelay */
117 {O_COW_ENCLOSED_1, N_("Cow (enclosed, 1)"), 0, "COW_ENCLOSED1", 0, 327, -88, -88, 120}, /* has ckdelay */
118 {O_COW_ENCLOSED_2, N_("Cow (enclosed, 2)"), 0, "COW_ENCLOSED2", 0, 327, -88, -88, 120}, /* has ckdelay */
119 {O_COW_ENCLOSED_3, N_("Cow (enclosed, 3)"), 0, "COW_ENCLOSED3", 0, 327, -88, -88, 120}, /* has ckdelay */
120 {O_COW_ENCLOSED_4, N_("Cow (enclosed, 4)"), 0, "COW_ENCLOSED4", 0, 327, -88, -88, 120}, /* has ckdelay */
121 {O_COW_ENCLOSED_5, N_("Cow (enclosed, 5)"), 0, "COW_ENCLOSED5", 0, 327, -88, -88, 120}, /* has ckdelay */
122 {O_COW_ENCLOSED_6, N_("Cow (enclosed, 6)"), 0, "COW_ENCLOSED6", 0, 327, -88, -88, 120}, /* has ckdelay */
123 {O_COW_ENCLOSED_7, N_("Cow (enclosed, 7)"), 0, "COW_ENCLOSED7", 0, 327, -88, -88, 120}, /* has ckdelay */
124 {O_WALLED_DIAMOND, N_("Walled diamond"), P_CAN_BE_HAMMERED, "WALLED_DIAMOND", 0, 322, 322, 5},
125 {O_WALLED_KEY_1, N_("Walled key 1"), P_CAN_BE_HAMMERED, "WALLED_KEY1", 0, 323, 323, 5},
126 {O_WALLED_KEY_2, N_("Walled key 2"), P_CAN_BE_HAMMERED, "WALLED_KEY2", 0, 324, 324, 5},
127 {O_WALLED_KEY_3, N_("Walled key 3"), P_CAN_BE_HAMMERED, "WALLED_KEY3", 0, 325, 325, 5},
129 {O_AMOEBA, N_("Amoeba"), P_BLOWS_UP_FLIES, "AMOEBA", 'a', 192, -192, -192, 260}, /* has ckdelay */
130 {O_AMOEBA_2, N_("Amoeba 2"), P_BLOWS_UP_FLIES|P_VISUAL_EFFECT, "AMOEBA2", 0, 296, -296, -296, 260}, /* has ckdelay */
131 {O_SWEET, N_("Sweet"), 0, "SWEET", 0, 8, 8, 8},
132 {O_VOODOO, N_("Voodoo doll"), P_BLOWS_UP_FLIES, "DUMMY", 'F', 7, 7, 7},
133 {O_SLIME, N_("Slime"), 0, "SLIME", 's', 200, -200, -200, 211}, /* has ckdelay */
134 {O_BLADDER, N_("Bladder"), 0, "BLADDER", 0, 176, -176, -176, 267}, /* has ckdelay */
135 {O_BLADDER_1, N_("Bladder (1)"), 0, "BLADDERd1", 0, 176, -176, -176},
136 {O_BLADDER_2, N_("Bladder (2)"), 0, "BLADDERd2", 0, 176, -176, -176},
137 {O_BLADDER_3, N_("Bladder (3)"), 0, "BLADDERd3", 0, 176, -176, -176},
138 {O_BLADDER_4, N_("Bladder (4)"), 0, "BLADDERd4", 0, 176, -176, -176},
139 {O_BLADDER_5, N_("Bladder (5)"), 0, "BLADDERd5", 0, 176, -176, -176},
140 {O_BLADDER_6, N_("Bladder (6)"), 0, "BLADDERd6", 0, 176, -176, -176},
141 {O_BLADDER_7, N_("Bladder (7)"), 0, "BLADDERd7", 0, 176, -176, -176},
142 {O_BLADDER_8, N_("Bladder (8)"), 0, "BLADDERd8", 0, 176, -176, -176},
144 {O_WAITING_STONE, N_("Waiting stone"), P_SLOPED, "WAITINGBOULDER", 0, 363, 363, 1, 176}, /* has ckdelay */
145 {O_CHASING_STONE, N_("Chasing stone"), P_SLOPED, "CHASINGBOULDER", 0, 17, 17, 17, 269}, /* has ckdelay */
146 {O_GHOST, N_("Ghost"), 0, "GHOST", 'g', 160, -160, -160, 50}, /* has ckdelay */
147 {O_GUARD_1, N_("Guard, left"), P_EXPLODES_TO_SPACE | P_CCW, "FIREFLYl", 'Q', 310, -136, -136, 384}, /* has ckdelay */
148 {O_GUARD_2, N_("Guard, up"), P_EXPLODES_TO_SPACE | P_CCW, "FIREFLYu", 'o', 311, -136, -136, 384}, /* has ckdelay */
149 {O_GUARD_3, N_("Guard, right"), P_EXPLODES_TO_SPACE | P_CCW, "FIREFLYr", 'O', 312, -136, -136, 384}, /* has ckdelay */
150 {O_GUARD_4, N_("Guard, down"), P_EXPLODES_TO_SPACE | P_CCW, "FIREFLYd", 'q', 313, -136, -136, 384}, /* has ckdelay */
151 {O_ALT_GUARD_1, N_("Alternative guard, left"), P_EXPLODES_TO_SPACE, "A_FIREFLYl", 0, 357, -104, -104, 384}, /* has ckdelay */
152 {O_ALT_GUARD_2, N_("Alternative guard, up"), P_EXPLODES_TO_SPACE, "A_FIREFLYu", 0, 358, -104, -104, 384}, /* has ckdelay */
153 {O_ALT_GUARD_3, N_("Alternative guard, right"), P_EXPLODES_TO_SPACE, "A_FIREFLYr", 0, 359, -104, -104, 384}, /* has ckdelay */
154 {O_ALT_GUARD_4, N_("Alternative guard, down"), P_EXPLODES_TO_SPACE, "A_FIREFLYd", 0, 360, -104, -104, 384}, /* has ckdelay */
155 {O_BUTTER_1, N_("Butterfly, left"), P_EXPLODES_TO_DIAMONDS, "BUTTERFLYl", 'C', 330, -144, -144, 384}, /* has ckdelay */
156 {O_BUTTER_2, N_("Butterfly, up"), P_EXPLODES_TO_DIAMONDS, "BUTTERFLYu", 'b', 331, -144, -144, 384}, /* has ckdelay */
157 {O_BUTTER_3, N_("Butterfly, right"), P_EXPLODES_TO_DIAMONDS, "BUTTERFLYr", 'B', 332, -144, -144, 384}, /* has ckdelay */
158 {O_BUTTER_4, N_("Butterfly, down"), P_EXPLODES_TO_DIAMONDS, "BUTTERFLYd", 'c', 333, -144, -144, 384}, /* has ckdelay */
159 {O_ALT_BUTTER_1, N_("Alternative butterfly, left"), P_EXPLODES_TO_DIAMONDS | P_CCW, "A_BUTTERFLYl", 0, 305, -112, -112, 384}, /* has ckdelay */
160 {O_ALT_BUTTER_2, N_("Alternative butterfly, up"), P_EXPLODES_TO_DIAMONDS | P_CCW, "A_BUTTERFLYu", 0, 306, -112, -112, 384}, /* has ckdelay */
161 {O_ALT_BUTTER_3, N_("Alternative butterfly, right"), P_EXPLODES_TO_DIAMONDS | P_CCW, "A_BUTTERFLYr", 0, 307, -112, -112, 384}, /* has ckdelay */
162 {O_ALT_BUTTER_4, N_("Alternative butterfly, down"), P_EXPLODES_TO_DIAMONDS | P_CCW, "A_BUTTERFLYd", 0, 308, -112, -112, 384}, /* has ckdelay */
163 {O_STONEFLY_1, N_("Stonefly, left"), P_EXPLODES_TO_STONES, "STONEFLYl", 0, 335, -152, -152, 384}, /* has ckdelay */
164 {O_STONEFLY_2, N_("Stonefly, up"), P_EXPLODES_TO_STONES, "STONEFLYu", 0, 336, -152, -152, 384}, /* has ckdelay */
165 {O_STONEFLY_3, N_("Stonefly, right"), P_EXPLODES_TO_STONES, "STONEFLYr", 0, 337, -152, -152, 384}, /* has ckdelay */
166 {O_STONEFLY_4, N_("Stonefly, down"), P_EXPLODES_TO_STONES, "STONEFLYd", 0, 338, -152, -152, 384}, /* has ckdelay */
167 {O_BITER_1, N_("Biter, up"), 0, "BITERu", 0, 347, -168, -168, 518}, /* has ckdelay */
168 {O_BITER_2, N_("Biter, right"), 0, "BITERr", 0, 348, -168, -168, 518}, /* has ckdelay */
169 {O_BITER_3, N_("Biter, down"), 0, "BITERd", 0, 349, -168, -168, 518}, /* has ckdelay */
170 {O_BITER_4, N_("Biter, left"), 0, "BITERl", 0, 350, -168, -168, 518}, /* has ckdelay */
172 {O_PRE_PL_1, N_("Player birth (1)"), 0, "GUYBIRTH1", 0, 32, 32, 32},
173 {O_PRE_PL_2, N_("Player birth (2)"), 0, "GUYBIRTH2", 0, 33, 33, 33},
174 {O_PRE_PL_3, N_("Player birth (3)"), 0, "GUYBIRTH3", 0, 34, 34, 34},
175 {O_PLAYER, N_("Player"), P_BLOWS_UP_FLIES | P_EXPLODES_TO_SPACE | P_PLAYER, "GUY", 0, 328, 328, 35, 32}, /* has ckdelay */
176 {O_PLAYER_BOMB, N_("Player with bomb"), P_BLOWS_UP_FLIES | P_EXPLODES_TO_SPACE | P_PLAYER, "GUYBOMB", 0, 42, 42, 42, 25}, /* has ckdelay */
177 {O_PLAYER_GLUED, N_("Glued player"), P_BLOWS_UP_FLIES | P_EXPLODES_TO_SPACE, "GUYGLUED", 0, 329, 329, 35}, /* is not a real player! so active x, y will not find it. */
178 {O_PLAYER_STIRRING, N_("Player stirring"), P_BLOWS_UP_FLIES | P_EXPLODES_TO_SPACE | P_PLAYER, "GUYSTIRRING", 0, 256, -256, -256},
180 {O_BOMB, N_("Bomb"), 0, "BOMB", 0, 48, 48, 48},
181 {O_BOMB_TICK_1, N_("Ticking bomb (1)"), P_EXPLOSION_FIRST_STAGE, "IGNITEDBOMB1", 0, 49, 49, 49},
182 {O_BOMB_TICK_2, N_("Ticking bomb (2)"), 0, "IGNITEDBOMB2", 0, 50, 50, 50},
183 {O_BOMB_TICK_3, N_("Ticking bomb (3)"), 0, "IGNITEDBOMB3", 0, 51, 51, 51},
184 {O_BOMB_TICK_4, N_("Ticking bomb (4)"), 0, "IGNITEDBOMB4", 0, 52, 52, 52},
185 {O_BOMB_TICK_5, N_("Ticking bomb (5)"), 0, "IGNITEDBOMB5", 0, 53, 53, 53},
186 {O_BOMB_TICK_6, N_("Ticking bomb (6)"), 0, "IGNITEDBOMB6", 0, 54, 54, 54},
187 {O_BOMB_TICK_7, N_("Ticking bomb (7)"), 0, "IGNITEDBOMB7", 0, 55, 55, 55},
189 {O_NITRO_PACK, N_("Nitro pack"), P_SLOPED|P_EXPLODES_AS_NITRO, "NITRO", 0, 288, 288, 288},
190 {O_NITRO_PACK_F, N_("Nitro pack, falling"), P_EXPLODES_AS_NITRO, "NITROf", 0, 304, 304, 288},
191 {O_NITRO_PACK_EXPLODE, N_("Nitro pack, triggered"), 0, "NITROtriggered", 0, 309, 309, 288},
193 {O_PRE_CLOCK_1, N_("Clock birth (1)"), P_EXPLOSION_FIRST_STAGE, "CLOCKBIRTH1", 0, 28, 28, 28, 280}, /* has ckdelay */
194 {O_PRE_CLOCK_2, N_("Clock birth (2)"), 0, "CLOCKBIRTH2", 0, 29, 29, 29, 280}, /* has ckdelay */
195 {O_PRE_CLOCK_3, N_("Clock birth (3)"), 0, "CLOCKBIRTH3", 0, 30, 30, 30, 280}, /* has ckdelay */
196 {O_PRE_CLOCK_4, N_("Clock birth (4)"), 0, "CLOCKBIRTH4", 0, 31, 31, 31, 280}, /* has ckdelay */
197 {O_PRE_DIA_1, N_("Diamond birth (1)"), P_EXPLOSION_FIRST_STAGE, "DIAMONDBIRTH1", 0, 56, 56, 56, 280}, /* has ckdelay */
198 {O_PRE_DIA_2, N_("Diamond birth (2)"), 0, "DIAMONDBIRTH2", 0, 57, 57, 57, 280}, /* has ckdelay */
199 {O_PRE_DIA_3, N_("Diamond birth (3)"), 0, "DIAMONDBIRTH3", 0, 58, 58, 58, 280}, /* has ckdelay */
200 {O_PRE_DIA_4, N_("Diamond birth (4)"), 0, "DIAMONDBIRTH4", 0, 59, 59, 59, 280}, /* has ckdelay */
201 {O_PRE_DIA_5, N_("Diamond birth (5)"), 0, "DIAMONDBIRTH5", 0, 60, 60, 60, 280}, /* has ckdelay */
202 {O_EXPLODE_1, N_("Explosion (1)"), P_EXPLOSION_FIRST_STAGE, "EXPLOSION1", 0, 43, 43, 43, 280}, /* has ckdelay */
203 {O_EXPLODE_2, N_("Explosion (2)"), 0, "EXPLOSION2", 0, 44, 44, 44, 280}, /* has ckdelay */
204 {O_EXPLODE_3, N_("Explosion (3)"), 0, "EXPLOSION3", 0, 45, 45, 45, 280}, /* has ckdelay */
205 {O_EXPLODE_4, N_("Explosion (4)"), 0, "EXPLOSION4", 0, 46, 46, 46, 280}, /* has ckdelay */
206 {O_EXPLODE_5, N_("Explosion (5)"), 0, "EXPLOSION5", 0, 47, 47, 47, 280}, /* has ckdelay */
207 {O_PRE_STONE_1, N_("Stone birth (1)"), P_EXPLOSION_FIRST_STAGE, "BOULDERBIRTH1", 0, 36, 36, 36, 280}, /* has ckdelay */
208 {O_PRE_STONE_2, N_("Stone birth (2)"), 0, "BOULDERBIRTH2", 0, 37, 37, 37, 280}, /* has ckdelay */
209 {O_PRE_STONE_3, N_("Stone birth (3)"), 0, "BOULDERBIRTH3", 0, 38, 38, 38, 280}, /* has ckdelay */
210 {O_PRE_STONE_4, N_("Stone birth (4)"), 0, "BOULDERBIRTH4", 0, 39, 39, 39, 280}, /* has ckdelay */
211 {O_PRE_STEEL_1, N_("Steel birth (1)"), P_EXPLOSION_FIRST_STAGE, "STEELWALLBIRTH1", 0, 24, 24, 24, 280}, /* has ckdelay */
212 {O_PRE_STEEL_2, N_("Steel birth (2)"), 0, "STEELWALLBIRTH2", 0, 25, 25, 25, 280}, /* has ckdelay */
213 {O_PRE_STEEL_3, N_("Steel birth (3)"), 0, "STEELWALLBIRTH3", 0, 26, 26, 26, 280}, /* has ckdelay */
214 {O_PRE_STEEL_4, N_("Steel birth (4)"), 0, "STEELWALLBIRTH4", 0, 27, 27, 27, 280}, /* has ckdelay */
215 {O_GHOST_EXPL_1, N_("Ghost explosion (1)"), P_EXPLOSION_FIRST_STAGE, "GHOSTEXPLOSION1", 0, 80, 80, 80, 280}, /* has ckdelay */
216 {O_GHOST_EXPL_2, N_("Ghost explosion (2)"), 0, "GHOSTEXPLOSION2", 0, 81, 81, 81, 280}, /* has ckdelay */
217 {O_GHOST_EXPL_3, N_("Ghost explosion (3)"), 0, "GHOSTEXPLOSION3", 0, 82, 82, 82, 280}, /* has ckdelay */
218 {O_GHOST_EXPL_4, N_("Ghost explosion (4)"), 0, "GHOSTEXPLOSION4", 0, 83, 83, 83, 280}, /* has ckdelay */
219 {O_BOMB_EXPL_1, N_("Bomb explosion (1)"), P_EXPLOSION_FIRST_STAGE, "BOMBEXPLOSION1", 0, 84, 84, 84, 280}, /* has ckdelay */
220 {O_BOMB_EXPL_2, N_("Bomb explosion (2)"), 0, "BOMBEXPLOSION2", 0, 85, 85, 85, 280}, /* has ckdelay */
221 {O_BOMB_EXPL_3, N_("Bomb explosion (3)"), 0, "BOMBEXPLOSION3", 0, 86, 86, 86, 280}, /* has ckdelay */
222 {O_BOMB_EXPL_4, N_("Bomb explosion (4)"), 0, "BOMBEXPLOSION4", 0, 87, 87, 87, 280}, /* has ckdelay */
223 {O_NITRO_EXPL_1, N_("Nitro pack explosion (1)"), P_EXPLOSION_FIRST_STAGE, "NITROEXPLOSION1", 0, 84, 84, 84, 280}, /* has ckdelay */
224 {O_NITRO_EXPL_2, N_("Nitro pack explosion (2)"), 0, "NITROEXPLOSION2", 0, 85, 85, 85, 280}, /* has ckdelay */
225 {O_NITRO_EXPL_3, N_("Nitro pack explosion (3)"), 0, "NITROEXPLOSION3", 0, 86, 86, 86, 280}, /* has ckdelay */
226 {O_NITRO_EXPL_4, N_("Nitro pack explosion (4)"), 0, "NITROEXPLOSION4", 0, 87, 87, 87, 280}, /* has ckdelay */
227 {O_AMOEBA_2_EXPL_1, N_("Amoeba 2 explosion (1)"), P_EXPLOSION_FIRST_STAGE, "AMOEBA2EXPLOSION1", 0, 292, 292, 292, 280}, /* has ckdelay */
228 {O_AMOEBA_2_EXPL_2, N_("Amoeba 2 explosion (2)"), 0, "AMOEBA2EXPLOSION2", 0, 293, 293, 293, 280}, /* has ckdelay */
229 {O_AMOEBA_2_EXPL_3, N_("Amoeba 2 explosion (3)"), 0, "AMOEBA2EXPLOSION3", 0, 294, 294, 294, 280}, /* has ckdelay */
230 {O_AMOEBA_2_EXPL_4, N_("Amoeba 2 explosion (4)"), 0, "AMOEBA2EXPLOSION4", 0, 295, 295, 295, 280}, /* has ckdelay */
232 {O_PLAYER_PNEUMATIC_LEFT, NULL /* Player using hammer, left */, P_BLOWS_UP_FLIES|P_EXPLODES_TO_SPACE, "GUYHAMMERl", 0, 265, 265, 265},
233 {O_PLAYER_PNEUMATIC_RIGHT, NULL /* Player using hammer, right */, P_BLOWS_UP_FLIES|P_EXPLODES_TO_SPACE, "GUYHAMMERr", 0, 268, 268, 268},
234 {O_PNEUMATIC_ACTIVE_LEFT, NULL /* Active hammer, left */, 0, "HAMMERACTIVEl", 0, 264, 264, 264},
235 {O_PNEUMATIC_ACTIVE_RIGHT, NULL /* Active hammer, right */, 0, "HAMMERACTIVEr", 0, 269, 269, 269},
237 {O_UNKNOWN, N_("Unknown element"), P_NON_EXPLODABLE, "UNKNOWN", 0, 362, 362, 4},
238 {O_NONE, N_("No element"), 0, "NONE", 0, 79, 79, 79},
239 {O_MAX},
241 /* these are just helpers, for all the element -> image index information to be in this array */
242 {O_FAKE_BONUS, NULL, 0, NULL, 0, 120, -120, -120},
243 {O_OUTBOX_CLOSED, NULL, 0, NULL, 0, 22, 22, 22}, /* game graphics - also for imported diego effects, but don't know if it is used anywhere in original games */
244 {O_OUTBOX_OPEN, NULL, 0, NULL, 0, 23, 23, 23},
245 {O_COVERED, NULL, 0, NULL, 0, 128, -128, -128},
246 {O_PLAYER_LEFT, NULL, 0, NULL, 0, 232, -232, -232},
247 {O_PLAYER_RIGHT, NULL, 0, NULL, 0, 240, -240, -240},
248 {O_PLAYER_TAP, NULL, 0, NULL, 0, 216, -216, -216},
249 {O_PLAYER_BLINK, NULL, 0, NULL, 0, 208, -208, -208},
250 {O_PLAYER_TAP_BLINK, NULL, 0, NULL, 0, 224, -224, -224},
251 {O_CREATURE_SWITCH_ON, NULL, 0, NULL, 0, 19, 19, 19},
252 {O_EXPANDING_WALL_SWITCH_HORIZ, NULL, 0, NULL, 0, 40, 40, 40},
253 {O_EXPANDING_WALL_SWITCH_VERT, NULL, 0, NULL, 0, 41, 41, 41},
254 {O_GRAVITY_SWITCH_ACTIVE, NULL, 0, NULL, 0, 275, 275, 275},
256 {O_QUESTION_MARK, NULL, 0, NULL, 0, 70, 70, 70},
257 {O_EATABLE, NULL, 0, NULL, 0, 71, 71, 71},
258 {O_DOWN_ARROW, NULL, 0, NULL, 0, 73, 73, 73},
259 {O_LEFTRIGHT_ARROW, NULL, 0, NULL, 0, 74, 74, 74},
260 {O_EVERYDIR_ARROW, NULL, 0, NULL, 0, 75, 75, 75},
261 {O_GLUED, NULL, 0, NULL, 0, 76, 76, 76},
262 {O_OUT, NULL, 0, NULL, 0, 77, 77, 77},
263 {O_EXCLAMATION_MARK, NULL, 0, NULL, 0, 78, 78, 78},
264 {-1},
269 /* entries. */
270 /* type given for each element;
271 * GD_TYPE_ELEMENT represents a combo box of gdash objects.
272 * GD_TAB&LABEL represents a notebook tab or a label.
273 * others are self-explanatory. */
274 const GdStructDescriptor
275 gd_cave_properties[] = {
276 /* default data */
277 {"", GD_TAB, 0, N_("Cave data")},
278 {"Name", GD_TYPE_STRING, 0, N_("Name"), G_STRUCT_OFFSET(Cave, name), 1, N_("Name of game")},
279 {"Description", GD_TYPE_STRING, 0, N_("Description"), G_STRUCT_OFFSET(Cave, description), 1, N_("Some words about the game")},
280 {"Author", GD_TYPE_STRING, 0, N_("Author"), G_STRUCT_OFFSET(Cave, author), 1, N_("Name of author")},
281 {"Date", GD_TYPE_STRING, 0, N_("Date"), G_STRUCT_OFFSET(Cave, date), 1, N_("Date of creation")},
282 {"WWW", GD_TYPE_STRING, 0, N_("WWW"), G_STRUCT_OFFSET(Cave, www), 1, N_("Web page or e-mail address")},
283 {"Difficulty", GD_TYPE_STRING, 0, N_("Difficulty"), G_STRUCT_OFFSET(Cave, difficulty), 1, N_("Difficulty (informative)")},
284 {"Remark", GD_TYPE_STRING, 0, N_("Remark"), G_STRUCT_OFFSET(Cave, remark), 1, N_("Remark (informative)")},
286 {"Selectable", GD_TYPE_BOOLEAN, 0, N_("Selectable as start"), G_STRUCT_OFFSET(Cave, selectable), 1, N_("This sets whether the game can be started at this cave.")},
287 {"Intermission", GD_TYPE_BOOLEAN, GD_ALWAYS_SAVE, N_("Intermission"), G_STRUCT_OFFSET(Cave, 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.")},
288 {"IntermissionProperties.instantlife", GD_TYPE_BOOLEAN, 0, N_(" Instant life"), G_STRUCT_OFFSET(Cave, intermission_instantlife), 1, N_("If true, an extra life is given to the player, when the intermission cave is reached.")},
289 {"IntermissionProperties.rewardlife", GD_TYPE_BOOLEAN, 0, N_(" Reward life"), G_STRUCT_OFFSET(Cave, intermission_rewardlife), 1, N_("If true, an extra life is given to the player, when the intermission cave is successfully finished.")},
290 {"Size", GD_TYPE_INT, GD_ALWAYS_SAVE, N_("Width"), G_STRUCT_OFFSET(Cave, w), 1, N_("Width of cave. The standard size for a cave is 40x22, and 20x12 for an intermission."), 12, 128},
291 {"Size", GD_TYPE_INT, GD_ALWAYS_SAVE, N_("Height"), G_STRUCT_OFFSET(Cave, h), 1, N_("Height of cave. The standard size for a cave is 40x22, and 20x12 for an intermission."), 12, 128},
292 {"Size", GD_TYPE_INT, GD_ALWAYS_SAVE|GD_DONT_SHOW_IN_EDITOR, N_("Visible, left"), G_STRUCT_OFFSET(Cave, x1), 1, N_("Visible parts of the cave, upper left and lower right corner."), 0, 127},
293 {"Size", GD_TYPE_INT, GD_ALWAYS_SAVE|GD_DONT_SHOW_IN_EDITOR, N_("Visible, upper"), G_STRUCT_OFFSET(Cave, y1), 1, N_("Visible parts of the cave, upper left and lower right corner."), 0, 127},
294 {"Size", GD_TYPE_INT, GD_ALWAYS_SAVE|GD_DONT_SHOW_IN_EDITOR, N_("Visible, right"), G_STRUCT_OFFSET(Cave, x2), 1, N_("Visible parts of the cave, upper left and lower right corner."), 0, 127},
295 {"Size", GD_TYPE_INT, GD_ALWAYS_SAVE|GD_DONT_SHOW_IN_EDITOR, N_("Visible, lower"), G_STRUCT_OFFSET(Cave, y2), 1, N_("Visible parts of the cave, upper left and lower right corner."), 0, 127},
296 {"Colors", GD_TYPE_COLOR, GD_ALWAYS_SAVE, N_("Border color"), G_STRUCT_OFFSET(Cave, colorb), 1, N_("Border color for C64 graphics. Only for compatibility, not used by GDash.")},
297 {"Colors", GD_TYPE_COLOR, GD_ALWAYS_SAVE, N_("Background color"), G_STRUCT_OFFSET(Cave, color0), 1, N_("Background color for C64 graphics")},
298 {"Colors", GD_TYPE_COLOR, GD_ALWAYS_SAVE, N_("Color 1 (dirt)"), G_STRUCT_OFFSET(Cave, color1), 1, N_("Foreground color 1 for C64 graphics")},
299 {"Colors", GD_TYPE_COLOR, GD_ALWAYS_SAVE, N_("Color 2 (steel wall)"), G_STRUCT_OFFSET(Cave, color2), 1, N_("Foreground color 2 for C64 graphics")},
300 {"Colors", GD_TYPE_COLOR, GD_ALWAYS_SAVE, N_("Color 3 (brick wall)"), G_STRUCT_OFFSET(Cave, color3), 1, N_("Foreground color 3 for C64 graphics")},
301 {"Colors", GD_TYPE_COLOR, GD_ALWAYS_SAVE, N_("Amoeba color"), G_STRUCT_OFFSET(Cave, color4), 1, N_("Amoeba color for C64 graphics")},
302 {"Colors", GD_TYPE_COLOR, GD_ALWAYS_SAVE, N_("Slime color"), G_STRUCT_OFFSET(Cave, color5), 1, N_("Slime color for C64 graphics")},
303 {"Charset", GD_TYPE_STRING, 0, N_("Character set"), G_STRUCT_OFFSET(Cave, charset), 1, N_("Theme used for displaying the game. Not used by GDash.")},
304 {"Fontset", GD_TYPE_STRING, 0, N_("Font set"), G_STRUCT_OFFSET(Cave, fontset), 1, N_("Font used during the game. Not used by GDash.")},
306 /* difficulty */
307 {"", GD_TAB, 0, N_("Difficulty")},
308 {"", GD_LABEL, GD_SHOW_LEVEL_LABEL, N_("Diamonds")},
309 {"DiamondsRequired", GD_TYPE_INT, GD_ALWAYS_SAVE, N_("Diamonds needed"), CAVE_OFFSET(level_diamonds[0]), 5, N_("Here zero means automatically count diamonds before level start. If negative, the value is subtracted from that. This is useful for totally random caves."), -100, 999},
310 {"DiamondValue", GD_TYPE_INT, GD_ALWAYS_SAVE, N_("Score for diamonds"), CAVE_OFFSET(diamond_value), 1, N_("Number of points per diamond collected, before opening the exit."), 0, 100},
311 {"DiamondValue", GD_TYPE_INT, GD_ALWAYS_SAVE, N_("Score for extra diamonds"), CAVE_OFFSET(extra_diamond_value), 1, N_("Number of points per diamond collected, after opening the exit."), 0, 100},
312 {"", GD_LABEL, 0, N_("Time")},
313 {"CaveTime", GD_TYPE_INT, GD_ALWAYS_SAVE, N_("Time (s)"), CAVE_OFFSET(level_time[0]), 5, N_("Time available to solve cave, in seconds."), 1, 999},
314 {"CaveMaxTime", GD_TYPE_INT, 0, N_("Maximum time (s)"), CAVE_OFFSET(max_time), 1, N_("If you reach this time by collecting too many clocks, the timer will overflow."), 60, 999},
315 {"TimeValue", GD_TYPE_INT, 0, N_("Score for time"), CAVE_OFFSET(level_timevalue[0]), 5, N_("Points for each seconds remaining, when the player exits the level."), 0, 50},
316 {"CaveScheduling", GD_TYPE_SCHEDULING, GD_ALWAYS_SAVE, N_("Scheduling type"), CAVE_OFFSET(scheduling), 1, N_("This flag sets whether the game uses an emulation of the original timing (c64-style), or a more modern milliseconds-based timing. The original game used a delay (empty loop) based timing of caves; this is selected by setting this to BD1, BD2, Construction Kit or Crazy Dream 7. This is a compatibility setting only; milliseconds-based timing is recommended for every new cave.")},
317 {"PALTiming", GD_TYPE_BOOLEAN, 0, N_("PAL timing"), CAVE_OFFSET(pal_timing), 1, N_("On the PAL version of the C64 computer, the timer was "
318 "actually slower than normal seconds. This flag is used to compensate for this. Most original games are authored for the PAL version.")},
319 {"CaveDelay", GD_TYPE_INT, GD_ALWAYS_SAVE, N_(" Delay (c64-style)"), CAVE_OFFSET(level_ckdelay[0]), 5, N_("The length of the delay loop between game frames. Used when milliseconds-based timing is inactive, ie. C64 scheduling is on."), 0, 32},
320 {"HatchingTime", GD_TYPE_INT, 0, N_(" Hatching time (seconds)"), CAVE_OFFSET(level_hatching_delay_time[0]), 5, N_("This value sets how much the cave will move until the player enters the cave. This is used for the C64-like schedulings."), 1, 40},
321 {"FrameTime", GD_TYPE_INT, GD_ALWAYS_SAVE, N_(" Speed (ms)"), CAVE_OFFSET(level_speed[0]), 5, N_("Number of milliseconds between game frames. Used when milliseconds-based timing is active, ie. C64 scheduling is off."), 50, 500},
322 {"HatchingDelay", GD_TYPE_INT, 0, N_(" Hatching delay (frames)"), CAVE_OFFSET(level_hatching_delay_frame[0]), 5, N_("This value sets how much the cave will move until the player enters the cave. This is used for the milliseconds-based scheduling."), 1, 40},
324 /* initial fill */
325 {"RandSeed", GD_TYPE_INT, GD_DONT_SHOW_IN_EDITOR, N_("Random seed value"), CAVE_OFFSET(level_rand[0]), 5, N_("Random seed value controls the predictable random number generator, which fills the cave initially. If set to -1, cave is totally random every time it is played."), -1, 255},
326 {"InitialBorder", GD_TYPE_ELEMENT, GD_DONT_SHOW_IN_EDITOR, NULL /* Initial border */, CAVE_OFFSET(initial_border), 1, NULL},
327 {"InitialFill", GD_TYPE_ELEMENT, GD_DONT_SHOW_IN_EDITOR, NULL /* Initial fill */, CAVE_OFFSET(initial_fill), 1, NULL},
328 {"RandomFill", GD_TYPE_ELEMENT, GD_DONT_SHOW_IN_EDITOR, NULL /* Random fill 1 */, CAVE_OFFSET(random_fill[0]), 1, NULL},
329 {"RandomFill", GD_TYPE_INT, GD_DONT_SHOW_IN_EDITOR, NULL /* Probability 1 */, CAVE_OFFSET(random_fill_probability[0]), 1, NULL, 0, 255},
330 {"RandomFill", GD_TYPE_ELEMENT, GD_DONT_SHOW_IN_EDITOR, NULL /* Random fill 2 */, CAVE_OFFSET(random_fill[1]), 1, NULL},
331 {"RandomFill", GD_TYPE_INT, GD_DONT_SHOW_IN_EDITOR, NULL /* Probability 2 */, CAVE_OFFSET(random_fill_probability[1]), 1, NULL, 0, 255},
332 {"RandomFill", GD_TYPE_ELEMENT, GD_DONT_SHOW_IN_EDITOR, NULL /* Random fill 3 */, CAVE_OFFSET(random_fill[2]), 1, NULL},
333 {"RandomFill", GD_TYPE_INT, GD_DONT_SHOW_IN_EDITOR, NULL /* Probability 3 */, CAVE_OFFSET(random_fill_probability[2]), 1, NULL, 0, 255},
334 {"RandomFill", GD_TYPE_ELEMENT, GD_DONT_SHOW_IN_EDITOR, NULL /* Random fill 4 */, CAVE_OFFSET(random_fill[3]), 1, NULL},
335 {"RandomFill", GD_TYPE_INT, GD_DONT_SHOW_IN_EDITOR, NULL /* Probability 4 */, CAVE_OFFSET(random_fill_probability[3]), 1, NULL, 0, 255},
337 /* PLAYER */
338 {"", GD_TAB, 0, N_("Player")},
339 /* player */
340 {"", GD_LABEL, 0, N_("Player movements")},
341 {"DiagonalMovement", GD_TYPE_BOOLEAN, 0, N_("Diagonal movements"), CAVE_OFFSET(diagonal_movements), 1, N_("Controls if the player can move diagonally.")},
342 {"ActiveGuyIsFirst", GD_TYPE_BOOLEAN, 0, N_("Uppermost player active"), CAVE_OFFSET(active_is_first_found), 1, N_("In 1stB, cave is scrolled to the uppermost and leftmost player found, whereas in the original game to the last one. Chasing stones also follow the active player.")},
343 {"SnapEffect", GD_TYPE_ELEMENT, 0, N_("Snap element"), CAVE_OFFSET(snap_element), 1, N_("Snapping (pressing fire while moving) usually creates space, but it can create any other element.")},
344 {"PushingBoulderProb", GD_TYPE_PROBABILITY, 0, N_("Probability of pushing (%)"), CAVE_OFFSET(pushing_stone_prob), 1, N_("Chance of player managing to push a stone, every game cycle he tries. This is the normal probability.")},
345 {"", GD_LABEL, 0, N_("Sweet")},
346 {"PushingBoulderProb", GD_TYPE_PROBABILITY, 0, N_("Probability of pushing (%)"), CAVE_OFFSET(pushing_stone_prob_sweet), 1, N_("Chance of player managing to push a stone, every game cycle he tries. This is used after eating sweet.")},
347 {"PushingMegaStonesAfterSweet", GD_TYPE_BOOLEAN, 0, N_("Mega stones pushable"), CAVE_OFFSET(mega_stones_pushable_with_sweet), 1, N_("If it is true, mega stones can be pushed after eating sweet.")},
348 /* pneumatic hammer */
349 {"", GD_LABEL, 0, N_("Pneumatic hammer")},
350 {"PneumaticHammer.frames", GD_TYPE_INT, 0, N_("Time for hammer (frames)"), CAVE_OFFSET(pneumatic_hammer_frame), 1, N_("This is the number of game frames, a pneumatic hammer is required to break a wall."), 1, 100},
351 {"PneumaticHammer.wallsreappear", GD_TYPE_BOOLEAN, 0, N_("Hammered walls reappear"), CAVE_OFFSET(hammered_walls_reappear), 1, N_("If this is set to true, walls broken with a pneumatic hammer will reappear later.")},
352 {"PneumaticHammer.wallsreappearframes", GD_TYPE_INT, 0, N_(" Timer for reappear (frames)"), CAVE_OFFSET(hammered_wall_reappear_frame), 1, N_("This sets the number of game frames, after hammered walls reappear, when the above setting is true."), 1, 200},
353 /* clock */
354 {"", GD_LABEL, GD_SHOW_LEVEL_LABEL, N_("Clock")},
355 {"BonusTime", GD_TYPE_INT, 0, N_("Time bonus (s)"), CAVE_OFFSET(level_bonus_time), 5, N_("Bonus time when a clock is collected."), -100, 100},
356 /* voodoo */
357 {"", GD_LABEL, 0, N_("Voodoo Doll")},
358 {"DummyProperties.diamondcollector", GD_TYPE_BOOLEAN, 0, N_("Can collect diamonds"), CAVE_OFFSET(voodoo_collects_diamonds), 1, N_("Controls if a voodoo doll can collect diamonds for the player.")},
359 {"DummyProperties.destructable", GD_TYPE_BOOLEAN, 0, N_("Can be destroyed by explosion"), CAVE_OFFSET(voodoo_can_be_destroyed), 1, N_("Controls if the voodoo can be destroyed by an explosion nearby. If not, it is converted to a gravestone, and you get a time penalty.")},
360 {"DummyProperties.penalty", GD_TYPE_BOOLEAN, 0, N_("Dies if hit by a stone"), CAVE_OFFSET(voodoo_dies_by_stone), 1, N_("Controls if the voodoo doll dies if it is hit by a stone. Then the player gets a time penalty.")},
361 {"PenaltyTime", GD_TYPE_INT, 0, N_("Time penalty (s)"), CAVE_OFFSET(level_penalty_time), 5, N_("Penalty time when the voodoo is destroyed by a stone."), 0, 100},
363 /* AMOEBA */
364 {"", GD_TAB, 0, N_("Amoeba")},
365 {"AmoebaProperties.waitforhatching", GD_TYPE_BOOLEAN, 0, N_("Timer waits for hatching"), CAVE_OFFSET(amoeba_timer_wait_for_hatching), 1, N_("This determines if the amoeba timer starts before the player appearing. Amoeba can always be activated before that; but if this is set to true, the timer will not start.")},
366 {"AmoebaProperties.immediately", GD_TYPE_BOOLEAN, 0, N_("Timer started immediately"), CAVE_OFFSET(amoeba_timer_started_immediately), 1, N_("If this flag is enabled, the amoeba slow growth timer will start at the beginning of the cave, regardless of the amoeba being let free or not.")},
367 /* amoeba */
368 {"", GD_LABEL, GD_SHOW_LEVEL_LABEL, N_("Amoeba")},
369 {"AmoebaThreshold", GD_TYPE_RATIO, 0, N_("Threshold (cells)"), CAVE_OFFSET(level_amoeba_threshold), 5, N_("If the amoeba grows more than this fraction of the cave, it is considered too big."), 0, 16383},
370 {"AmoebaTime", GD_TYPE_INT, 0, N_("Slow growth time (s)"), CAVE_OFFSET(level_amoeba_time), 5, N_("After this time, amoeba will grow very quickly."), 0, 999},
371 {"AmoebaGrowthProb", GD_TYPE_PROBABILITY, 0, N_("Growth ratio, slow (%)"), CAVE_OFFSET(amoeba_growth_prob), 1, N_("This sets the speed at which a slow amoeba grows.")},
372 {"AmoebaGrowthProb", GD_TYPE_PROBABILITY, 0, N_("Growth ratio, fast (%)"), CAVE_OFFSET(amoeba_fast_growth_prob), 1, N_("This sets the speed at which a fast amoeba grows.")},
373 {"AMOEBABOULDEReffect", GD_TYPE_EFFECT, 0, N_("If too big, converts to"), CAVE_OFFSET(too_big_amoeba_to), 1, N_("Controls which element an overgrown amoeba converts to.")},
374 {"AMOEBADIAMONDeffect", GD_TYPE_EFFECT, 0, N_("If enclosed, converts to"), CAVE_OFFSET(enclosed_amoeba_to), 1, N_("Controls which element an enclosed amoeba converts to.")},
375 {"", GD_LABEL, GD_SHOW_LEVEL_LABEL, N_("Amoeba 2")},
376 {"Amoeba2Threshold", GD_TYPE_RATIO, 0, N_("Threshold (cells)"), CAVE_OFFSET(level_amoeba_2_threshold), 5, N_("If the amoeba grows more than this fraction of the cave, it is considered too big."), 0, 16383},
377 {"Amoeba2Time", GD_TYPE_INT, 0, N_("Slow growth time (s)"), CAVE_OFFSET(level_amoeba_2_time), 5, N_("After this time, amoeba will grow very quickly."), 0, 999},
378 {"Amoeba2GrowthProb", GD_TYPE_PROBABILITY, 0, N_("Growth ratio, slow (%)"), CAVE_OFFSET(amoeba_2_growth_prob), 1, N_("This sets the speed at which a slow amoeba grows.")},
379 {"Amoeba2GrowthProb", GD_TYPE_PROBABILITY, 0, N_("Growth ratio, fast (%)"), CAVE_OFFSET(amoeba_2_fast_growth_prob), 1, N_("This sets the speed at which a fast amoeba grows.")},
380 {"Amoeba2Properties.explode", GD_TYPE_BOOLEAN, 0, N_("Explodes by amoeba"), CAVE_OFFSET(amoeba_2_explodes_by_amoeba), 1, N_("If this setting is enabled, an amoeba 2 will explode if it is touched by a normal amoeba.")},
381 {"AMOEBA2EXPLOSIONeffect", GD_TYPE_EFFECT, 0, N_(" Explodes to"), CAVE_OFFSET(amoeba_2_explodes_to), 1, N_("An amoeba 2 explodes to this element, when touched by the original amoeba.")},
382 {"AMOEBA2BOULDEReffect", GD_TYPE_EFFECT, 0, N_("If too big, converts to"), CAVE_OFFSET(too_big_amoeba_2_to), 1, N_("Controls which element an overgrown amoeba converts to.")},
383 {"AMOEBA2DIAMONDeffect", GD_TYPE_EFFECT, 0, N_("If enclosed, converts to"), CAVE_OFFSET(enclosed_amoeba_2_to), 1, N_("Controls which element an enclosed amoeba converts to.")},
384 {"AMOEBA2LOOKSLIKEeffect", GD_TYPE_EFFECT, 0, N_("Looks like"), CAVE_OFFSET(amoeba_2_looks_like), 1, N_("Amoeba 2 can look like any other element. Hint: it can also look like a normal amoeba. Or it can look like slime, and then you have two different colored amoebas!")},
386 /* ACTIVE 1 */
387 {"", GD_TAB, 0, N_("Active elements")},
388 /* magic wall */
389 {"", GD_LABEL, GD_SHOW_LEVEL_LABEL, N_("Magic Wall")},
390 {"MagicWallTime", GD_TYPE_INT, 0, N_("Milling time (s)"), CAVE_OFFSET(level_magic_wall_time), 5, N_("Magic wall will stop after this time, and it cannot be activated again."), 0, 999},
391 {"MagicWallProperties", GD_TYPE_ELEMENT, 0, N_("Converts diamond to"), CAVE_OFFSET(magic_diamond_to), 1, N_("As a special effect, magic walls can convert diamonds to any other element.")},
392 {"MagicWallProperties", GD_TYPE_ELEMENT, 0, N_("Converts stone to"), CAVE_OFFSET(magic_stone_to), 1, N_("As a special effect, magic walls can convert stones to any other element.")},
393 {"MagicWallProperties.convertamoeba", GD_TYPE_BOOLEAN, 0, N_("Stops amoeba"), CAVE_OFFSET(magic_wall_stops_amoeba), 1, N_("When the magic wall is activated, it can convert amoeba into diamonds.")},
394 {"MagicWallProperties.waitforhatching", GD_TYPE_BOOLEAN, 0, N_("Timer waits for hatching"), CAVE_OFFSET(magic_timer_wait_for_hatching), 1, N_("This determines if the magic wall timer starts before the player appearing. Magic can always be activated before that; but if this is set to true, the timer will not start.")},
396 /* slime */
397 {"", GD_LABEL, GD_SHOW_LEVEL_LABEL, N_("Slime")},
398 {"", GD_TYPE_BOOLEAN, GD_DONT_SAVE, N_("Predictable"), CAVE_OFFSET(slime_predictable), 1, N_("Controls if the predictable random generator is used for slime. It is required for compatibility with some older caves.")},
399 /* permeabilities are "always" saved; and according to the predictability, one of them is removed. */
400 {"SlimePermeability", GD_TYPE_PROBABILITY, GD_ALWAYS_SAVE, N_("Permeability (unpredictable, %)"), CAVE_OFFSET(level_slime_permeability[0]), 5, N_("This controls the rate at which elements go through the slime. Higher values represent higher probability of passing. This one is for unpredictable slime.")},
401 {"SlimePermeabilityC64", GD_TYPE_INT, GD_ALWAYS_SAVE, N_("Permeability (predictable, bits)"), CAVE_OFFSET(level_slime_permeability_c64[0]), 5, N_("This controls the rate at which elements go through the slime. This one is for predictable slime, and the value is used for a bitwise AND function. The values used by the C64 engines are 0, 128, 192, 224, 240, 248, 252, 254 and 255."), 0, 255},
402 {"SlimePredictableC64.seed", GD_TYPE_INT, 0, N_("Random seed (predictable)"), CAVE_OFFSET(level_slime_seed_c64), 5, N_("The random number seed for predictable slime. Use -1 to leave on its default. Not recommended to change. Does not affect unpredictable slime."), -1, 65535},
403 {"SlimeProperties", GD_TYPE_ELEMENT, 0, N_("Eats this..."), CAVE_OFFSET(slime_eats_1), 1, N_("Slime can let other elements than stone and diamond go through. It always lets a waiting or a chasing stone pass, though.")},
404 {"SlimeProperties", GD_TYPE_ELEMENT, 0, N_(" ... and converts to"), CAVE_OFFSET(slime_converts_1), 1, N_("Slime can let other elements than stone and diamond go through. It always lets a waiting or a chasing stone pass, though.")},
405 {"SlimeProperties", GD_TYPE_ELEMENT, 0, N_("Eats this..."), CAVE_OFFSET(slime_eats_2), 1, N_("Slime can let other elements than stone and diamond go through. It always lets a waiting or a chasing stone pass, though.")},
406 {"SlimeProperties", GD_TYPE_ELEMENT, 0, N_(" ... and converts to"), CAVE_OFFSET(slime_converts_2), 1, N_("Slime can let other elements than stone and diamond go through. It always lets a waiting or a chasing stone pass, though.")},
408 /* ACTIVE 2 */
409 {"", GD_TAB, 0, N_("More elements")},
410 /* water */
411 {"", GD_LABEL, 0, N_("Water")},
412 {"WaterProperties.doesnotflowdown", GD_TYPE_BOOLEAN, 0, N_("Does not flow downwards"), CAVE_OFFSET(water_does_not_flow_down), 1, N_("In CrDr, the water element had the odd property that it did not flow downwards, only in other directions. This flag emulates this behaviour.")},
414 /* acid */
415 {"", GD_LABEL, 0, N_("Acid")},
416 {"AcidProperties", GD_TYPE_ELEMENT, 0, N_("Eats this element"), CAVE_OFFSET(acid_eats_this), 1, N_("The element which acid eats. If it cannot find any, it simply disappears.")},
417 {"AcidProperties", GD_TYPE_PROBABILITY, 0, N_("Spread ratio (%)"), CAVE_OFFSET(acid_spread_ratio), 1, N_("The probability at which an acid will explode and eat neighbouring elements.")},
418 {"ACIDEffect", GD_TYPE_EFFECT, 0, N_("Leaves this behind"), CAVE_OFFSET(acid_turns_to), 1, N_("If acid converts to an explosion puff on spreading or any other element.")},
420 /* biter */
421 {"", GD_LABEL, 0, N_("Biter")},
422 {"BiterProperties", GD_TYPE_INT, 0, N_("Delay (frame)"), CAVE_OFFSET(biter_delay_frame), 1, N_("Number of frames biters wait between movements."), 0, 3},
423 {"BiterProperties", GD_TYPE_ELEMENT, 0, N_("Eats this"), CAVE_OFFSET(biter_eat), 1, N_("Biters eat this element. (They always eat dirt.)")},
425 /* bladder */
426 {"", GD_LABEL, 0, N_("Bladder")},
427 {"BladderProperties", GD_TYPE_ELEMENT, 0, N_("Converts to clock by touching"), CAVE_OFFSET(bladder_converts_by), 1, NULL},
429 /* expanding wall */
430 {"", GD_LABEL, 0, N_("Expanding wall")},
431 {"ExpandingWallDirection.changed", GD_TYPE_BOOLEAN, 0, N_("Direction changed"), CAVE_OFFSET(expanding_wall_changed), 1, N_("If this option is enabled, the direction of growing for the horizontal and vertical expanding wall is switched.")},
433 /* EFFECTS */
434 {"", GD_TAB, 0, N_("Effects")},
435 /* creature effects */
436 {"", GD_LABEL, 0, N_("Creature effects")},
437 {"EnemyDirectionProperties.startbackwards", GD_TYPE_BOOLEAN, 0, N_("Start backwards"), CAVE_OFFSET(creatures_backwards), 1, NULL},
438 {"EnemyDirectionProperties.time", GD_TYPE_INT, 0, N_("Automatically turn (s)"), CAVE_OFFSET(creatures_direction_auto_change_time), 1, N_("If this is greater than zero, creatures will automatically change direction in every x seconds."), 0, 999},
439 {"EnemyDirectionProperties.changeathatching", GD_TYPE_BOOLEAN, 0, N_("Automatically turn on start"), CAVE_OFFSET(creatures_direction_auto_change_on_start), 1, N_("If this is set to true, creatures also turn at the start signal. If false, the first change in direction occurs only later.")},
440 /* cave effects */
441 {"", GD_LABEL, 0, N_("Cave effects")},
442 {"EXPLOSIONEffect", GD_TYPE_EFFECT, 0, N_("Explosions convert to"), CAVE_OFFSET(explosion_to), 1, N_("This element appears in places where an explosion happens.")},
443 {"DIAMONDBIRTHEffect", GD_TYPE_EFFECT, 0, N_("Diamond births convert to"), CAVE_OFFSET(diamond_birth_to), 1, NULL},
444 {"BOMBEXPLOSIONeffect", GD_TYPE_EFFECT, 0, N_("Bombs explode to"), CAVE_OFFSET(bomb_explode_to), 1, NULL},
445 {"NITROEXPLOSIONeffect", GD_TYPE_EFFECT, 0, N_("Nitro packs explode to"), CAVE_OFFSET(nitro_explode_to), 1, NULL},
446 {"BOULDERfallingeffect", GD_TYPE_EFFECT, 0, N_("Falling stones convert to"), CAVE_OFFSET(falling_stone_to), 1, N_("When a stone begins falling, it converts to this element.")},
447 {"BOULDERbouncingeffect", GD_TYPE_EFFECT, 0, N_("Bouncing stones convert to"), CAVE_OFFSET(bouncing_stone_to), 1, N_("When a stone stops falling and rolling, it converts to this element.")},
448 {"DIAMONDfallingeffect", GD_TYPE_EFFECT, 0, N_("Falling diamonds convert to"), CAVE_OFFSET(falling_diamond_to), 1, N_("When a diamond begins falling, it converts to this element.")},
449 {"DIAMONDbouncingeffect", GD_TYPE_EFFECT, 0, N_("Bouncing diamonds convert to"), CAVE_OFFSET(bouncing_diamond_to), 1, N_("When a diamond stops falling and rolling, it converts to this element.")},
450 /* visual effects */
451 {"", GD_LABEL, 0, N_("Visual effects")},
452 {"EXPANDINGWALLLOOKSLIKEeffect", GD_TYPE_EFFECT, 0, N_("Expanding wall looks like"), CAVE_OFFSET(expanding_wall_looks_like), 1, NULL},
453 {"DIRTLOOKSLIKEeffect", GD_TYPE_EFFECT, 0, N_("Dirt looks like"), CAVE_OFFSET(dirt_looks_like), 1, NULL},
454 /* gravity */
455 {"", GD_LABEL, 0, N_("Gravitation effects")},
456 {"Gravitation", GD_TYPE_DIRECTION, 0, N_("Direction"), CAVE_OFFSET(gravity), 1, N_("The direction where stones and diamonds fall.")},
457 {"GravitationSwitchActive", GD_TYPE_BOOLEAN, 0, N_("Switch active at start"), CAVE_OFFSET(gravity_switch_active), 1, N_("If set to true, the gravitation switch will be already activated, when the cave is started, as if a pot has already been collected.")},
458 {"SkeletonsForPot", GD_TYPE_INT, 0, N_("Skeletons needed for pot"), CAVE_OFFSET(skeletons_needed_for_pot), 1, N_("The number of skeletons to be collected to be able to use a pot."), 0, 50},
459 {"GravitationChangeDelay", GD_TYPE_INT, 0, N_("Gravitation switch delay"), CAVE_OFFSET(gravity_change_time), 1, N_("The gravitation changes after a while using the gravitation switch. This option sets the number of seconds to wait."), 1, 60},
461 /* SOUND */
462 {"", GD_TAB, 0, N_("Sound")},
463 {"", GD_LABEL, 0, N_("Sound for elements")},
464 {"Diamond.sound", GD_TYPE_BOOLEAN, 0, N_("Diamond"), CAVE_OFFSET(diamond_sound), 1, N_("If true, falling diamonds will have sound.")},
465 {"Stone.sound", GD_TYPE_BOOLEAN, 0, N_("Stone"), CAVE_OFFSET(stone_sound), 1, N_("If true, falling and pushed stones will have sound.")},
466 {"NitroPack.sound", GD_TYPE_BOOLEAN, 0, N_("Nitro pack"), CAVE_OFFSET(nitro_sound), 1, N_("If true, falling and pushed nitro packs will have sound.")},
467 {"ExpandingWall.sound", GD_TYPE_BOOLEAN, 0, N_("Expanding wall"), CAVE_OFFSET(expanding_wall_sound), 1, N_("If true, expanding wall will have sound.")},
468 {"FallingWall.sound", GD_TYPE_BOOLEAN, 0, N_("Falling wall"), CAVE_OFFSET(falling_wall_sound), 1, N_("If true, falling wall will have sound.")},
469 {"AmoebaProperties.sound", GD_TYPE_BOOLEAN, 0, N_("Amoeba"), CAVE_OFFSET(amoeba_sound), 1, N_("Controls if the living amoeba has sound or not.")},
470 {"MagicWallProperties.sound", GD_TYPE_BOOLEAN, 0, N_("Magic wall"), CAVE_OFFSET(magic_wall_sound), 1, N_("If true, the activated magic wall will have sound.")},
471 {"SlimeProperties.sound", GD_TYPE_BOOLEAN, 0, N_("Slime"), CAVE_OFFSET(slime_sound), 1, N_("If true, the elements passing slime will have sound.")},
472 {"AcidProperties.sound", GD_TYPE_BOOLEAN, 0, N_("Acid"), CAVE_OFFSET(acid_spread_sound), 1, N_("If true, the acid spreading will have sound.")},
473 {"BiterProperties.sound", GD_TYPE_BOOLEAN, 0, N_("Biter"), CAVE_OFFSET(biter_sound), 1, N_("Biters eating something or pushing a stone will have sound.")},
474 {"BladderProperties.sound", GD_TYPE_BOOLEAN, 0, N_("Bladder"), CAVE_OFFSET(bladder_sound), 1, N_("Bladders moving and being pushed can have sound.")},
475 {"WaterProperties.sound", GD_TYPE_BOOLEAN, 0, N_("Water"), CAVE_OFFSET(water_sound), 1, N_("If true, the cave containing water will have sound.")},
476 {"PneumaticHammer.sound", GD_TYPE_BOOLEAN, 0, N_("Pneumatic hammer"), CAVE_OFFSET(pneumatic_hammer_sound), 1, N_("If true, using the pneumatic hammer will have sound.")},
477 {"BladderSpender.sound", GD_TYPE_BOOLEAN, 0, N_("Bladder spender"), CAVE_OFFSET(bladder_spender_sound), 1, N_("If true, the bladder spender will make sound, when the bladder appears.")},
478 {"BladderConvert.sound", GD_TYPE_BOOLEAN, 0, N_("Bladder convert"), CAVE_OFFSET(bladder_convert_sound), 1, N_("If true, the bladder converting to a clock will make sound.")},
479 {"", GD_LABEL, 0, N_("Event sounds")},
480 {"GravityChange.sound", GD_TYPE_BOOLEAN, 0, N_("Gravity change"), CAVE_OFFSET(gravity_change_sound), 1, N_("If true, the gravity changing will make sound.")},
483 /* COMPATIBILITY */
484 {"", GD_TAB, 0, N_("Compatibility")},
485 {"", GD_LABEL, 0, N_("Compatibility")},
486 {"BorderProperties.lineshift", GD_TYPE_BOOLEAN, 0, N_("Line shifting border"), CAVE_OFFSET(lineshift), 1, N_("If this is set to true, the player exiting on either side will appear one row lower or upper on the other side.")},
487 {"BorderProperties.objectwraparound", GD_TYPE_BOOLEAN, 0, N_("Objects wrap around"), CAVE_OFFSET(wraparound_objects), 1, N_("If true, objects will wrap around the cave borders as well, ie. if you drag a line to the left, part of it will appear on the right hand side of the cave. The drawing in this case is also affected by the line shifting border property. If that one is enabled, too, crossing the left hand side or right hand side boundary will decrement or increment the row, and crossing the top or the bottom boundary will have no effect at all.")},
488 {"BorderProperties.scan", GD_TYPE_BOOLEAN, 0, N_("Scan first and last row"), CAVE_OFFSET(border_scan_first_and_last), 1, N_("Elements move on first and last row, too.")},
489 {"ShortExplosions", GD_TYPE_BOOLEAN, 0, N_("Short explosions"), CAVE_OFFSET(short_explosions), 1, N_("In 1stB, explosions were longer, took five cave frames to complete, as opposed to four in the original.")},
490 {"SkeletonsWorthDiamonds", GD_TYPE_INT, 0, N_("Skeletons worth diamonds"), CAVE_OFFSET(skeletons_worth_diamonds), 1, N_("The number of diamonds each skeleton is worth."), 0, 10},
491 {"GravityAffectsAll", GD_TYPE_BOOLEAN, 0, N_("Gravity change affects everything"), CAVE_OFFSET(gravity_affects_all), 1, N_("If this is enabled, changing the gravity will also affect bladders (moving and pushing), bladder spenders, falling walls and waiting stones. Otherwise, those elements behave as gravity was always pointing downwards.")},
493 /* notes - a tab on its own */
494 {"Notes", GD_TYPE_LONGSTRING, 0, N_("Notes"), G_STRUCT_OFFSET(Cave, notes), 1, N_("Long description of the cave.")},
496 {NULL}
503 /* entries. */
504 /* type given for each element;
505 * GD_TYPE_ELEMENT represents a combo box of gdash objects.
506 * GD_TAB&LABEL represents a notebook tab or a label.
507 * others are self-explanatory. */
508 const GdStructDescriptor
509 gd_replay_properties[] = {
510 /* default data */
511 {"", GD_TAB, 0, N_("Replay")},
512 {"Level", GD_TYPE_INT, 0, NULL, G_STRUCT_OFFSET(GdReplay, level), 1, NULL},
513 {"RandomSeed", GD_TYPE_INT, 0, NULL, G_STRUCT_OFFSET(GdReplay, seed), 1, NULL},
514 // {"Saved", GD_TYPE_BOOLEAN, 0, NULL, G_STRUCT_OFFSET(GdReplay, saved), 1, NULL},
515 {"Player", GD_TYPE_STRING, 0, NULL, G_STRUCT_OFFSET(GdReplay, player_name), 1, NULL},
516 {"Date", GD_TYPE_STRING, 0, NULL, G_STRUCT_OFFSET(GdReplay, date), 1, NULL},
517 {"Comment", GD_TYPE_STRING, 0, NULL, G_STRUCT_OFFSET(GdReplay, comment), 1, NULL},
518 {"Score", GD_TYPE_INT, 0, NULL, G_STRUCT_OFFSET(GdReplay, score), 1, NULL},
519 {"Duration", GD_TYPE_INT, 0, NULL, G_STRUCT_OFFSET(GdReplay, duration), 1, NULL},
520 {"Success", GD_TYPE_BOOLEAN, 0, NULL, G_STRUCT_OFFSET(GdReplay, success), 1, NULL},
521 {NULL}
526 GdPropertyDefault gd_cave_defaults_gdash[] = {
527 /* default data */
528 {CAVE_OFFSET(selectable), TRUE},
529 {CAVE_OFFSET(intermission), FALSE},
530 {CAVE_OFFSET(intermission_instantlife), FALSE},
531 {CAVE_OFFSET(intermission_rewardlife), TRUE},
532 {CAVE_OFFSET(w), 40},
533 {CAVE_OFFSET(h), 22},
534 {CAVE_OFFSET(x1), 0},
535 {CAVE_OFFSET(y1), 0},
536 {CAVE_OFFSET(x2), 39},
537 {CAVE_OFFSET(y2), 21},
538 {CAVE_OFFSET(colorb), 0},
539 {CAVE_OFFSET(color0), 0},
540 {CAVE_OFFSET(color1), 8},
541 {CAVE_OFFSET(color2), 11},
542 {CAVE_OFFSET(color3), 1},
543 {CAVE_OFFSET(color4), 5},
544 {CAVE_OFFSET(color5), 6},
546 /* difficulty */
547 {CAVE_OFFSET(level_diamonds[0]), 10},
548 {CAVE_OFFSET(diamond_value), 0},
549 {CAVE_OFFSET(extra_diamond_value), 0},
550 {CAVE_OFFSET(level_time[0]), 999},
551 {CAVE_OFFSET(max_time), 999},
552 {CAVE_OFFSET(pal_timing), FALSE},
553 {CAVE_OFFSET(level_timevalue[0]), 1},
554 {CAVE_OFFSET(scheduling), GD_SCHEDULING_MILLISECONDS},
555 {CAVE_OFFSET(level_ckdelay[0]), 0},
556 {CAVE_OFFSET(level_hatching_delay_time[0]), 2},
557 {CAVE_OFFSET(level_speed[0]), 200},
558 {CAVE_OFFSET(level_hatching_delay_frame[0]), 21},
559 {CAVE_OFFSET(level_rand[0]), 0},
561 /* initial fill */
562 {CAVE_OFFSET(initial_border), O_STEEL},
563 {CAVE_OFFSET(initial_fill), O_DIRT},
564 {CAVE_OFFSET(random_fill[0]), O_DIRT},
565 {CAVE_OFFSET(random_fill_probability[0]), 0},
566 {CAVE_OFFSET(random_fill[1]), O_DIRT},
567 {CAVE_OFFSET(random_fill_probability[1]), 0},
568 {CAVE_OFFSET(random_fill[2]), O_DIRT},
569 {CAVE_OFFSET(random_fill_probability[2]), 0},
570 {CAVE_OFFSET(random_fill[3]), O_DIRT},
571 {CAVE_OFFSET(random_fill_probability[3]), 0},
573 /* PLAYER */
574 {CAVE_OFFSET(diagonal_movements), FALSE},
575 {CAVE_OFFSET(active_is_first_found), TRUE},
576 {CAVE_OFFSET(snap_element), O_SPACE},
577 {CAVE_OFFSET(pushing_stone_prob), 250000},
578 {CAVE_OFFSET(pushing_stone_prob_sweet), 1000000},
579 {CAVE_OFFSET(level_bonus_time), 30},
580 {CAVE_OFFSET(pneumatic_hammer_frame), 5},
581 {CAVE_OFFSET(hammered_walls_reappear), FALSE},
582 {CAVE_OFFSET(hammered_wall_reappear_frame), 100},
583 {CAVE_OFFSET(voodoo_collects_diamonds), FALSE},
584 {CAVE_OFFSET(voodoo_can_be_destroyed), TRUE},
585 {CAVE_OFFSET(voodoo_dies_by_stone), FALSE},
586 {CAVE_OFFSET(level_penalty_time), 30},
588 /* magic wall */
589 {CAVE_OFFSET(level_magic_wall_time), 999},
590 {CAVE_OFFSET(magic_diamond_to), O_STONE_F},
591 {CAVE_OFFSET(magic_stone_to), O_DIAMOND_F},
592 {CAVE_OFFSET(magic_wall_stops_amoeba), TRUE},
593 {CAVE_OFFSET(magic_timer_wait_for_hatching), FALSE},
594 /* amoeba */
595 {CAVE_OFFSET(amoeba_timer_started_immediately), TRUE},
596 {CAVE_OFFSET(amoeba_timer_wait_for_hatching), FALSE},
598 {CAVE_OFFSET(level_amoeba_threshold), 200},
599 {CAVE_OFFSET(amoeba_growth_prob), 31250},
600 {CAVE_OFFSET(amoeba_fast_growth_prob), 250000},
601 {CAVE_OFFSET(level_amoeba_time), 999},
602 {CAVE_OFFSET(amoeba_timer_started_immediately), TRUE},
603 {CAVE_OFFSET(amoeba_timer_wait_for_hatching), FALSE},
604 {CAVE_OFFSET(too_big_amoeba_to), O_STONE},
605 {CAVE_OFFSET(enclosed_amoeba_to), O_DIAMOND},
606 /* amoeba */
607 {CAVE_OFFSET(level_amoeba_2_threshold), 200},
608 {CAVE_OFFSET(amoeba_2_growth_prob), 31250},
609 {CAVE_OFFSET(amoeba_2_fast_growth_prob), 250000},
610 {CAVE_OFFSET(level_amoeba_2_time), 999},
611 {CAVE_OFFSET(too_big_amoeba_2_to), O_STONE},
612 {CAVE_OFFSET(enclosed_amoeba_2_to), O_DIAMOND},
613 {CAVE_OFFSET(amoeba_2_explodes_by_amoeba), TRUE},
614 {CAVE_OFFSET(amoeba_2_looks_like), O_AMOEBA_2},
615 {CAVE_OFFSET(amoeba_2_explodes_to), O_SPACE},
617 /* water */
618 {CAVE_OFFSET(water_does_not_flow_down), FALSE},
620 /* slime */
621 {CAVE_OFFSET(slime_predictable), TRUE},
622 {CAVE_OFFSET(level_slime_seed_c64), -1},
623 {CAVE_OFFSET(level_slime_permeability_c64), 0},
624 {CAVE_OFFSET(level_slime_permeability), 1000000},
625 {CAVE_OFFSET(slime_eats_1), O_DIAMOND},
626 {CAVE_OFFSET(slime_converts_1), O_DIAMOND_F},
627 {CAVE_OFFSET(slime_eats_2), O_STONE},
628 {CAVE_OFFSET(slime_converts_2), O_STONE_F},
630 /* acid */
631 {CAVE_OFFSET(acid_eats_this), O_DIRT},
632 {CAVE_OFFSET(acid_spread_ratio), 31250},
633 {CAVE_OFFSET(acid_turns_to), O_EXPLODE_3},
635 /* biter */
636 {CAVE_OFFSET(biter_delay_frame), 0},
637 {CAVE_OFFSET(biter_eat), O_DIAMOND},
639 /* bladder */
640 {CAVE_OFFSET(bladder_converts_by), O_VOODOO},
642 /* SOUND */
643 {CAVE_OFFSET(amoeba_sound), TRUE},
644 {CAVE_OFFSET(magic_wall_sound), TRUE},
645 {CAVE_OFFSET(slime_sound), TRUE},
646 {CAVE_OFFSET(acid_spread_sound), TRUE},
647 {CAVE_OFFSET(biter_sound), TRUE},
648 {CAVE_OFFSET(bladder_sound), TRUE},
649 {CAVE_OFFSET(water_sound), TRUE},
650 {CAVE_OFFSET(stone_sound), TRUE},
651 {CAVE_OFFSET(diamond_sound), TRUE},
652 {CAVE_OFFSET(falling_wall_sound), TRUE},
653 {CAVE_OFFSET(expanding_wall_sound), TRUE},
654 {CAVE_OFFSET(nitro_sound), TRUE},
655 {CAVE_OFFSET(pneumatic_hammer_sound), TRUE},
656 {CAVE_OFFSET(bladder_spender_sound), TRUE},
657 {CAVE_OFFSET(bladder_convert_sound), TRUE},
658 {CAVE_OFFSET(gravity_change_sound), TRUE},
660 /* creature effects */
661 {CAVE_OFFSET(creatures_backwards), FALSE},
662 {CAVE_OFFSET(creatures_direction_auto_change_time), 0},
663 {CAVE_OFFSET(creatures_direction_auto_change_on_start), FALSE},
664 /* cave effects */
665 {CAVE_OFFSET(explosion_to), O_SPACE},
666 {CAVE_OFFSET(diamond_birth_to), O_DIAMOND},
667 {CAVE_OFFSET(bomb_explode_to), O_BRICK},
668 {CAVE_OFFSET(nitro_explode_to), O_SPACE},
669 {CAVE_OFFSET(falling_stone_to), O_STONE_F},
670 {CAVE_OFFSET(bouncing_stone_to), O_STONE},
671 {CAVE_OFFSET(falling_diamond_to), O_DIAMOND_F},
672 {CAVE_OFFSET(bouncing_diamond_to), O_DIAMOND},
673 /* visual effects */
674 {CAVE_OFFSET(expanding_wall_looks_like), O_BRICK},
675 {CAVE_OFFSET(dirt_looks_like), O_DIRT},
676 /* gravity */
677 {CAVE_OFFSET(gravity), MV_DOWN},
678 {CAVE_OFFSET(gravity_switch_active), FALSE},
679 {CAVE_OFFSET(skeletons_needed_for_pot), 5},
680 {CAVE_OFFSET(gravity_change_time), 10},
682 /* COMPATIBILITY */
683 {CAVE_OFFSET(border_scan_first_and_last), TRUE},
684 {CAVE_OFFSET(lineshift), FALSE},
685 {CAVE_OFFSET(wraparound_objects), FALSE},
686 {CAVE_OFFSET(short_explosions), TRUE},
687 {CAVE_OFFSET(skeletons_worth_diamonds), 0},
688 {CAVE_OFFSET(gravity_affects_all), TRUE},
689 {-1},
694 /* return new element, which appears after elem is hammered. */
695 /* returns o_none, if elem is invalid for hammering. */
696 GdElement
697 gd_get_hammered_element(GdElement elem)
699 switch (elem) { /* what is under the pneumatic hammer? */
700 case O_WALLED_KEY_1:
701 return O_KEY_1;
702 case O_WALLED_KEY_2:
703 return O_KEY_2;
704 case O_WALLED_KEY_3:
705 return O_KEY_3;
706 case O_WALLED_DIAMOND:
707 return O_DIAMOND;
708 case O_BRICK:
709 case O_BRICK_SLOPED_UP_RIGHT:
710 case O_BRICK_SLOPED_UP_LEFT:
711 case O_BRICK_SLOPED_DOWN_RIGHT:
712 case O_BRICK_SLOPED_DOWN_LEFT:
713 case O_BRICK_NON_SLOPED:
714 case O_MAGIC_WALL:
715 case O_STEEL_EXPLODABLE:
716 case O_EXPANDING_WALL:
717 case O_V_EXPANDING_WALL:
718 case O_H_EXPANDING_WALL:
719 case O_FALLING_WALL:
720 case O_FALLING_WALL_F:
721 return O_SPACE;
722 default:
723 return O_NONE;
728 void
729 gd_cave_db_init()
731 int i;
732 gboolean cell_used[NUM_OF_CELLS];
733 GHashTable *pointers;
734 gboolean lowercase_names=TRUE;
736 for (i=0; i<NUM_OF_CELLS; i++)
737 cell_used[i]=FALSE;
739 /* TRANSLATORS: some languages (for example, german) do not have lowercase nouns. */
740 /* When gdash generates the list of lowercase element names, this has to be */
741 /* taken into account. Therefore we have a string, which must be changed */
742 /* by the translator to select the behavior. */
743 /* For example, the name of the element is "Brick wall", as in a button, it has to be */
744 /* written with an uppercase initial. But if "Line of brick wall", the B is changed to b. */
745 /* However, this is not allowed in some languages, for example, German. */
746 /* So one writes "Ziegelmauer", and "Linie aus Ziegelmauer", the Z is not changed to z. */
747 /* Set the translated string to "lowercase-element-names-yes", if your language */
748 /* allows writing nouns with lowercase initials. Set it to "lowercase-element-names-no", */
749 /* if not: for example, german. Do not translate the string, but set the behavior! */
750 if (g_str_equal(_("lowercase-element-names-yes"), "lowercase-element-names-no"))
751 lowercase_names=FALSE;
754 /* check element database for faults. */
755 for (i=0; gd_elements[i].element!=-1; i++) {
756 int j, m;
758 if (gd_elements[i].element!=i)
759 g_critical("element: i:0x%x!=0x%x", i, gd_elements[i].element);
760 /* if it has a name, create a lowercase name (of the translated one). will be used by the editor */
761 if (gd_elements[i].name) {
762 if (lowercase_names)
763 /* the function allocates a new string, but it is needed as long as the app is running */
764 gd_elements[i].lowercase_name=g_utf8_strdown(gettext(gd_elements[i].name), -1);
765 else
766 /* only translate, no lowercase. */
767 gd_elements[i].lowercase_name=gettext(gd_elements[i].name);
770 /* we do not like generated pixbufs for games. only those that are in the png. */
771 if (ABS(gd_elements[i].image_game)>NUM_OF_CELLS_X*NUM_OF_CELLS_Y)
772 g_critical("game pixbuf for element %x (%s) bigger than png size", i, gd_elements[i].name);
774 if (gd_elements[i].image<0)
775 g_critical("editor pixbuf for element %x (%s) should not be animated", i, gd_elements[i].name);
777 if (gd_elements[i].properties&P_CAN_BE_HAMMERED && gd_get_hammered_element((GdElement) i)==O_NONE)
778 g_critical("element %x (%s) can be hammered, but get_hammered_element does not define another one", i, gd_elements[i].name);
780 m=gd_elements[i].image<0?8:1;
781 for (j=0; j<m; j++)
782 cell_used[ABS(gd_elements[i].image)+j]=TRUE;
783 m=gd_elements[i].image_simple<0?8:1;
784 for (j=0; j<m; j++)
785 cell_used[ABS(gd_elements[i].image_simple)+j]=TRUE;
786 m=gd_elements[i].image_game<0?8:1;
787 for (j=0; j<m; j++)
788 cell_used[ABS(gd_elements[i].image_game)+j]=TRUE;
792 g_print("Free pixbuf indexes: ");
793 for (i=NUM_OF_CELLS_X*NUM_OF_CELLS_Y; i<NUM_OF_CELLS; i++) {
794 if (!cell_used[i])
795 g_print("%d ", i);
797 g_print("\n");
800 /* uncomment this, to show free element->character characters. */
802 gd_create_char_to_element_table();
803 g_print("Free characters: ");
804 for (i=32; i<128; i++)
805 if (gd_char_to_element[i]==O_UNKNOWN)
806 g_print("%c", i);
807 g_print("\n");
810 /* check the cave property database for faults. */
811 pointers=g_hash_table_new(g_direct_hash, g_direct_equal);
812 for (i=0; gd_cave_properties[i].identifier!=NULL; i++) {
813 GdType type=gd_cave_properties[i].type;
815 switch (type) {
816 case GD_LABEL:
817 case GD_TAB:
818 /* some lines are used for the user interface. these should not have an identifier. */
819 if (strcmp(gd_cave_properties[i].identifier, "")!=0) {
820 g_critical ("ui lines in cave properties should not have identifiers: %s", gd_cave_properties[i].identifier);
821 g_assert_not_reached();
823 break;
825 case GD_TYPE_STRING:
826 /* check if any of the properties are designated as string arrays. they are not supported in
827 * file read/write and operations, also they do not even make any sense! */
828 if (gd_cave_properties[i].count!=1) {
829 g_critical ("string arrays have no sense in cave properties: %s", gd_cave_properties[i].identifier);
830 g_assert_not_reached();
832 break;
834 case GD_TYPE_LONGSTRING:
835 if (gd_cave_properties[i].count!=1) {
836 g_critical ("longstring arrays have no sense cave properties: %s", gd_cave_properties[i].identifier);
837 g_assert_not_reached();
839 if (gd_cave_properties[i+1].identifier!=NULL && gd_cave_properties[i+1].type!=GD_TAB) {
840 g_critical ("every longstring must be followed by a new tab (this is for the editor): %s", gd_cave_properties[i].identifier);
841 g_assert_not_reached();
843 break;
845 case GD_TYPE_EFFECT:
846 /* the same applies for effects. */
847 if (gd_cave_properties[i].count!=1) {
848 g_critical ("effect arrays not supported in cave properties: %s", gd_cave_properties[i].identifier);
849 g_assert_not_reached();
851 break;
853 case GD_TYPE_COLOR:
854 /* the same applies for effects. */
855 if (gd_cave_properties[i].count!=1) {
856 g_critical ("color arrays not supported in cave properties: %s", gd_cave_properties[i].identifier);
857 g_assert_not_reached();
859 break;
861 default:
862 break;
865 if (type!=GD_LABEL && (gd_cave_properties[i].flags&GD_SHOW_LEVEL_LABEL)) {
866 g_critical ("show_level_label only for labels: line %d", i);
867 g_assert_not_reached();
870 if (type!=GD_LABEL && type!=GD_TAB) {
871 const char *another_prop;
873 /* other types */
874 /* check if its pointer is not the same as another one's */
875 /* +1 is added so it is never zero */
876 if (!(gd_cave_properties[i].flags&GD_DONT_SAVE) && strcmp(gd_cave_properties[i].identifier, "")==0) {
877 g_critical ("property should have a bdcff identifier: line %d, name %s", i, gd_cave_properties[i].name);
878 g_assert_not_reached();
880 another_prop=g_hash_table_lookup(pointers, GINT_TO_POINTER(gd_cave_properties[i].offset+1));
881 if (another_prop!=NULL) {
882 g_critical("property %s has the same pointer as property %s", gd_cave_properties[i].identifier, another_prop);
883 g_assert_not_reached();
884 } else
885 /* value is the identifier, so we can report the OLD one if the check fails */
886 g_hash_table_insert(pointers, GINT_TO_POINTER(gd_cave_properties[i].offset+1), gd_cave_properties[i].identifier);
889 g_hash_table_destroy(pointers);