2 * Copyright (c) 2007, 2008, 2009, 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.
18 #include <glib/gi18n.h>
23 /* make all caves selectable. */
24 static boolean gd_import_as_all_caves_selectable = TRUE;
26 /* conversion table for imported bd1 caves. */
27 static const GdElement bd1_import_table[] =
29 /* 0 */ O_SPACE, O_DIRT, O_BRICK, O_MAGIC_WALL,
30 /* 4 */ O_PRE_OUTBOX, O_OUTBOX, O_STEEL_EXPLODABLE, O_STEEL,
31 /* 8 */ O_FIREFLY_1, O_FIREFLY_2, O_FIREFLY_3, O_FIREFLY_4,
32 /* c */ O_FIREFLY_1, O_FIREFLY_2, O_FIREFLY_3, O_FIREFLY_4,
33 /* 10 */ O_STONE, O_STONE, O_STONE_F, O_STONE_F,
34 /* 14 */ O_DIAMOND, O_DIAMOND, O_DIAMOND_F, O_DIAMOND_F,
35 /* 18 */ O_ACID, O_ACID, O_EXPLODE_1, O_EXPLODE_2, /* ACID: marek roth extension in crazy dream 3 */
36 /* 1c */ O_EXPLODE_3, O_EXPLODE_4, O_EXPLODE_5, O_PRE_DIA_1,
37 /* 20 */ O_PRE_DIA_2, O_PRE_DIA_3, O_PRE_DIA_4, O_PRE_DIA_5,
38 /* 24 */ O_PRE_DIA_5, O_INBOX, O_PRE_PL_1, O_PRE_PL_2,
39 /* 28 */ O_PRE_PL_3, O_PRE_PL_3, O_H_EXPANDING_WALL, O_H_EXPANDING_WALL,
40 /* 2c */ O_UNKNOWN, O_UNKNOWN, O_UNKNOWN, O_UNKNOWN,
41 /* 30 */ O_BUTTER_4, O_BUTTER_1, O_BUTTER_2, O_BUTTER_3,
42 /* 34 */ O_BUTTER_4, O_BUTTER_1, O_BUTTER_2, O_BUTTER_3,
43 /* 38 */ O_PLAYER, O_PLAYER, O_AMOEBA, O_AMOEBA,
44 /* 3c */ O_VOODOO, O_INVIS_OUTBOX, O_SLIME, O_UNKNOWN
47 /* conversion table for imported plck caves. */
48 static const GdElement plck_import_nybble[] =
50 /* 0 */ O_STONE, O_DIAMOND, O_MAGIC_WALL, O_BRICK,
51 /* 4 */ O_STEEL, O_H_EXPANDING_WALL, O_VOODOO, O_DIRT,
52 /* 8 */ O_FIREFLY_1, O_BUTTER_4, O_AMOEBA, O_SLIME,
53 /* 12 */ O_PRE_INVIS_OUTBOX, O_PRE_OUTBOX, O_INBOX, O_SPACE
56 /* conversion table for imported 1stb caves. */
57 static const GdElement firstboulder_import_table[] =
59 /* 0 */ O_SPACE, O_DIRT, O_BRICK, O_MAGIC_WALL,
60 /* 4 */ O_PRE_OUTBOX, O_OUTBOX, O_PRE_INVIS_OUTBOX, O_INVIS_OUTBOX,
61 /* 8 */ O_FIREFLY_1, O_FIREFLY_2, O_FIREFLY_3, O_FIREFLY_4,
62 /* c */ O_FIREFLY_1, O_FIREFLY_2, O_FIREFLY_3, O_FIREFLY_4,
63 /* 10 */ O_STONE, O_STONE, O_STONE_F, O_STONE_F,
64 /* 14 */ O_DIAMOND, O_DIAMOND, O_DIAMOND_F, O_DIAMOND_F,
65 /* 18 */ O_PRE_CLOCK_1, O_PRE_CLOCK_2, O_PRE_CLOCK_3, O_PRE_CLOCK_4,
66 /* 1c */ O_BITER_SWITCH, O_BITER_SWITCH, O_BLADDER_SPENDER, O_PRE_DIA_1,
67 /* 20 */ O_PRE_DIA_1, O_PRE_DIA_2, O_PRE_DIA_3, O_PRE_DIA_4,
68 /* 24 */ O_PRE_DIA_5, O_INBOX, O_PRE_PL_1, O_PRE_PL_2,
69 /* 28 */ O_PRE_PL_3, O_CLOCK, O_H_EXPANDING_WALL, O_H_EXPANDING_WALL, /* CLOCK: not mentioned in marek's bd inside faq */
70 /* 2c */ O_CREATURE_SWITCH, O_CREATURE_SWITCH, O_EXPANDING_WALL_SWITCH, O_EXPANDING_WALL_SWITCH,
71 /* 30 */ O_BUTTER_3, O_BUTTER_4, O_BUTTER_1, O_BUTTER_2,
72 /* 34 */ O_BUTTER_3, O_BUTTER_4, O_BUTTER_1, O_BUTTER_2,
73 /* 38 */ O_STEEL, O_SLIME, O_BOMB, O_SWEET,
74 /* 3c */ O_PRE_STONE_1, O_PRE_STONE_2, O_PRE_STONE_3, O_PRE_STONE_4,
75 /* 40 */ O_BLADDER, O_BLADDER_1, O_BLADDER_2, O_BLADDER_3,
76 /* 44 */ O_BLADDER_4, O_BLADDER_5, O_BLADDER_6, O_BLADDER_7,
77 /* 48 */ O_BLADDER_8, O_BLADDER_8, O_EXPLODE_1, O_EXPLODE_1,
78 /* 4c */ O_EXPLODE_2, O_EXPLODE_3, O_EXPLODE_4, O_EXPLODE_5,
79 /* 50 */ O_PLAYER, O_PLAYER, O_PLAYER_BOMB, O_PLAYER_BOMB,
80 /* 54 */ O_PLAYER_GLUED, O_PLAYER_GLUED, O_VOODOO, O_AMOEBA,
81 /* 58 */ O_AMOEBA, O_BOMB_TICK_1, O_BOMB_TICK_2, O_BOMB_TICK_3,
82 /* 5c */ O_BOMB_TICK_4, O_BOMB_TICK_5, O_BOMB_TICK_6, O_BOMB_TICK_7,
83 /* 60 */ O_BOMB_EXPL_1, O_BOMB_EXPL_2, O_BOMB_EXPL_3, O_BOMB_EXPL_4,
84 /* 64 */ O_GHOST, O_GHOST, O_GHOST_EXPL_1, O_GHOST_EXPL_2,
85 /* 68 */ O_GHOST_EXPL_3, O_GHOST_EXPL_4, O_GRAVESTONE, O_STONE_GLUED,
86 /* 6c */ O_DIAMOND_GLUED, O_DIAMOND_KEY, O_TRAPPED_DIAMOND, O_GRAVESTONE,
87 /* 70 */ O_WAITING_STONE, O_WAITING_STONE, O_CHASING_STONE, O_CHASING_STONE,
88 /* 74 */ O_PRE_STEEL_1, O_PRE_STEEL_2, O_PRE_STEEL_3, O_PRE_STEEL_4,
89 /* 78 */ O_BITER_1, O_BITER_2, O_BITER_3, O_BITER_4,
90 /* 7c */ O_BITER_1, O_BITER_2, O_BITER_3, O_BITER_4,
93 /* conversion table for imported crazy dream caves. */
94 static const GdElement crazydream_import_table[] =
96 /* 0 */ O_SPACE, O_DIRT, O_BRICK, O_MAGIC_WALL,
97 /* 4 */ O_PRE_OUTBOX, O_OUTBOX, O_PRE_INVIS_OUTBOX, O_INVIS_OUTBOX,
98 /* 8 */ O_FIREFLY_1, O_FIREFLY_2, O_FIREFLY_3, O_FIREFLY_4,
99 /* c */ O_FIREFLY_1, O_FIREFLY_2, O_FIREFLY_3, O_FIREFLY_4,
100 /* 10 */ O_STONE, O_STONE, O_STONE_F, O_STONE_F,
101 /* 14 */ O_DIAMOND, O_DIAMOND, O_DIAMOND_F, O_DIAMOND_F,
102 /* 18 */ O_PRE_CLOCK_1, O_PRE_CLOCK_2, O_PRE_CLOCK_3, O_PRE_CLOCK_4,
103 /* 1c */ O_BITER_SWITCH, O_BITER_SWITCH, O_BLADDER_SPENDER, O_PRE_DIA_1, /* 6 different stages */
104 /* 20 */ O_PRE_DIA_1, O_PRE_DIA_2, O_PRE_DIA_3, O_PRE_DIA_4,
105 /* 24 */ O_PRE_DIA_5, O_INBOX, O_PRE_PL_1, O_PRE_PL_2,
106 /* 28 */ O_PRE_PL_3, O_CLOCK, O_H_EXPANDING_WALL, O_H_EXPANDING_WALL, /* CLOCK: not mentioned in marek's bd inside faq */
107 /* 2c */ O_CREATURE_SWITCH, O_CREATURE_SWITCH, O_EXPANDING_WALL_SWITCH, O_EXPANDING_WALL_SWITCH,
108 /* 30 */ O_BUTTER_3, O_BUTTER_4, O_BUTTER_1, O_BUTTER_2,
109 /* 34 */ O_BUTTER_3, O_BUTTER_4, O_BUTTER_1, O_BUTTER_2,
110 /* 38 */ O_STEEL, O_SLIME, O_BOMB, O_SWEET,
111 /* 3c */ O_PRE_STONE_1, O_PRE_STONE_2, O_PRE_STONE_3, O_PRE_STONE_4,
112 /* 40 */ O_BLADDER, O_BLADDER_1, O_BLADDER_2, O_BLADDER_3,
113 /* 44 */ O_BLADDER_4, O_BLADDER_5, O_BLADDER_6, O_BLADDER_7,
114 /* 48 */ O_BLADDER_8, O_BLADDER_8|SCANNED, O_EXPLODE_1, O_EXPLODE_1,
115 /* 4c */ O_EXPLODE_2, O_EXPLODE_3, O_EXPLODE_4, O_EXPLODE_5,
116 /* 50 */ O_PLAYER, O_PLAYER, O_PLAYER_BOMB, O_PLAYER_BOMB,
117 /* 54 */ O_PLAYER_GLUED, O_PLAYER_GLUED, O_VOODOO, O_AMOEBA,
118 /* 58 */ O_AMOEBA, O_BOMB_TICK_1, O_BOMB_TICK_2, O_BOMB_TICK_3,
119 /* 5c */ O_BOMB_TICK_4, O_BOMB_TICK_5, O_BOMB_TICK_6, O_BOMB_TICK_7,
120 /* 60 */ O_BOMB_EXPL_1, O_BOMB_EXPL_2, O_BOMB_EXPL_3, O_BOMB_EXPL_4,
121 /* 64 */ O_GHOST, O_GHOST, O_GHOST_EXPL_1, O_GHOST_EXPL_2,
122 /* 68 */ O_GHOST_EXPL_3, O_GHOST_EXPL_4, O_GRAVESTONE, O_STONE_GLUED,
123 /* 6c */ O_DIAMOND_GLUED, O_DIAMOND_KEY, O_TRAPPED_DIAMOND, O_GRAVESTONE,
124 /* 70 */ O_WAITING_STONE, O_WAITING_STONE, O_CHASING_STONE, O_CHASING_STONE,
125 /* 74 */ O_PRE_STEEL_1, O_PRE_STEEL_2, O_PRE_STEEL_3, O_PRE_STEEL_4,
126 /* 78 */ O_BITER_1, O_BITER_2, O_BITER_3, O_BITER_4,
127 /* 7c */ O_BITER_1, O_BITER_2, O_BITER_3, O_BITER_4,
129 /* 80 */ O_POT, O_PLAYER_STIRRING, O_GRAVITY_SWITCH, O_GRAVITY_SWITCH,
130 /* 84 */ O_PNEUMATIC_HAMMER, O_PNEUMATIC_HAMMER, O_BOX, O_BOX,
131 /* 88 */ O_UNKNOWN, O_UNKNOWN, O_ACID, O_ACID,
132 /* 8c */ O_KEY_1, O_KEY_2, O_KEY_3, O_UNKNOWN,
133 /* 90 */ O_UNKNOWN, O_UNKNOWN, O_UNKNOWN, O_UNKNOWN,
134 /* 94 */ O_UNKNOWN, O_TELEPORTER, O_UNKNOWN, O_SKELETON,
135 /* 98 */ O_WATER, O_WATER_16, O_WATER_15, O_WATER_14,
136 /* 9c */ O_WATER_13, O_WATER_12, O_WATER_11, O_WATER_10,
137 /* a0 */ O_WATER_9, O_WATER_8, O_WATER_7, O_WATER_6,
138 /* a4 */ O_WATER_5, O_WATER_4, O_WATER_3, O_WATER_2,
139 /* a8 */ O_WATER_1, O_COW_ENCLOSED_1, O_COW_ENCLOSED_2, O_COW_ENCLOSED_3,
140 /* ac */ O_COW_ENCLOSED_4, O_COW_ENCLOSED_5, O_COW_ENCLOSED_6, O_COW_ENCLOSED_7,
141 /* b0 */ O_COW_1, O_COW_2, O_COW_3, O_COW_4,
142 /* b4 */ O_COW_1, O_COW_2, O_COW_3, O_COW_4,
143 /* b8 */ O_DIRT_GLUED, O_STEEL_EXPLODABLE, O_DOOR_1, O_DOOR_2,
144 /* bc */ O_DOOR_3, O_FALLING_WALL, O_FALLING_WALL_F, O_FALLING_WALL_F,
145 /* c0 */ O_WALLED_DIAMOND, O_UNKNOWN, O_WALLED_KEY_1, O_WALLED_KEY_2,
146 /* c5 = brick?! (vital key), c7 = dirt?! (think twice) */
147 /* c7 = dirt, as it has a code which will change it to dirt. */
148 /* c4 */ O_WALLED_KEY_3, O_BRICK, O_UNKNOWN, O_DIRT,
149 /* c8 */ O_DIRT2, O_UNKNOWN, O_UNKNOWN, O_UNKNOWN,
150 /* cc */ O_UNKNOWN, O_UNKNOWN, O_UNKNOWN, O_UNKNOWN,
151 /* d0 */ O_UNKNOWN, O_UNKNOWN, O_UNKNOWN, O_UNKNOWN,
152 /* d4 */ O_UNKNOWN, O_UNKNOWN, O_UNKNOWN, O_UNKNOWN,
153 /* d8 */ O_UNKNOWN, O_UNKNOWN, O_UNKNOWN, O_UNKNOWN,
154 /* dc */ O_UNKNOWN, O_UNKNOWN, O_UNKNOWN, O_UNKNOWN,
155 /* e0 */ O_ALT_FIREFLY_1, O_ALT_FIREFLY_2, O_ALT_FIREFLY_3, O_ALT_FIREFLY_4,
156 /* e4 */ O_ALT_FIREFLY_1, O_ALT_FIREFLY_2, O_ALT_FIREFLY_3, O_ALT_FIREFLY_4,
157 /* e8 */ O_ALT_BUTTER_3, O_ALT_BUTTER_4, O_ALT_BUTTER_1, O_ALT_BUTTER_2,
158 /* ec */ O_ALT_BUTTER_3, O_ALT_BUTTER_4, O_ALT_BUTTER_1, O_ALT_BUTTER_2,
159 /* f0 */ O_WATER, O_WATER, O_WATER, O_WATER,
160 /* f4 */ O_WATER, O_WATER, O_WATER, O_WATER,
161 /* f8 */ O_WATER, O_WATER, O_WATER, O_WATER,
162 /* fc */ O_WATER, O_WATER, O_WATER, O_WATER,
165 /* conversion table for imported 1stb caves. */
166 const GdElement gd_crazylight_import_table[] =
168 /* 0 */ O_SPACE, O_DIRT, O_BRICK, O_MAGIC_WALL,
169 /* 4 */ O_PRE_OUTBOX, O_OUTBOX, O_PRE_INVIS_OUTBOX, O_INVIS_OUTBOX,
170 /* 8 */ O_FIREFLY_1, O_FIREFLY_2, O_FIREFLY_3, O_FIREFLY_4,
171 /* c */ O_FIREFLY_1|SCANNED, O_FIREFLY_2|SCANNED, O_FIREFLY_3|SCANNED, O_FIREFLY_4|SCANNED,
172 /* 10 */ O_STONE, O_STONE|SCANNED, O_STONE_F, O_STONE_F|SCANNED,
173 /* 14 */ O_DIAMOND, O_DIAMOND|SCANNED, O_DIAMOND_F, O_DIAMOND_F|SCANNED,
174 /* 18 */ O_PRE_CLOCK_1, O_PRE_CLOCK_2, O_PRE_CLOCK_3, O_PRE_CLOCK_4,
175 /* 1c */ O_BITER_SWITCH, O_BITER_SWITCH, O_BLADDER_SPENDER, O_PRE_DIA_1, /* 6 different stages, the first is the pre_dia_0 */
176 /* 20 */ O_PRE_DIA_1, O_PRE_DIA_2, O_PRE_DIA_3, O_PRE_DIA_4,
177 /* 24 */ O_PRE_DIA_5, O_INBOX, O_PRE_PL_1, O_PRE_PL_2,
178 /* 28 */ O_PRE_PL_3, O_CLOCK, O_H_EXPANDING_WALL, O_H_EXPANDING_WALL|SCANNED, /* CLOCK: not mentioned in marek's bd inside faq */
179 /* 2c */ O_CREATURE_SWITCH, O_CREATURE_SWITCH, O_EXPANDING_WALL_SWITCH, O_EXPANDING_WALL_SWITCH,
180 /* 30 */ O_BUTTER_3, O_BUTTER_4, O_BUTTER_1, O_BUTTER_2,
181 /* 34 */ O_BUTTER_3|SCANNED, O_BUTTER_4|SCANNED, O_BUTTER_1|SCANNED, O_BUTTER_2|SCANNED,
182 /* 38 */ O_STEEL, O_SLIME, O_BOMB, O_SWEET,
183 /* 3c */ O_PRE_STONE_1, O_PRE_STONE_2, O_PRE_STONE_3, O_PRE_STONE_4,
184 /* 40 */ O_BLADDER, O_BLADDER_1, O_BLADDER_2, O_BLADDER_3,
185 /* 44 */ O_BLADDER_4, O_BLADDER_5, O_BLADDER_6, O_BLADDER_7,
186 /* 48 */ O_BLADDER_8, O_BLADDER_8|SCANNED, O_EXPLODE_1, O_EXPLODE_1,
187 /* 4c */ O_EXPLODE_2, O_EXPLODE_3, O_EXPLODE_4, O_EXPLODE_5,
188 /* 50 */ O_PLAYER, O_PLAYER|SCANNED, O_PLAYER_BOMB, O_PLAYER_BOMB|SCANNED,
189 /* 54 */ O_PLAYER_GLUED, O_PLAYER_GLUED|SCANNED, O_VOODOO, O_AMOEBA,
190 /* 58 */ O_AMOEBA|SCANNED, O_BOMB_TICK_1, O_BOMB_TICK_2, O_BOMB_TICK_3,
191 /* 5c */ O_BOMB_TICK_4, O_BOMB_TICK_5, O_BOMB_TICK_6, O_BOMB_TICK_7,
192 /* 60 */ O_BOMB_EXPL_1, O_BOMB_EXPL_2, O_BOMB_EXPL_3, O_BOMB_EXPL_4,
193 /* 64 */ O_ACID, O_ACID, O_FALLING_WALL, O_FALLING_WALL_F,
194 /* 68 */ O_FALLING_WALL_F|SCANNED, O_BOX, O_GRAVESTONE, O_STONE_GLUED,
195 /* 6c */ O_DIAMOND_GLUED, O_DIAMOND_KEY, O_TRAPPED_DIAMOND, O_GRAVESTONE,
196 /* 70 */ O_WAITING_STONE, O_WAITING_STONE|SCANNED, O_CHASING_STONE, O_CHASING_STONE|SCANNED,
197 /* 74 */ O_PRE_STEEL_1, O_PRE_STEEL_2, O_PRE_STEEL_3, O_PRE_STEEL_4,
198 /* 78 */ O_BITER_1, O_BITER_2, O_BITER_3, O_BITER_4,
199 /* 7c */ O_BITER_1|SCANNED, O_BITER_2|SCANNED, O_BITER_3|SCANNED, O_BITER_4|SCANNED,
202 GdPropertyDefault gd_defaults_bd1[] =
204 {CAVE_OFFSET(level_amoeba_threshold), 200},
205 {CAVE_OFFSET(amoeba_growth_prob), 31250},
206 {CAVE_OFFSET(amoeba_fast_growth_prob), 250000},
207 {CAVE_OFFSET(amoeba_timer_started_immediately), TRUE},
208 {CAVE_OFFSET(amoeba_timer_wait_for_hatching), FALSE},
209 {CAVE_OFFSET(lineshift), TRUE},
210 {CAVE_OFFSET(wraparound_objects), TRUE},
211 {CAVE_OFFSET(diagonal_movements), FALSE},
212 {CAVE_OFFSET(voodoo_collects_diamonds), FALSE},
213 {CAVE_OFFSET(voodoo_dies_by_stone), FALSE},
214 {CAVE_OFFSET(voodoo_disappear_in_explosion), TRUE},
215 {CAVE_OFFSET(voodoo_any_hurt_kills_player), FALSE},
216 {CAVE_OFFSET(creatures_backwards), FALSE},
217 {CAVE_OFFSET(creatures_direction_auto_change_on_start), FALSE},
218 {CAVE_OFFSET(creatures_direction_auto_change_time), 0},
219 {CAVE_OFFSET(level_hatching_delay_time[0]), 2},
220 {CAVE_OFFSET(intermission_instantlife), TRUE},
221 {CAVE_OFFSET(intermission_rewardlife), FALSE},
222 {CAVE_OFFSET(magic_wall_stops_amoeba), TRUE},
223 {CAVE_OFFSET(magic_timer_wait_for_hatching), FALSE},
224 {CAVE_OFFSET(pushing_stone_prob), 250000},
225 {CAVE_OFFSET(pushing_stone_prob_sweet), 1000000},
226 {CAVE_OFFSET(active_is_first_found), FALSE},
227 {CAVE_OFFSET(short_explosions), TRUE},
228 {CAVE_OFFSET(slime_predictable), TRUE},
229 {CAVE_OFFSET(snap_element), O_SPACE},
230 {CAVE_OFFSET(max_time), 999},
232 {CAVE_OFFSET(scheduling), GD_SCHEDULING_BD1},
233 {CAVE_OFFSET(pal_timing), TRUE},
238 GdPropertyDefault gd_defaults_bd2[] =
240 {CAVE_OFFSET(level_amoeba_threshold), 200},
241 {CAVE_OFFSET(amoeba_growth_prob), 31250},
242 {CAVE_OFFSET(amoeba_fast_growth_prob), 250000},
243 {CAVE_OFFSET(amoeba_timer_started_immediately), FALSE},
244 {CAVE_OFFSET(amoeba_timer_wait_for_hatching), FALSE},
245 {CAVE_OFFSET(lineshift), TRUE},
246 {CAVE_OFFSET(wraparound_objects), TRUE},
247 {CAVE_OFFSET(diagonal_movements), FALSE},
248 {CAVE_OFFSET(voodoo_collects_diamonds), FALSE},
249 {CAVE_OFFSET(voodoo_dies_by_stone), FALSE},
250 {CAVE_OFFSET(voodoo_disappear_in_explosion), TRUE},
251 {CAVE_OFFSET(voodoo_any_hurt_kills_player), FALSE},
252 {CAVE_OFFSET(creatures_backwards), FALSE},
253 {CAVE_OFFSET(creatures_direction_auto_change_on_start), FALSE},
254 {CAVE_OFFSET(creatures_direction_auto_change_time), 0},
255 {CAVE_OFFSET(level_hatching_delay_time[0]), 2},
256 {CAVE_OFFSET(intermission_instantlife), TRUE},
257 {CAVE_OFFSET(intermission_rewardlife), FALSE},
258 {CAVE_OFFSET(magic_wall_stops_amoeba), FALSE}, /* marek roth bd inside faq 3.0 */
259 {CAVE_OFFSET(magic_timer_wait_for_hatching), FALSE},
260 {CAVE_OFFSET(pushing_stone_prob), 250000},
261 {CAVE_OFFSET(pushing_stone_prob_sweet), 1000000},
262 {CAVE_OFFSET(active_is_first_found), FALSE},
263 {CAVE_OFFSET(short_explosions), TRUE},
264 {CAVE_OFFSET(slime_predictable), TRUE},
265 {CAVE_OFFSET(snap_element), O_SPACE},
266 {CAVE_OFFSET(max_time), 999},
268 {CAVE_OFFSET(pal_timing), TRUE},
269 {CAVE_OFFSET(scheduling), GD_SCHEDULING_BD2},
274 GdPropertyDefault gd_defaults_plck[] =
276 {CAVE_OFFSET(amoeba_growth_prob), 31250},
277 {CAVE_OFFSET(amoeba_fast_growth_prob), 250000},
278 {CAVE_OFFSET(amoeba_timer_started_immediately), FALSE},
279 {CAVE_OFFSET(amoeba_timer_wait_for_hatching), FALSE},
280 {CAVE_OFFSET(lineshift), TRUE},
281 {CAVE_OFFSET(wraparound_objects), TRUE},
282 {CAVE_OFFSET(border_scan_first_and_last), FALSE},
283 {CAVE_OFFSET(diagonal_movements), FALSE},
284 {CAVE_OFFSET(voodoo_collects_diamonds), FALSE},
285 {CAVE_OFFSET(voodoo_dies_by_stone), FALSE},
286 {CAVE_OFFSET(voodoo_disappear_in_explosion), TRUE},
287 {CAVE_OFFSET(voodoo_any_hurt_kills_player), FALSE},
288 {CAVE_OFFSET(creatures_backwards), FALSE},
289 {CAVE_OFFSET(creatures_direction_auto_change_on_start), FALSE},
290 {CAVE_OFFSET(creatures_direction_auto_change_time), 0},
291 {CAVE_OFFSET(level_hatching_delay_time[0]), 2},
292 {CAVE_OFFSET(intermission_instantlife), TRUE},
293 {CAVE_OFFSET(intermission_rewardlife), FALSE},
294 {CAVE_OFFSET(magic_wall_stops_amoeba), FALSE},
295 {CAVE_OFFSET(magic_timer_wait_for_hatching), FALSE},
296 {CAVE_OFFSET(pushing_stone_prob), 250000},
297 {CAVE_OFFSET(pushing_stone_prob_sweet), 1000000},
298 {CAVE_OFFSET(active_is_first_found), FALSE},
299 {CAVE_OFFSET(short_explosions), TRUE},
300 {CAVE_OFFSET(snap_element), O_SPACE},
301 {CAVE_OFFSET(max_time), 999},
303 {CAVE_OFFSET(pal_timing), TRUE},
304 {CAVE_OFFSET(scheduling), GD_SCHEDULING_PLCK},
309 GdPropertyDefault gd_defaults_1stb[] =
311 {CAVE_OFFSET(amoeba_growth_prob), 31250},
312 {CAVE_OFFSET(amoeba_fast_growth_prob), 250000},
313 {CAVE_OFFSET(amoeba_timer_started_immediately), FALSE},
314 {CAVE_OFFSET(amoeba_timer_wait_for_hatching), TRUE},
315 {CAVE_OFFSET(lineshift), TRUE},
316 {CAVE_OFFSET(wraparound_objects), TRUE},
317 {CAVE_OFFSET(voodoo_collects_diamonds), TRUE},
318 {CAVE_OFFSET(voodoo_dies_by_stone), TRUE},
319 {CAVE_OFFSET(voodoo_disappear_in_explosion), FALSE},
320 {CAVE_OFFSET(voodoo_any_hurt_kills_player), FALSE},
321 {CAVE_OFFSET(creatures_direction_auto_change_on_start), TRUE},
322 {CAVE_OFFSET(level_hatching_delay_time[0]), 2},
323 {CAVE_OFFSET(intermission_instantlife), FALSE},
324 {CAVE_OFFSET(intermission_rewardlife), TRUE},
325 {CAVE_OFFSET(magic_timer_wait_for_hatching), TRUE},
326 {CAVE_OFFSET(pushing_stone_prob), 250000},
327 {CAVE_OFFSET(pushing_stone_prob_sweet), 1000000},
328 {CAVE_OFFSET(active_is_first_found), TRUE},
329 {CAVE_OFFSET(short_explosions), FALSE},
330 {CAVE_OFFSET(slime_predictable), TRUE},
331 {CAVE_OFFSET(snap_element), O_SPACE},
332 {CAVE_OFFSET(max_time), 999},
334 {CAVE_OFFSET(pal_timing), TRUE},
335 {CAVE_OFFSET(scheduling), GD_SCHEDULING_PLCK},
336 {CAVE_OFFSET(amoeba_enclosed_effect), O_PRE_DIA_1}, /* not immediately to diamond, but with animation */
337 {CAVE_OFFSET(dirt_looks_like), O_DIRT2},
342 GdPropertyDefault gd_defaults_crdr_7[] =
344 {CAVE_OFFSET(amoeba_growth_prob), 31250},
345 {CAVE_OFFSET(amoeba_fast_growth_prob), 250000},
346 {CAVE_OFFSET(amoeba_timer_started_immediately), FALSE},
347 {CAVE_OFFSET(amoeba_timer_wait_for_hatching), TRUE},
348 {CAVE_OFFSET(lineshift), TRUE},
349 {CAVE_OFFSET(wraparound_objects), TRUE},
350 {CAVE_OFFSET(voodoo_collects_diamonds), TRUE},
351 {CAVE_OFFSET(voodoo_dies_by_stone), TRUE},
352 {CAVE_OFFSET(voodoo_disappear_in_explosion), FALSE},
353 {CAVE_OFFSET(voodoo_any_hurt_kills_player), FALSE},
354 {CAVE_OFFSET(creatures_direction_auto_change_on_start), FALSE},
355 {CAVE_OFFSET(level_hatching_delay_time[0]), 2},
356 {CAVE_OFFSET(intermission_instantlife), FALSE},
357 {CAVE_OFFSET(intermission_rewardlife), TRUE},
358 {CAVE_OFFSET(magic_timer_wait_for_hatching), TRUE},
359 {CAVE_OFFSET(pushing_stone_prob), 250000},
360 {CAVE_OFFSET(pushing_stone_prob_sweet), 1000000},
361 {CAVE_OFFSET(active_is_first_found), TRUE},
362 {CAVE_OFFSET(short_explosions), FALSE},
363 {CAVE_OFFSET(slime_predictable), TRUE},
364 {CAVE_OFFSET(snap_element), O_SPACE},
365 {CAVE_OFFSET(max_time), 999},
367 {CAVE_OFFSET(pal_timing), TRUE},
368 {CAVE_OFFSET(scheduling), GD_SCHEDULING_CRDR},
369 {CAVE_OFFSET(amoeba_enclosed_effect), O_PRE_DIA_1}, /* not immediately to diamond, but with animation */
370 {CAVE_OFFSET(water_does_not_flow_down), TRUE},
371 {CAVE_OFFSET(skeletons_worth_diamonds), 1}, /* in crdr, skeletons can also be used to open the gate */
372 {CAVE_OFFSET(gravity_affects_all), FALSE}, /* the intermission "survive" needs this flag */
377 GdPropertyDefault gd_defaults_crli[] =
379 {CAVE_OFFSET(amoeba_growth_prob), 31250},
380 {CAVE_OFFSET(amoeba_fast_growth_prob), 250000},
381 {CAVE_OFFSET(amoeba_timer_started_immediately), FALSE},
382 {CAVE_OFFSET(amoeba_timer_wait_for_hatching), TRUE},
383 {CAVE_OFFSET(lineshift), TRUE},
384 {CAVE_OFFSET(wraparound_objects), TRUE},
385 {CAVE_OFFSET(voodoo_collects_diamonds), TRUE},
386 {CAVE_OFFSET(voodoo_dies_by_stone), TRUE},
387 {CAVE_OFFSET(voodoo_disappear_in_explosion), FALSE},
388 {CAVE_OFFSET(voodoo_any_hurt_kills_player), FALSE},
389 {CAVE_OFFSET(creatures_direction_auto_change_on_start), FALSE},
390 {CAVE_OFFSET(level_hatching_delay_time[0]), 2},
391 {CAVE_OFFSET(intermission_instantlife), FALSE},
392 {CAVE_OFFSET(intermission_rewardlife), TRUE},
393 {CAVE_OFFSET(magic_timer_wait_for_hatching), TRUE},
394 {CAVE_OFFSET(pushing_stone_prob), 250000},
395 {CAVE_OFFSET(pushing_stone_prob_sweet), 1000000},
396 {CAVE_OFFSET(active_is_first_found), TRUE},
397 {CAVE_OFFSET(short_explosions), FALSE},
398 {CAVE_OFFSET(slime_predictable), TRUE},
399 {CAVE_OFFSET(max_time), 999},
401 {CAVE_OFFSET(pal_timing), TRUE},
402 {CAVE_OFFSET(scheduling), GD_SCHEDULING_PLCK},
403 {CAVE_OFFSET(amoeba_enclosed_effect), O_PRE_DIA_1}, /* not immediately to diamond, but with animation */
408 /* internal character (letter) codes in c64 games.
409 missing: "triple line" after >, diamond between ()s, player's head after )
410 used for converting names of caves imported from crli and other types of binary data */
411 const char gd_bd_internal_chars[] = " ,!./0123456789:*<=> ABCDEFGHIJKLMNOPQRSTUVWXYZ( ) _";
413 /* used for bdcff engine flag. */
414 const char *gd_engines[] =
424 /* to convert predictable slime values to bit masks */
425 static int slime_shift_msb(int c64_data)
431 for (i = 0; i < c64_data; i++)
432 /* shift in this many msb 1's */
433 perm = (0x100|perm) >> 1;
438 static GdElement bd1_import(guint8 c, int i)
440 if (c < G_N_ELEMENTS(bd1_import_table))
441 return bd1_import_table[c];
443 Warn("Invalid BD1 element in imported file at cave data %d: %d", i, c);
448 /* deluxe caves 1 contained a special element, non-sloped brick. */
449 static GdElement deluxecaves_1_import(guint8 c, int i)
451 GdElement e = bd1_import(c, i);
453 if (e == O_H_EXPANDING_WALL)
454 e = O_BRICK_NON_SLOPED;
459 static GdElement firstboulder_import(guint8 c, int i)
461 if (c < G_N_ELEMENTS(firstboulder_import_table))
462 return firstboulder_import_table[c];
464 Warn("Invalid 1stB element in imported file at cave data %d: %d", i, c);
469 static GdElement crazylight_import(guint8 c, int i)
471 if (c < G_N_ELEMENTS(gd_crazylight_import_table))
472 return gd_crazylight_import_table[c] & O_MASK; /* & O_MASK: do not import "scanned" flag */
474 Warn("Invalid CrLi element in imported file at cave data %d: %d", i, c);
479 GdPropertyDefault *gd_get_engine_default_array(GdEngine engine)
484 return gd_defaults_bd1;
488 return gd_defaults_bd2;
492 return gd_defaults_plck;
496 return gd_defaults_1stb;
499 case GD_ENGINE_CRDR7:
500 return gd_defaults_crdr_7;
504 return gd_defaults_crli;
507 /* to avoid compiler warning */
508 case GD_ENGINE_INVALID:
512 return gd_defaults_bd1;
515 void gd_cave_set_engine_defaults(GdCave *cave, GdEngine engine)
517 gd_cave_set_defaults_from_array(cave, gd_get_engine_default_array(engine));
519 /* these have hardcoded ckdelay. */
520 /* setting this ckdelay array does not fit into the gd_struct_default scheme. */
521 if (engine == GD_ENGINE_BD1)
523 cave->level_ckdelay[0] = 12;
524 cave->level_ckdelay[1] = 6;
525 cave->level_ckdelay[2] = 3;
526 cave->level_ckdelay[3] = 1;
527 cave->level_ckdelay[4] = 0;
530 if (engine == GD_ENGINE_BD2)
532 cave->level_ckdelay[0] = 9; /* 180ms */
533 cave->level_ckdelay[1] = 8; /* 160ms */
534 cave->level_ckdelay[2] = 7; /* 140ms */
535 cave->level_ckdelay[3] = 6; /* 120ms */
536 cave->level_ckdelay[4] = 6; /* 120ms (!) not faster than level4 */
540 GdEngine gd_cave_get_engine_from_string(const char *param)
544 for (i = 0; i < GD_ENGINE_INVALID; i++)
545 if (strcasecmp(param, gd_engines[i]) == 0)
548 return GD_ENGINE_INVALID;
551 /****************************************************************************
553 * cave import routines.
554 * take a cave, data, and maybe remaining bytes.
555 * return the number of bytes read, -1 if error.
557 ****************************************************************************/
560 take care of required diamonds values == 0 or > 100.
561 in original bd, the counter was only two-digit. so bd3 cave f
562 says 150 diamonds required, but you only had to collect 50.
563 also, gate opening is triggered by incrementing diamond
564 count and THEN checking if more required; so if required was
565 0, you had to collect 100. (also check crazy light 8 cave "1000")
567 http://www.boulder-dash.nl/forum/viewtopic.php?t=88
570 /* import bd1 cave data into our format. */
571 static int cave_copy_from_bd1(GdCave *cave, const guint8 *data, int remaining_bytes,
572 GdCavefileFormat format)
574 int length, direction;
580 GdElement (* import_func) (guint8 c, int i);
583 /* cant be shorted than this: header + no objects + delimiter */
584 if (remaining_bytes < 33)
586 Error("truncated BD1 cave data, %d bytes", remaining_bytes);
591 gd_cave_set_engine_defaults(cave, GD_ENGINE_BD1);
593 if (format == GD_FORMAT_BD1_ATARI)
594 cave->scheduling = GD_SCHEDULING_BD1_ATARI;
596 if (format == GD_FORMAT_DC1)
597 import_func = deluxecaves_1_import;
599 import_func = bd1_import;
601 /* set visible size for intermission */
602 if (cave->intermission)
608 /* cave number data[0] */
609 cave->diamond_value = data[2];
610 cave->extra_diamond_value = data[3];
612 for (level = 0; level < 5; level++)
614 cave->level_amoeba_time[level] = data[1];
616 /* 0 immediately underflowed to 999, so we use 999. example: sendydash 3, cave 02. */
617 if (cave->level_amoeba_time[level] == 0)
618 cave->level_amoeba_time[level] = 999;
620 cave->level_magic_wall_time[level] = data[1];
621 cave->level_rand[level] = data[4 + level];
622 cave->level_diamonds[level] = data[9 + level] % 100; /* check comment above */
624 /* gate opening is checked AFTER adding to diamonds collected, so 0 here means 100 to collect */
625 if (cave->level_diamonds[level] == 0)
626 cave->level_diamonds[level] = 100;
627 cave->level_time[level] = data[14 + level];
630 /* LogicDeLuxe extension: acid
631 $16 Acid speed (unused in the original BD1)
632 $17 Bit 2: if set, Acid's original position converts to explosion puff during spreading.
633 Otherwise, Acid remains intact, ie. it's just growing. (unused in the original BD1)
634 $1C Acid eats this element. (also Probability of element 1)
636 there is no problem importing these; as other bd1 caves did not contain acid at all,
637 so it does not matter how we set the values.
640 /* 0x1c index: same as probability1 !!!!! don't be surprised. we do a &0x3f because of this */
641 cave->acid_eats_this = import_func(data[0x1c] & 0x3F, 0x1c);
643 /* acid speed, *1e6 as probabilities are stored in int */
644 cave->acid_spread_ratio = data[0x16] / 255.0 * 1E6 + 0.5;
646 cave->acid_turns_to = (data[0x17] & (1 << 2)) ? O_EXPLODE_3 : O_ACID;
648 cave->colorb = GD_GDASH_BLACK; /* border - black */
649 cave->color0 = GD_GDASH_BLACK; /* background - black */
650 cave->color1= GD_GDASH_RED;
651 cave->color2 = GD_GDASH_PURPLE;
652 cave->color3 = GD_GDASH_YELLOW;
653 cave->color4 = cave->color3; /* in bd1, amoeba was color3 */
654 cave->color5 = cave->color3; /* no slime, but let it be color 3 */
657 for (i = 0; i < 4; i++)
659 cave->random_fill[i] = import_func(data[24 + i], 24 + i);
660 cave->random_fill_probability[i] = data[28 + i];
664 * Decode the explicit cave data
668 while (data[index] != 0xFF && index < remaining_bytes && index < 255)
672 /* crazy dream 3 extension: */
675 int x1, y1, nx, ny, dx, dy;
678 /* as this one uses nonstandard dx dy values, create points instead */
679 elem = import_func(data[index + 1], index + 1);
680 x1 = data[index + 2];
681 y1 = data[index + 3] - 2;
682 nx = data[index + 4];
683 ny = data[index + 5];
684 dx = data[index + 6];
685 dy = data[index + 7] + 1;
687 for (y = 0; y < ny; y++)
689 for (x = 0; x < nx; x++)
691 int pos = x1 + y1 * 40 + y * dy * 40 + x * dx;
693 cave->objects = list_append(cave->objects, gd_object_new_point(GD_OBJECT_LEVEL_ALL, pos % 40, pos / 40, elem));
701 /* object is code & 3f, object type is upper 2 bits */
702 elem = import_func(code & 0x3F, index);
704 switch ((code >> 6) & 3)
706 case 0: /* 00: POINT */
707 x1 = data[index + 1];
708 y1 = data[index + 2] - 2;
710 if (x1 >= cave->w || y1 >= cave->h)
711 Warn("invalid point coordinates %d,%d at byte %d", x1, y1, index);
713 cave->objects = list_append(cave->objects, gd_object_new_point(GD_OBJECT_LEVEL_ALL, x1, y1, elem));
718 case 1: /* 01: LINE */
719 x1 = data[index + 1];
720 y1 = data[index + 2] - 2;
721 length = (gint8)data[index + 3] - 1;
722 direction = data[index + 4];
726 Warn("line length negative, not displaying line at all, at byte %d", index);
730 if (direction > GD_MV_UP_LEFT)
732 Warn("invalid line direction %d at byte %d", direction, index);
733 direction = GD_MV_STILL;
736 x2 = x1 + length * gd_dx[direction + 1];
737 y2 = y1 + length * gd_dy[direction + 1];
743 Warn("invalid line coordinates %d,%d %d,%d at byte %d", x1, y1, x2, y2, index);
745 cave->objects = list_append(cave->objects, gd_object_new_line(GD_OBJECT_LEVEL_ALL, x1, y1, x2, y2, elem));
751 case 2: /* 10: FILLED RECTANGLE */
752 x1 = data[index + 1];
753 y1 = data[index + 2] - 2;
754 x2 = x1 + data[index + 3] - 1; /* width */
755 y2 = y1 + data[index + 4] - 1; /* height */
761 Warn("invalid filled rectangle coordinates %d,%d %d,%d at byte %d", x1, y1, x2, y2, index);
763 cave->objects = list_append(cave->objects, gd_object_new_filled_rectangle(GD_OBJECT_LEVEL_ALL, x1, y1, x2, y2, elem, import_func(data[index + 5], index + 5)));
768 case 3: /* 11: OPEN RECTANGLE (OUTLINE) */
769 x1 = data[index + 1];
770 y1 = data[index + 2] - 2;
771 x2 = x1 + data[index + 3] - 1;
772 y2 = y1 + data[index + 4] - 1;
778 Warn("invalid rectangle coordinates %d,%d %d,%d at byte %d", x1, y1, x2, y2, index);
780 cave->objects = list_append(cave->objects, gd_object_new_rectangle(GD_OBJECT_LEVEL_ALL, x1, y1, x2, y2, elem));
788 if (data[index] != 0xFF)
790 Error("import error, cave not delimited with 0xFF");
797 /* import bd2 cave data into our format. return number of bytes if pointer passed.
798 this is pretty much the same as above, only the encoding was different. */
799 static int cave_copy_from_bd2(GdCave *cave, const guint8 *data, int remaining_bytes,
800 GdCavefileFormat format)
805 int x1, y1, x2, y2, dx, dy;
808 if (remaining_bytes < 0x1A + 5)
810 Error("truncated BD2 cave data, %d bytes", remaining_bytes);
814 gd_cave_set_engine_defaults(cave, GD_ENGINE_BD2);
816 if (format == GD_FORMAT_BD2_ATARI)
817 cave->scheduling = GD_SCHEDULING_BD2_PLCK_ATARI;
819 /* set visible size for intermission */
820 if (cave->intermission)
826 cave->diamond_value = data[1];
827 cave->extra_diamond_value = data[2];
829 for (i = 0; i < 5; i++)
831 /* 0 immediately underflowed to 999, so we use 999. example: sendydash 3, cave 02. */
832 cave->level_amoeba_time[i] = data[0] == 0 ? 999 : data[0];
833 cave->level_rand[i] = data[13 + i];
835 /* gate opening is checked AFTER adding to diamonds collected, so 0 here is 1000 needed */
836 cave->level_diamonds[i] = data[8 + i] == 0 ? 1000 : data[8 + i];
837 cave->level_time[i] = data[3 + i];
838 cave->level_magic_wall_time[i] = data[0];
841 for (i = 0; i < 4; i++)
843 cave->random_fill[i] = bd1_import(data[0x16 + i], 0x16 + i);
844 cave->random_fill_probability[i] = data[0x12 + i];
848 * Decode the explicit cave data
852 while (data[index] != 0xFF && index < remaining_bytes)
857 int length, direction;
862 elem = bd1_import(data[index + 1], index + 1);
863 y1 = data[index + 2];
864 x1 = data[index + 3];
866 /* they are multiplied by two - 0 is up, 2 is upright, 4 is right... */
867 direction = data[index + 4] / 2;
868 length = data[index + 5] - 1;
870 if (direction > GD_MV_UP_LEFT)
872 Warn("invalid line direction %d at byte %d", direction, index);
873 direction = GD_MV_STILL;
876 x2 = x1 + length * gd_dx[direction + 1];
877 y2 = y1 + length * gd_dy[direction + 1];
883 Warn("invalid line coordinates %d,%d %d,%d at byte %d", x1, y1, x2, y2, index);
885 cave->objects = list_append(cave->objects, gd_object_new_line(GD_OBJECT_LEVEL_ALL, x1, y1, x2, y2, elem));
890 case 1: /* OPEN RECTANGLE */
891 elem = bd1_import(data[index + 1], index + 1);
892 y1 = data[index + 2];
893 x1 = data[index + 3];
894 y2 = y1 + data[index + 4] - 1; /* height */
895 x2 = x1 + data[index + 5] - 1;
901 Warn("invalid rectangle coordinates %d,%d %d,%d at byte %d", x1, y1, x2, y2, index);
903 cave->objects = list_append(cave->objects, gd_object_new_rectangle(GD_OBJECT_LEVEL_ALL, x1, y1, x2, y2, elem));
908 case 2: /* FILLED RECTANGLE */
909 elem = bd1_import(data[index + 1], index + 1);
910 y1 = data[index + 2];
911 x1 = data[index + 3];
912 y2 = y1 + data[index + 4] - 1;
913 x2 = x1 + data[index + 5] - 1;
919 Warn("invalid filled rectangle coordinates %d,%d %d,%d at byte %d", x1, y1, x2, y2, index);
921 cave->objects = list_append(cave->objects, gd_object_new_filled_rectangle(GD_OBJECT_LEVEL_ALL, x1, y1, x2, y2, elem, bd1_import(data[index+6], index+6)));
927 elem = bd1_import(data[index + 1], index + 1);
928 y1 = data[index + 2];
929 x1 = data[index + 3];
933 Warn("invalid point coordinates %d,%d at byte %d", x1, y1, index);
935 cave->objects = list_append(cave->objects, gd_object_new_point(GD_OBJECT_LEVEL_ALL, x1, y1, elem));
941 elem = bd1_import(data[index + 1], index + 1);
942 y1 = data[index + 2]; /* starting pos */
943 x1 = data[index + 3];
944 ny = data[index + 4] - 1; /* number of elements */
945 nx = data[index + 5] - 1;
946 dy = data[index + 6]; /* displacement */
947 dx = data[index + 7];
948 y2 = y1 + dy * ny; /* calculate rectangle */
951 /* guess this has to be here, after x2,y2 calculation, because of some bugs in imported data */
961 Warn("invalid raster coordinates %d,%d %d,%d at byte %d", x1, y1, x2, y2, index);
963 cave->objects = list_append(cave->objects, gd_object_new_raster(GD_OBJECT_LEVEL_ALL, x1, y1, x2, y2, dx, dy, elem));
969 /* profi boulder extension: bitmap */
970 elem = bd1_import(data[index + 1], index + 1);
971 bytes = data[index + 2]; /* number of bytes in bitmap */
973 if (bytes >= cave->w * cave->h / 8)
974 Warn("invalid bitmap length at byte %d", index - 4);
977 addr += data[index + 3]; /*msb */
978 addr += data[index + 4] << 8; /*lsb */
980 /* this was a pointer to the cave work memory (used during game). */
983 if (addr >= cave->w * cave->h)
984 Warn("invalid bitmap start address at byte %d", index - 4);
989 for (i = 0; i < bytes; i++)
991 /* for ("bytes" number of bytes) */
992 val = data[index + 5 + i];
994 for (n = 0; n < 8; n++)
996 /* for (8 bits in a byte) */
997 if ((val & 1) != 0) /* convert to single points... */
998 cave->objects = list_append(cave->objects, gd_object_new_point(GD_OBJECT_LEVEL_ALL, x1, y1, elem));
1001 x1++; /* next cave pos */
1005 /* maybe next line in map */
1012 index += 5 + bytes; /* 5 description bytes and "bytes" data bytes */
1016 dy = data[index + 3] / 40;
1017 dx = data[index + 3] % 40; /* same byte!!! */
1018 cave->objects = list_append(cave->objects, gd_object_new_join(GD_OBJECT_LEVEL_ALL, dx, dy, bd1_import(data[index+1], index+1), bd1_import(data[index+2], index+2)));
1023 case 7: /* SLIME PERMEABILITY */
1024 /* interesting this is set here, and not in the cave header */
1025 for (i = 0; i < 5; i++)
1026 cave->level_slime_permeability_c64[i] = data[index + 1];
1032 /* profi boulder extension by player: plck-like cave map. the import
1033 routine (any2gdash) inserts it here. */
1034 if (cave->map != NULL)
1036 Error("contains more than one PLCK map");
1037 gd_cave_map_free(cave->map);
1040 cave->map = gd_cave_map_new(cave, GdElement);
1042 for (x = 0; x < cave->w; x++)
1044 /* fill the first and the last row with steel wall. */
1045 cave->map[0][x] = O_STEEL;
1046 cave->map[cave->h - 1][x] = O_STEEL;
1049 n = 0; /* number of bytes read from map */
1051 /* the first and the last rows are not stored. */
1052 for (y = 1; y < cave->h - 1; y++)
1054 for (x = 0; x < cave->w; x += 2)
1056 cave->map[y][x] = plck_import_nybble[data[index + 3 + n] >> 4]; /* msb 4 bits */
1057 cave->map[y][x + 1] = plck_import_nybble[data[index + 3 + n] % 16]; /* lsb 4 bits */
1062 /* the position of inbox is stored. this is to check the cave */
1063 ry = data[index + 1] - 2;
1064 rx = data[index + 2];
1066 /* at the start of the cave, bd scrolled to the last player placed during the drawing
1067 (setup) of the cave.
1068 i think this is why a map also stored the coordinates of the player - we can use
1069 this to check its integrity */
1070 if (rx >= cave->w || ry < 0 ||
1071 ry >= cave->h || cave->map[ry][rx] != O_INBOX)
1072 Warn ("embedded PLCK map may be corrupted, player coordinates %d,%d", rx, rx);
1078 Warn ("unknown bd2 extension no. %02x at byte %d", data[index], index);
1080 index += 1; /* skip that byte */
1084 if (data[index] != 0xFF)
1086 Error("import error, cave not delimited with 0xFF");
1090 /* skip delimiter */
1093 /* animation byte - told the engine which objects to animate - to make game faster */
1096 /* the colors from the memory dump are appended here by any2gdash */
1097 cave->colorb = GD_GDASH_BLACK; /* border - black */
1098 cave->color0 = GD_GDASH_BLACK; /* background - black */
1099 cave->color1 = GD_GDASH_RED;
1100 cave->color2 = GD_GDASH_PURPLE;
1101 cave->color3 = GD_GDASH_YELLOW;
1102 cave->color4 = cave->color3; /* in bd1, amoeba was color3 */
1103 cave->color5 = cave->color3; /* no slime, but let it be color 3 */
1108 /* import plck cave data into our format.
1109 length is always 512 bytes, and contains if it is an intermission cave. */
1110 static int cave_copy_from_plck(GdCave *cave, const guint8 *data,
1111 int remaining_bytes, GdCavefileFormat format)
1113 /* i don't really think that all this table is needed, but included to be complete. */
1114 /* this is for the dirt and expanding wall looks like effect. */
1115 /* it also contains the individual frames */
1116 static GdElement plck_graphic_table[] =
1118 /* 3000 */ O_UNKNOWN, O_UNKNOWN, O_UNKNOWN, O_UNKNOWN, O_UNKNOWN, O_UNKNOWN, O_UNKNOWN, O_UNKNOWN,
1119 /* 3100 */ O_BUTTER_1, O_MAGIC_WALL, O_PRE_DIA_1, O_PRE_DIA_2, O_PRE_DIA_3, O_PRE_DIA_4, O_PRE_DIA_5, O_OUTBOX_CLOSED,
1120 /* 3200 */ O_AMOEBA, O_VOODOO, O_STONE, O_DIRT, O_DIAMOND, O_STEEL, O_PLAYER, O_BRICK,
1121 /* 3300 */ O_SPACE, O_OUTBOX_OPEN, O_FIREFLY_1, O_EXPLODE_1, O_EXPLODE_2, O_EXPLODE_3, O_MAGIC_WALL, O_MAGIC_WALL,
1122 /* 3400 */ O_PLAYER_TAP_BLINK, O_PLAYER_TAP_BLINK, O_PLAYER_TAP_BLINK, O_PLAYER_TAP_BLINK, O_PLAYER_TAP_BLINK, O_PLAYER_TAP_BLINK, O_PLAYER_TAP_BLINK, O_PLAYER_TAP_BLINK,
1123 /* 3500 */ O_PLAYER_LEFT, O_PLAYER_LEFT, O_PLAYER_LEFT, O_PLAYER_LEFT, O_PLAYER_LEFT, O_PLAYER_LEFT, O_PLAYER_LEFT, O_PLAYER_LEFT,
1124 /* 3600 */ O_PLAYER_RIGHT, O_PLAYER_RIGHT, O_PLAYER_RIGHT, O_PLAYER_RIGHT, O_PLAYER_RIGHT, O_PLAYER_RIGHT, O_PLAYER_RIGHT, O_PLAYER_RIGHT,
1125 /* 3700 */ O_BUTTER_1, O_BUTTER_1, O_BUTTER_1, O_BUTTER_1, O_BUTTER_1, O_BUTTER_1, O_BUTTER_1, O_BUTTER_1,
1126 /* 3800 */ O_AMOEBA, O_AMOEBA, O_AMOEBA, O_AMOEBA, O_AMOEBA, O_AMOEBA, O_AMOEBA, O_AMOEBA,
1132 if (remaining_bytes < 512)
1134 Error("truncated plck cave data!");
1138 gd_cave_set_engine_defaults(cave, GD_ENGINE_PLCK);
1140 if (format == GD_FORMAT_PLC_ATARI)
1141 cave->scheduling = GD_SCHEDULING_BD2_PLCK_ATARI;
1143 cave->intermission = data[0x1da] != 0;
1145 if (cave->intermission)
1147 /* set visible size for intermission */
1152 /* cave selection table, was not part of cave data, rather given in game packers.
1153 * if a new enough version of any2gdash is used, it will put information after the cave.
1154 * detect this here and act accordingly */
1155 if ((data[0x1f0] == data[0x1f1] - 1) &&
1156 (data[0x1f0] == 0x19 ||
1157 data[0x1f0] == 0x0e))
1161 /* found selection table */
1162 cave->selectable = data[0x1f0] == 0x19;
1163 gd_strcpy(cave->name, " ");
1165 for (j = 0; j < 12; j++)
1166 cave->name[j] = data[0x1f2 + j];
1168 chompString(cave->name); /* remove spaces */
1172 /* no selection info found, let intermissions be unselectable */
1173 cave->selectable = !cave->intermission;
1176 cave->diamond_value = data[0x1be];
1177 cave->extra_diamond_value = data[0x1c0];
1179 for (i = 0; i < 5; i++)
1181 /* plck doesnot really have levels, so just duplicate data five times */
1182 cave->level_amoeba_time[i] = data[0x1c4];
1184 /* immediately underflowed to 999, so we use 999. example: sendydash 3, cave 02. */
1185 if (cave->level_amoeba_time[i] == 0)
1186 cave->level_amoeba_time[i] = 999;
1188 cave->level_time[i] = data[0x1ba];
1189 cave->level_diamonds[i] = data[0x1bc];
1191 /* gate opening is checked AFTER adding to diamonds collected, so 0 here is 1000 needed */
1192 if (cave->level_diamonds[i] == 0)
1193 cave->level_diamonds[i] = 1000;
1195 cave->level_ckdelay[i] = data[0x1b8];
1196 cave->level_magic_wall_time[i] = data[0x1c6];
1197 cave->level_slime_permeability_c64[i] = slime_shift_msb(data[0x1c2]);
1200 cave->colorb = GD_GDASH_BLACK; /* border - black */
1201 cave->color0 = GD_GDASH_BLACK; /* background - black */
1202 cave->color1 = GD_GDASH_RED;
1203 cave->color2 = GD_GDASH_PURPLE;
1204 cave->color3 = GD_GDASH_YELLOW;
1205 cave->color4 = cave->color3; /* in bd1, amoeba was color3 */
1206 cave->color5 = cave->color3; /* no slime, but let it be color 3 */
1208 /* ... the cave is stored like a map. */
1209 cave->map = gd_cave_map_new(cave, GdElement);
1211 /* cave map looked like this. */
1212 /* two rows of steel wall ($44's), then cave description, 20 bytes (40 nybbles) for each line. */
1213 /* the bottom and top lines were not stored... originally. */
1214 /* some games write to the top line; so we import that, too. */
1215 /* also dlp 155 allowed writing to the bottom line; the first 20 $44-s now store the bottom line. */
1216 /* so the cave is essentially shifted one row down in the file: cave->map[y][x] = data[... y+1 mod height ][x] */
1217 for (y = 0; y < cave->h; y++)
1219 for (x = 0; x < cave->w; x += 2)
1221 /* msb 4 bits: we do not check index ranges, as >>4 and %16 will result in 0..15 */
1222 cave->map[y][x] = plck_import_nybble[data[((y + 1) % cave->h) * 20 + x / 2] >> 4];
1225 cave->map[y][x + 1] = plck_import_nybble[data[((y + 1) % cave->h) * 20 + x / 2] % 16];
1229 /* FOR NOW, WE DO NOT IMPORT THE BOTTOM BORDER */
1230 for (x = 0; x < cave->w; x++)
1231 cave->map[cave->h - 1][x] = O_STEEL;
1234 if (steels && data[0] == 0x55)
1235 cave->map[cave->h - 1][0] = cave->map[cave->h - 1][1] = O_STEEL;
1238 /* check for diego-effects */
1239 /* c64 magic values (byte sequences) 0x20 0x90 0x46, also 0xa9 0x1c 0x85 */
1240 if ((data[0x1e5] == 0x20 &&
1241 data[0x1e6] == 0x90 &&
1242 data[0x1e7] == 0x46) ||
1243 (data[0x1e5] == 0xa9 &&
1244 data[0x1e6] == 0x1c &&
1245 data[0x1e7] == 0x85))
1247 /* diego effects enabled. */
1248 cave->stone_bouncing_effect = bd1_import(data[0x1ea], 0x1ea);
1249 cave->diamond_falling_effect = bd1_import(data[0x1eb], 0x1eb);
1251 /* explosions: 0x1e was explosion 5, if this is set to default, we also do not read it,
1252 as in our engine this would cause an O_EXPLODE_5 to stay there. */
1253 if (data[0x1ec] != 0x1e)
1254 cave->explosion_effect = bd1_import(data[0x1ec], 0x1ec);
1256 /* pointer to element graphic.
1257 two bytes/column (one element), that is data[xxx] % 16 / 2.
1258 also there are 16bytes/row.
1259 that is, 0x44 = stone, upper left character. 0x45 = upper right,
1260 0x54 = lower right, 0x55 = lower right.
1261 so high nybble must be shifted right twice -> data[xxx]/16*4. */
1262 cave->dirt_looks_like = plck_graphic_table[(data[0x1ed] / 16) * 4 + (data[0x1ed] % 16) / 2];
1263 cave->expanding_wall_looks_like = plck_graphic_table[(data[0x1ee] / 16) * 4 + (data[0x1ee] % 16) / 2];
1265 for (i = 0; i < 5; i++)
1266 cave->level_amoeba_threshold[i] = data[0x1ef];
1272 /* no one's delight boulder dash essentially: rle compressed plck maps. */
1273 static int cave_copy_from_dlb(GdCave *cave, const guint8 *data, int remaining_bytes)
1278 START, /* initial state */
1279 SEPARATOR, /* got a separator */
1280 RLE, /* after a separator, got the byte to duplicate */
1281 NORMAL /* normal, copy bytes till separator */
1283 int pos, cavepos, i, x, y;
1284 guint8 byte, separator;
1286 gd_cave_set_engine_defaults(cave, GD_ENGINE_PLCK); /* essentially the plck engine */
1288 for (i = 0; i < 5; i++)
1290 /* does not really have levels, so just duplicate data five times */
1291 cave->level_time[i] = data[1];
1292 cave->level_diamonds[i] = data[2];
1294 /* gate opening is checked AFTER adding to diamonds collected, so 0 here is 1000 needed */
1295 if (cave->level_diamonds[i] == 0)
1296 cave->level_diamonds[i] = 1000;
1298 cave->level_ckdelay[i] = data[0];
1299 cave->level_amoeba_time[i] = data[6];
1301 /* 0 immediately underflowed to 999, so we use 999. example: sendydash 3, cave 02. */
1302 if (cave->level_amoeba_time[i] == 0)
1303 cave->level_amoeba_time[i] = 999;
1305 cave->level_magic_wall_time[i] = data[7];
1306 cave->level_slime_permeability_c64[i] = slime_shift_msb(data[5]);
1309 cave->diamond_value = data[3];
1310 cave->extra_diamond_value = data[4];
1312 /* then 5 color bytes follow */
1313 cave->colorb = gd_c64_color(data[8] & 0xf); /* border */
1314 cave->color0 = gd_c64_color(data[9] & 0xf);
1315 cave->color1 = gd_c64_color(data[10] & 0xf);
1316 cave->color2 = gd_c64_color(data[11] & 0xf);
1317 cave->color3 = gd_c64_color(data[12] & 0x7); /* lower 3 bits only! */
1318 cave->color4 = cave->color3; /* in plck, amoeba was color3 */
1319 cave->color5 = cave->color3; /* same for slime */
1322 pos = 13; /* those 13 bytes were the cave values above */
1324 byte = 0; /* just to get rid of compiler warning */
1325 separator = 0; /* just to get rid of compiler warning */
1327 /* employ a state machine. */
1330 while (cavepos < 400 && pos < remaining_bytes)
1335 /* first byte is a separator. remember it */
1336 separator = data[pos];
1338 /* after the first separator, no rle data, just copy. */
1343 /* we had a separator. remember this byte, as this will be duplicated (or more) */
1349 /* we had the first byte, duplicate this n times. */
1350 if (data[pos] == 0xff)
1352 /* if it is a 0xff, we will have another byte, which is also a length specifier. */
1353 /* and for this one, duplicate only 254 times */
1354 if (cavepos + 254 > 400)
1356 Error("DLB import error: RLE data overflows buffer");
1360 for (i = 0; i < 254; i++)
1361 decomp[cavepos++] = byte;
1365 /* if not 0xff, duplicate n times and back to copy mode */
1366 if (cavepos + data[pos] > 400)
1368 Error("DLB import error: RLE data overflows buffer");
1372 for (i = 0; i < data[pos]; i++)
1373 decomp[cavepos++] = byte;
1380 /* bytes duplicated; now only copy the remaining, till the next separator. */
1381 if (data[pos] == separator)
1384 decomp[cavepos++] = data[pos]; /* copy this byte and state is still NORMAL */
1393 Error("DLB import error: RLE processing, cave length %d, should be 400", cavepos);
1397 /* process uncompressed map */
1398 cave->map = gd_cave_map_new(cave, GdElement);
1400 for (x = 0; x < cave->w; x++)
1402 /* fill the first and the last row with steel wall. */
1403 cave->map[0][x] = O_STEEL;
1404 cave->map[cave->h - 1][x] = O_STEEL;
1407 for (y = 1; y < cave->h - 1; y++)
1409 for (x = 0; x < cave->w; x += 2)
1412 cave->map[y][x] = plck_import_nybble[decomp[((y - 1) * cave->w + x) / 2] >> 4];
1414 cave->map[y][x + 1] = plck_import_nybble[decomp[((y - 1) * cave->w + x) / 2] % 16];
1418 /* return number of bytes read from buffer */
1422 /* import plck cave data into our format. */
1423 static int cave_copy_from_1stb(GdCave *cave, const guint8 *data, int remaining_bytes)
1428 if (remaining_bytes < 1024)
1430 Error("truncated 1stb cave data!");
1435 gd_cave_set_engine_defaults(cave, GD_ENGINE_1STB);
1438 gd_strcpy(cave->name, " ");
1440 for (i = 0; i < 14; i++)
1442 int c = data[0x3a0 + i];
1444 /* import cave name; a conversion table is used for each character */
1446 c = gd_bd_internal_chars[c];
1452 c = ' '; /* don't know this, so change to space */
1460 chompString(cave->name);
1462 cave->intermission = data[0x389] != 0;
1464 /* if it is intermission but not scrollable */
1465 if (cave->intermission && !data[0x38c])
1471 cave->diamond_value = 100 * data[0x379] + 10 * data[0x379 + 1] + data[0x379 + 2];
1472 cave->extra_diamond_value = 100 * data[0x376] + 10 * data[0x376 + 1] + data[0x376 + 2];
1474 for (i = 0; i < 5; i++)
1476 /* plck doesnot really have levels, so just duplicate data five times */
1477 cave->level_time[i] = 100 * data[0x370] + 10 * data[0x370+1] + data[0x370 + 2];
1479 /* same as gate opening after 0 diamonds */
1480 if (cave->level_time[i] == 0)
1481 cave->level_time[i] = 1000;
1483 cave->level_diamonds[i] = 100 * data[0x373] + 10 * data[0x373 + 1] + data[0x373 + 2];
1485 /* gate opening is checked AFTER adding to diamonds collected, so 0 here is 1000 (!) needed */
1486 if (cave->level_diamonds[i] == 0)
1487 cave->level_diamonds[i] = 1000;
1489 cave->level_ckdelay[i] = data[0x38a];
1490 cave->level_amoeba_time[i] = 256 * (int)data[0x37c] + data[0x37d];
1492 /* 0 immediately underflowed to 999, so we use 999. example: sendydash 3, cave 02. */
1493 if (cave->level_amoeba_time[i] == 0)
1494 cave->level_amoeba_time[i] = 999;
1496 cave->level_magic_wall_time[i] = 256 * (int)data[0x37e] + data[0x37f];
1497 cave->level_slime_permeability_c64[i] = data[0x38b];
1498 cave->level_bonus_time[i] = data[0x392];
1499 cave->level_penalty_time[i] = data[0x393];
1500 cave->level_amoeba_threshold[i] = 256 * (int)data[0x390] + data[0x390 + 1];
1503 /* also has no random data... */
1504 cave->colorb = gd_c64_color(data[0x384] & 0xf); /* border */
1505 cave->color0 = gd_c64_color(data[0x385] & 0xf);
1506 cave->color1 = gd_c64_color(data[0x386] & 0xf);
1507 cave->color2 = gd_c64_color(data[0x387] & 0xf);
1508 cave->color3 = gd_c64_color(data[0x388] & 0x7); /* lower 3 bits only! */
1509 cave->color4 = cave->color1;
1510 cave->color5 = cave->color1;
1512 cave->amoeba_growth_prob = (4.0 * 1E6 / (data[0x382] + 1)) + 0.5; /* probabilities store *1M */
1513 if (cave->amoeba_growth_prob > 1000000)
1514 cave->amoeba_growth_prob = 1000000;
1516 cave->amoeba_fast_growth_prob = (4.0 * 1E6 / (data[0x383] + 1)) + 0.5;
1517 if (cave->amoeba_fast_growth_prob > 1000000)
1518 cave->amoeba_fast_growth_prob = 1000000;
1520 if (data[0x380] != 0)
1521 cave->creatures_direction_auto_change_time = data[0x381];
1523 cave->diagonal_movements = data[0x381] != 0;
1525 /* ... the cave is stored like a map. */
1526 cave->map = gd_cave_map_new(cave, GdElement);
1527 for (y = 0; y < cave->h; y++)
1528 for (x = 0; x < cave->w; x++)
1529 cave->map[y][x] = firstboulder_import(data[y * 40 + x], y * 40 + x);
1531 cave->magic_wall_sound = data[0x38d] == 0xf1;
1533 /* 2d was a normal switch, 2e a changed one. */
1534 cave->creatures_backwards = data[0x38f] == 0x2d;
1536 /* 2e horizontal, 2f vertical. */
1537 cave->expanding_wall_changed = data[0x38e] == 0x2f;
1539 cave->biter_delay_frame = data[0x394];
1540 cave->magic_wall_stops_amoeba = data[0x395] == 0; /* negated!! */
1542 cave->bomb_explosion_effect = firstboulder_import(data[0x396], 0x396);
1543 cave->explosion_effect = firstboulder_import(data[0x397], 0x397);
1544 cave->stone_bouncing_effect = firstboulder_import(data[0x398], 0x398);
1545 cave->diamond_birth_effect = firstboulder_import(data[0x399], 0x399);
1546 cave->magic_diamond_to = firstboulder_import(data[0x39a], 0x39a);
1548 cave->bladder_converts_by = firstboulder_import(data[0x39b], 0x39b);
1549 cave->diamond_falling_effect = firstboulder_import(data[0x39c], 0x39c);
1550 cave->biter_eat = firstboulder_import(data[0x39d], 0x39d);
1551 cave->slime_eats_1 = firstboulder_import(data[0x39e], 0x39e);
1552 cave->slime_converts_1 = firstboulder_import(data[0x39e] + 3, 0x39e);
1553 cave->slime_eats_2 = firstboulder_import(data[0x39f], 0x39f);
1554 cave->slime_converts_2 = firstboulder_import(data[0x39f] + 3, 0x39f);
1555 cave->magic_diamond_to = firstboulder_import(data[0x39a], 0x39a);
1557 /* length is always 1024 bytes */
1562 static int cave_copy_from_crdr_7(GdCave *cave, const guint8 *data, int remaining_bytes)
1567 /* if we have name, convert */
1568 gd_strcpy(cave->name, " ");
1570 for (i = 0; i < 14; i++)
1574 /* import cave name; a conversion table is used for each character */
1576 c = gd_bd_internal_chars[c];
1589 chompString(cave->name); /* remove trailing and leading spaces */
1591 cave->selectable = data[14] != 0;
1593 /* jump 15 bytes, 14 was the name and 15 selectability */
1596 if (memcmp((char *)data + 0x30, "V4\0020", 4) != 0)
1597 Warn("unknown crdr version %c%c%c%c", data[0x30], data[0x31], data[0x32], data[0x33]);
1599 gd_cave_set_engine_defaults(cave, GD_ENGINE_CRDR7);
1601 for (i = 0; i < 5; i++)
1603 cave->level_time[i] = (int)data[0x0] * 100 + data[0x1] * 10 + data[0x2];
1605 /* same as gate opening after 0 diamonds */
1606 if (cave->level_time[i] == 0)
1607 cave->level_time[i] = 1000;
1609 cave->level_diamonds[i] = (int)data[0x3] * 100 + data[0x4] * 10 + data[0x5];
1611 /* gate opening is checked AFTER adding to diamonds collected, so 0 here is 1000 (!) needed */
1612 if (cave->level_diamonds[i] == 0)
1613 cave->level_diamonds[i] = 1000;
1615 cave->level_ckdelay[i] = data[0x1A];
1616 cave->level_rand[i] = data[0x40];
1617 cave->level_amoeba_time[i] = (int)data[0xC] * 256 + data[0xD];
1619 /* 0 immediately underflowed to 999, so we use 999. example: sendydash 3, cave 02. */
1620 if (cave->level_amoeba_time[i] == 0)
1621 cave->level_amoeba_time[i] = 999;
1623 cave->level_magic_wall_time[i] = (int)data[0xE] * 256 + data[0xF];
1624 cave->level_slime_permeability_c64[i] = data[0x1B];
1625 cave->level_bonus_time[i] = data[0x22];
1626 cave->level_penalty_time[i] = data[0x23];
1627 cave->level_bonus_time[i] = data[0x22];
1628 cave->level_penalty_time[i] = data[0x23];
1629 cave->level_amoeba_threshold[i] = 256 * (int)data[0x20] + data[0x21];
1632 cave->extra_diamond_value = (int)data[0x6] * 100 + data[0x7] * 10 + data[0x8];
1633 cave->diamond_value = (int)data[0x9] * 100 + data[0xA] * 10 + data[0xB];
1636 cave->creatures_direction_auto_change_time = data[0x11];
1638 cave->colorb = gd_c64_color(data[0x14] & 0xf); /* border */
1639 cave->color0 = gd_c64_color(data[0x15] & 0xf);
1640 cave->color1 = gd_c64_color(data[0x16] & 0xf);
1641 cave->color2 = gd_c64_color(data[0x17] & 0xf);
1642 cave->color3 = gd_c64_color(data[0x18] & 0x7); /* lower 3 bits only! */
1643 cave->color4 = cave->color3;
1644 cave->color5 = cave->color1;
1645 cave->intermission = data[0x19] != 0;
1647 /* if it is intermission but not scrollable */
1648 if (cave->intermission && !data[0x1c])
1654 /* AMOEBA in crazy dash 8:
1655 jsr $2500 ; generate true random
1656 and $94 ; binary and the current "probability"
1657 cmp #$04 ; compare to 4
1658 bcs out ; jump out (do not expand) if carry set, ie. result was less than 4.
1660 prob values can be like num = 3, 7, 15, 31, 63, ... n lsb bits count.
1661 0..3>=4? 0..7>=4? 0..15>=4? and similar.
1662 this way, probability of growing is 4/(num+1)
1665 cave->amoeba_growth_prob = (4.0 * 1E6 / (data[0x12] + 1)) + 0.5; /* probabilities store * 1M */
1666 if (cave->amoeba_growth_prob > 1000000)
1667 cave->amoeba_growth_prob = 1000000;
1669 cave->amoeba_fast_growth_prob = (4.0 * 1E6 / (data[0x13] + 1)) + 0.5;
1670 if (cave->amoeba_fast_growth_prob > 1000000)
1671 cave->amoeba_fast_growth_prob = 1000000;
1673 /* expanding wall direction change - 2e horizontal, 2f vertical */
1674 cave->expanding_wall_changed = data[0x1e] == 0x2f;
1676 /* 2c was a normal switch, 2d a changed one. */
1677 cave->creatures_backwards = data[0x1f] == 0x2d;
1678 cave->biter_delay_frame = data[0x24];
1679 cave->magic_wall_stops_amoeba = data[0x25] == 0; /* negated!! */
1681 cave->bomb_explosion_effect = crazydream_import_table[data[0x26]];
1682 cave->explosion_effect = crazydream_import_table[data[0x27]];
1683 cave->stone_bouncing_effect = crazydream_import_table[data[0x28]];
1684 cave->diamond_birth_effect = crazydream_import_table[data[0x29]];
1685 cave->magic_diamond_to = crazydream_import_table[data[0x2a]];
1687 cave->bladder_converts_by = crazydream_import_table[data[0x2b]];
1688 cave->diamond_falling_effect = crazydream_import_table[data[0x2c]];
1689 cave->biter_eat = crazydream_import_table[data[0x2d]];
1690 cave->slime_eats_1 = crazydream_import_table[data[0x2e]];
1691 cave->slime_converts_1 = crazydream_import_table[data[0x2e] + 3];
1692 cave->slime_eats_2 = crazydream_import_table[data[0x2f]];
1693 cave->slime_converts_2 = crazydream_import_table[data[0x2f] + 3];
1695 cave->diagonal_movements = (data[0x34] & 1) != 0;
1696 cave->gravity_change_time = data[0x35];
1697 cave->pneumatic_hammer_frame = data[0x36];
1698 cave->hammered_wall_reappear_frame = data[0x37];
1699 cave->hammered_walls_reappear = data[0x3f] != 0;
1702 acid in crazy dream 8:
1703 jsr $2500 ; true random
1704 cmp $03a8 ; compare to ratio
1705 bcs out ; if it was smaller, forget it for now.
1707 ie. random<=ratio, then acid grows.
1710 /* 1e6, probabilities are stored as int */
1711 cave->acid_spread_ratio = data[0x38] / 255.0 * 1E6 + 0.5;
1713 cave->acid_eats_this = crazydream_import_table[data[0x39]];
1714 switch(data[0x3a] & 3)
1716 case 0: cave->gravity = GD_MV_UP; break;
1717 case 1: cave->gravity = GD_MV_DOWN; break;
1718 case 2: cave->gravity = GD_MV_LEFT; break;
1719 case 3: cave->gravity = GD_MV_RIGHT; break;
1722 cave->snap_element = ((data[0x3a] & 4) != 0) ? O_EXPLODE_1 : O_SPACE;
1724 /* we do not know the values for these, so do not import */
1725 // cave->dirt_looks_like... data[0x3c]
1726 // cave->expanding_wall_looks_like... data[0x3b]
1727 for (i = 0; i < 4; i++)
1729 cave->random_fill[i] = crazydream_import_table[data[0x41 + i]];
1730 cave->random_fill_probability[i] = data[0x45 + i];
1736 while (data[index] != 0xff)
1739 int x1, y1, x2, y2, dx, dy;
1741 int length, direction;
1743 /* for copy&paste; copy&paste are different objects, static = ugly solution :) */
1744 static int cx1, cy1, cw, ch;
1746 switch (data[index])
1749 elem = crazydream_import_table[data[index + 1]];
1750 x1 = data[index + 2];
1751 y1 = data[index + 3];
1752 if (x1 >= cave->w || y1 >= cave->h)
1753 Warn("invalid point coordinates %d,%d at byte %d", x1, y1, index);
1755 cave->objects = list_append(cave->objects, gd_object_new_point(GD_OBJECT_LEVEL_ALL, x1, y1, elem));
1760 case 2: /* rectangle */
1761 elem = crazydream_import_table[data[index + 1]];
1762 x1 = data[index + 2];
1763 y1 = data[index + 3];
1764 x2 = x1 + data[index + 4] - 1;
1765 y2 = y1 + data[index + 5] - 1; /* height */
1767 if (x1 >= cave->w ||
1771 Warn("invalid rectangle coordinates %d,%d %d,%d at byte %d", x1, y1, x2, y2, index);
1773 cave->objects = list_append(cave->objects, gd_object_new_rectangle(GD_OBJECT_LEVEL_ALL, x1, y1, x2, y2, elem));
1778 case 3: /* fillrect */
1779 x1 = data[index + 2];
1780 y1 = data[index + 3];
1781 x2 = x1 + data[index + 4] - 1;
1782 y2 = y1 + data[index + 5] - 1;
1784 if (x1 >= cave->w ||
1788 Warn("invalid filled rectangle coordinates %d,%d %d,%d at byte %d", x1, y1, x2, y2, index);
1790 /* border and inside of fill is the same element. */
1791 cave->objects = list_append(cave->objects, gd_object_new_filled_rectangle(GD_OBJECT_LEVEL_ALL, x1, y1, x2, y2, crazydream_import_table[data[index + 1]], crazydream_import_table[data[index + 1]]));
1797 elem = crazydream_import_table[data[index + 1]];
1798 if (elem == O_UNKNOWN)
1799 Warn("unknown element at %d: %x", index + 1, data[index + 1]);
1801 x1 = data[index + 2];
1802 y1 = data[index + 3];
1803 length = data[index + 4];
1804 direction = data[index + 5];
1805 nx = ((signed)direction - 128) % 40;
1806 ny = ((signed)direction - 128) / 40;
1807 x2 = x1 + (length - 1) * nx;
1808 y2 = y1 + (length - 1) * ny;
1810 /* if either is bigger than one, we cannot treat this as a line. create points instead */
1811 if (ABS(nx) >= 2 || ABS(ny) >= 2)
1813 for (i = 0; i < length; i++)
1815 cave->objects = list_append(cave->objects, gd_object_new_point(GD_OBJECT_LEVEL_ALL, x1, y1, elem));
1822 /* this is a normal line, and will be appended. only do the checking here */
1823 if (x1 >= cave->w ||
1827 Warn("invalid line coordinates %d,%d %d,%d at byte %d", x1, y1, x2, y2, index - 5);
1829 cave->objects = list_append(cave->objects, gd_object_new_line(GD_OBJECT_LEVEL_ALL, x1, y1, x2, y2, elem));
1836 cx1 = data[index + 1];
1837 cy1 = data[index + 2];
1838 cw = data[index + 3];
1839 ch = data[index + 4];
1841 if (cx1 >= cave->w ||
1843 cx1 + cw > cave->w ||
1845 Warn("invalid copy coordinates %d,%d or size %d,%d at byte %d", cx1, cy1, cw, ch, index);
1854 /* original stored width and height, we store the coordinates of the source area */
1857 dx = data[index + 1]; /* new pos */
1858 dy = data[index + 2];
1860 if (dx >= cave->w ||
1862 dx + cw > cave->w ||
1864 Warn("invalid paste coordinates %d,%d at byte %d", dx, dy, index);
1866 cave->objects = list_append(cave->objects, gd_object_new_copy_paste(GD_OBJECT_LEVEL_ALL, x1, y1, x2, y2, dx, dy, FALSE, FALSE));
1871 case 11: /* raster */
1872 elem = crazydream_import_table[data[index + 1]];
1873 x1 = data[index + 2];
1874 y1 = data[index + 3];
1875 dx = data[index + 4];
1876 dy = data[index + 5];
1877 nx = data[index + 6] - 1;
1878 ny = data[index + 7] - 1;
1879 x2 = x1 + dx * nx; /* calculate rectangle we use */
1887 if (x1 >= cave->w ||
1891 Warn("invalid raster coordinates %d,%d %d,%d at byte %d", x1, y1, x2, y2, index);
1893 cave->objects = list_append(cave->objects, gd_object_new_raster(GD_OBJECT_LEVEL_ALL, x1, y1, x2, y2, dx, dy, elem));
1899 Warn ("unknown crdr extension no. %02x at byte %d", data[index], index);
1900 index += 1; /* skip that byte */
1905 index++; /* skip $ff */
1907 /* crazy dream 7 hack */
1910 for (i = 0; i < 0x3b0; i++)
1911 checksum = checksum^data[i];
1913 if (strEqual(cave->name, "Crazy maze") && checksum == 195)
1914 cave->skeletons_needed_for_pot = 0;
1916 return 15 + 0x49 + index;
1919 static void crazy_dream_9_add_specials(GdCave *cave, const guint8 *buf, const int length)
1924 /* crazy dream 9 hack */
1926 for (i = 0; i < length; i++)
1927 checksum = checksum^buf[i];
1929 /* check cave name and the checksum. both are hardcoded here */
1930 if (strEqual(cave->name, "Rockfall") && checksum == 134)
1932 GdElement rand[4] = { O_DIAMOND, O_STONE, O_ACID, O_DIRT };
1933 gint32 prob[4] = { 37, 32, 2, 0 };
1934 gint32 seeds[5] = { -1, -1, -1, -1, -1 };
1936 cave->objects = list_append(cave->objects, gd_object_new_random_fill(GD_OBJECT_LEVEL_ALL, 0, 0, 39, 21, seeds, O_DIRT, rand, prob, O_BLADDER_SPENDER, FALSE));
1939 if (strEqual(cave->name, "Roll dice now!") && checksum == 235)
1941 GdElement rand[4] = { O_STONE, O_BUTTER_3, O_DIRT, O_DIRT };
1942 gint32 prob[4] = { 0x18, 0x08, 0, 0 };
1943 gint32 seeds[5] = { -1, -1, -1, -1, -1 };
1945 cave->objects = list_append(cave->objects, gd_object_new_random_fill(GD_OBJECT_LEVEL_ALL, 0, 0, 39, 21, seeds, O_DIRT, rand, prob, O_BLADDER_SPENDER, FALSE));
1948 if (strEqual(cave->name, "Random maze") && checksum == 24)
1950 gint32 seeds[5] = { -1, -1, -1, -1, -1 };
1951 cave->objects = list_append(cave->objects, gd_object_new_maze(GD_OBJECT_LEVEL_ALL, 1, 4, 35, 20, 1, 1, O_NONE, O_DIRT, 50, seeds));
1954 if (strEqual(cave->name, "Metamorphosis") && checksum == 53)
1956 gint32 seeds[5] = { -1, -1, -1, -1, -1 };
1957 GdElement rand[4] = { O_STONE, O_DIRT, O_DIRT, O_DIRT };
1958 gint32 prob[4] = { 0x18, 0, 0, 0 };
1960 cave->objects = list_append(cave->objects, gd_object_new_maze(GD_OBJECT_LEVEL_ALL, 4, 1, 38, 19, 1, 3, O_NONE, O_BLADDER_SPENDER, 50, seeds));
1961 cave->objects = list_append(cave->objects, gd_object_new_random_fill(GD_OBJECT_LEVEL_ALL, 4, 1, 38, 19, seeds, O_DIRT, rand, prob, O_BLADDER_SPENDER, FALSE));
1962 cave->creatures_backwards = TRUE; /* for some reason, this level worked like that */
1965 if (strEqual(cave->name, "All the way") && checksum == 33)
1967 gint32 seeds[5] = { -1, -1, -1, -1, -1 };
1969 cave->objects = list_append(cave->objects, gd_object_new_maze_unicursal(GD_OBJECT_LEVEL_ALL, 1, 1, 35, 19, 1, 1, O_BRICK, O_PRE_DIA_1, 50, seeds));
1971 /* a point which "breaks" the unicursal maze, making it one very long path */
1972 cave->objects = list_append(cave->objects, gd_object_new_point(GD_OBJECT_LEVEL_ALL, 35, 18, O_BRICK));
1976 /* crazy light contruction kit */
1977 static int cave_copy_from_crli(GdCave *cave, const guint8 *data, int remaining_bytes)
1979 guint8 uncompressed[1024];
1980 int datapos, cavepos, i, x, y;
1982 const char *versions[] = { "V2.2", "V2.6", "V3.0" };
1986 V2_2, /* XXX whats the difference between 2.2 and 2.6?*/
1990 GdElement (*import) (guint8 c, int i) = NULL; /* import function */
1992 gd_cave_set_engine_defaults(cave, GD_ENGINE_CRLI);
1994 /* detect if this is a cavefile */
2001 datapos = 5; /* cavefile, skipping 0x00 0xc4 D L P */
2006 /* converted from snapshot, skip "selectable" and 14byte name */
2011 /* if we have name, convert */
2014 gd_strcpy(cave->name, " ");
2016 for (i = 0; i < 14; i++)
2018 int c = data[i + 1];
2020 /* import cave name; a conversion table is used for each character */
2022 c = gd_bd_internal_chars[c];
2036 chompString(cave->name); /* remove trailing and leading spaces */
2039 /* uncompress rle data */
2042 while (cavepos < 0x3b0)
2044 /* <- loop until the uncompressed reaches its size */
2045 if (datapos >= remaining_bytes)
2047 Error("truncated crli cave data");
2051 if (data[datapos] == 0xbf)
2053 /* magic value 0xbf is the escape byte */
2054 if (datapos + 2 >= remaining_bytes)
2056 Error("truncated crli cave data");
2060 if (data[datapos + 2] + datapos >= sizeof(uncompressed))
2062 /* we would run out of buffer, this must be some error */
2063 Error("invalid crli cave data - RLE length value is too big");
2067 /* 0xbf, number, byte to dup */
2068 for (i = 0; i < data[datapos + 2]; i++)
2069 uncompressed[cavepos++] = data[datapos + 1];
2075 uncompressed[cavepos++] = data[datapos++];
2079 /* check crli version */
2080 for (i = 0; i < G_N_ELEMENTS(versions); i++)
2081 if (memcmp((char *)uncompressed + 0x3a0, versions[i], 4) == 0)
2084 /* v3.0 has falling wall and box, and no ghost. */
2085 import = version >= V3_0 ? crazylight_import : firstboulder_import;
2087 if (version == none)
2089 Warn("unknown crli version %c%c%c%c", uncompressed[0x3a0], uncompressed[0x3a1], uncompressed[0x3a2], uncompressed[0x3a3]);
2090 import = crazylight_import;
2094 cave->map = gd_cave_map_new(cave, GdElement);
2096 for (y = 0; y < cave->h; y++)
2098 for (x = 0; x < cave->w; x++)
2100 int index = y * cave->w + x;
2102 cave->map[y][x] = import(uncompressed[index], index);
2106 /* crli has no levels */
2107 for (i = 0; i < 5; i++)
2109 cave->level_time[i] = (int)uncompressed[0x370] * 100 + uncompressed[0x371] * 10 + uncompressed[0x372];
2111 /* same as gate opening after 0 diamonds */
2112 if (cave->level_time[i] == 0)
2113 cave->level_time[i] = 1000;
2115 cave->level_diamonds[i] = (int)uncompressed[0x373] * 100 + uncompressed[0x374] * 10 + uncompressed[0x375];
2117 /* gate opening is checked AFTER adding to diamonds collected, so 0 here is 1000 (!) needed */
2118 if (cave->level_diamonds[i] == 0)
2119 cave->level_diamonds[i] = 1000;
2121 cave->level_ckdelay[i] = uncompressed[0x38A];
2122 cave->level_amoeba_time[i] = (int)uncompressed[0x37C] * 256 + uncompressed[0x37D];
2124 /* 0 immediately underflowed to 999, so we use 999. example: sendydash 3, cave 02. */
2125 if (cave->level_amoeba_time[i] == 0)
2126 cave->level_amoeba_time[i] = 999;
2128 cave->level_magic_wall_time[i] = (int)uncompressed[0x37E] * 256 + uncompressed[0x37F];
2129 cave->level_slime_permeability_c64[i] = uncompressed[0x38B];
2130 cave->level_bonus_time[i] = uncompressed[0x392];
2131 cave->level_penalty_time[i] = uncompressed[0x393];
2132 cave->level_amoeba_threshold[i] = 256 * (int)uncompressed[0x390] + uncompressed[0x390 + 1];
2135 cave->extra_diamond_value = (int)uncompressed[0x376] * 100 + uncompressed[0x377] * 10 + uncompressed[0x378];
2136 cave->diamond_value = (int)uncompressed[0x379] * 100 + uncompressed[0x37A] * 10 + uncompressed[0x37B];
2138 if (uncompressed[0x380])
2139 cave->creatures_direction_auto_change_time = uncompressed[0x381];
2141 cave->colorb = gd_c64_color(uncompressed[0x384] & 0xf); /* border */
2142 cave->color0 = gd_c64_color(uncompressed[0x385] & 0xf);
2143 cave->color1 = gd_c64_color(uncompressed[0x386] & 0xf);
2144 cave->color2 = gd_c64_color(uncompressed[0x387] & 0xf);
2145 cave->color3 = gd_c64_color(uncompressed[0x388] & 0x7); /* lower 3 bits only! */
2146 cave->color4 = cave->color3;
2147 cave->color5 = cave->color1;
2148 cave->intermission = uncompressed[0x389] != 0;
2150 /* if it is intermission but not scrollable */
2151 if (cave->intermission && !uncompressed[0x38c])
2157 /* AMOEBA in crazy dash 8:
2158 jsr $2500 ; generate true random
2159 and $94 ; binary and the current "probability"
2160 cmp #$04 ; compare to 4
2161 bcs out ; jump out (do not expand) if carry set, ie. result was less than 4.
2163 prob values can be like num = 3, 7, 15, 31, 63, ... n lsb bits count.
2164 0..3>=4? 0..7>=4? 0..15>=4? and similar.
2165 this way, probability of growing is 4/(num+1)
2168 /* probabilities store * 1M */
2169 cave->amoeba_growth_prob = (1E6 * 4.0 / (uncompressed[0x382] + 1)) + 0.5;
2171 if (cave->amoeba_growth_prob > 1000000)
2172 cave->amoeba_growth_prob = 1000000;
2174 cave->amoeba_fast_growth_prob = (1E6*4.0/(uncompressed[0x383] + 1)) + 0.5;
2176 if (cave->amoeba_fast_growth_prob > 1000000)
2177 cave->amoeba_fast_growth_prob = 1000000;
2179 /* 2c was a normal switch, 2d a changed one. */
2180 cave->creatures_backwards = uncompressed[0x38f] == 0x2d;
2181 cave->magic_wall_sound = uncompressed[0x38d] == 0xf1;
2183 /* 2e horizontal, 2f vertical. we implement this by changing them */
2184 if (uncompressed[0x38e] == 0x2f)
2186 for (y = 0; y < cave->h; y++)
2188 for (x = 0; x < cave->w; x++)
2190 if (cave->map[y][x] == O_H_EXPANDING_WALL)
2191 cave->map[y][x] = O_V_EXPANDING_WALL;
2196 cave->biter_delay_frame = uncompressed[0x394];
2197 cave->magic_wall_stops_amoeba = uncompressed[0x395] == 0; /* negated!! */
2198 cave->bomb_explosion_effect = import(uncompressed[0x396], 0x396);
2199 cave->explosion_effect = import(uncompressed[0x397], 0x397);
2200 cave->stone_bouncing_effect = import(uncompressed[0x398], 0x398);
2201 cave->diamond_birth_effect = import(uncompressed[0x399], 0x399);
2202 cave->magic_diamond_to = import(uncompressed[0x39a], 0x39a);
2204 cave->bladder_converts_by = import(uncompressed[0x39b], 0x39b);
2205 cave->diamond_falling_effect = import(uncompressed[0x39c], 0x39c);
2206 cave->biter_eat = import(uncompressed[0x39d], 0x39d);
2207 cave->slime_eats_1 = import(uncompressed[0x39e], 0x39e);
2208 cave->slime_converts_1 = import(uncompressed[0x39e] + 3, 0x39e);
2209 cave->slime_eats_2 = import(uncompressed[0x39f], 0x39f);
2210 cave->slime_converts_2 = import(uncompressed[0x39f] + 3, 0x39f);
2212 /* v3.0 has some new properties. */
2213 if (version >= V3_0)
2215 cave->diagonal_movements = uncompressed[0x3a4] != 0;
2216 cave->amoeba_too_big_effect = import(uncompressed[0x3a6], 0x3a6);
2217 cave->amoeba_enclosed_effect = import(uncompressed[0x3a7], 0x3a7);
2220 acid in crazy dream 8:
2221 jsr $2500 ; true random
2222 cmp $03a8 ; compare to ratio
2223 bcs out ; if it was smaller, forget it for now.
2225 ie. random<=ratio, then acid grows.
2228 /* * 1e6, probabilities are stored as int */
2229 cave->acid_spread_ratio = uncompressed[0x3a8] / 255.0 * 1E6;
2230 cave->acid_eats_this = import(uncompressed[0x3a9], 0x3a9);
2231 cave->expanding_wall_looks_like = import(uncompressed[0x3ab], 0x3ab);
2232 cave->dirt_looks_like = import(uncompressed[0x3ac], 0x3ac);
2236 /* version is <= 3.0, so this is a 1stb cave. */
2237 /* the only parameters, for which this matters, are these: */
2238 if (uncompressed[0x380] != 0)
2239 cave->creatures_direction_auto_change_time = uncompressed[0x381];
2241 cave->diagonal_movements = uncompressed[0x381] != 0;
2245 cave->selectable = !cave->intermission; /* best we can do */
2247 cave->selectable = !data[0]; /* given by converter */
2252 GdCavefileFormat gd_caveset_imported_get_format(const guint8 *buf)
2254 const char *s_bd1 = "GDashBD1";
2255 const char *s_bd1_atari = "GDashB1A";
2256 const char *s_dc1 = "GDashDC1";
2257 const char *s_bd2 = "GDashBD2";
2258 const char *s_bd2_atari = "GDashB2A";
2259 const char *s_plc = "GDashPLC";
2260 const char *s_plc_atari = "GDashPCA";
2261 const char *s_dlb = "GDashDLB";
2262 const char *s_crl = "GDashCRL";
2263 const char *s_cd7 = "GDashCD7";
2264 const char *s_cd9 = "GDashCD9";
2265 const char *s_1st = "GDash1ST";
2267 if (memcmp((char *)buf, s_bd1, strlen(s_bd1)) == 0)
2268 return GD_FORMAT_BD1;
2269 if (memcmp((char *)buf, s_bd1_atari, strlen(s_bd1_atari)) == 0)
2270 return GD_FORMAT_BD1_ATARI;
2271 if (memcmp((char *)buf, s_dc1, strlen(s_dc1)) == 0)
2272 return GD_FORMAT_DC1;
2273 if (memcmp((char *)buf, s_bd2, strlen(s_bd2)) == 0)
2274 return GD_FORMAT_BD2;
2275 if (memcmp((char *)buf, s_bd2_atari, strlen(s_bd2_atari)) == 0)
2276 return GD_FORMAT_BD2_ATARI;
2277 if (memcmp((char *)buf, s_plc, strlen(s_plc)) == 0)
2278 return GD_FORMAT_PLC;
2279 if (memcmp((char *)buf, s_plc_atari, strlen(s_plc_atari)) == 0)
2280 return GD_FORMAT_PLC_ATARI;
2281 if (memcmp((char *)buf, s_dlb, strlen(s_dlb)) == 0)
2282 return GD_FORMAT_DLB;
2283 if (memcmp((char *)buf, s_crl, strlen(s_crl)) == 0)
2284 return GD_FORMAT_CRLI;
2285 if (memcmp((char *)buf, s_cd7, strlen(s_cd7)) == 0)
2286 return GD_FORMAT_CRDR_7;
2287 if (memcmp((char *)buf, s_cd9, strlen(s_cd9)) == 0)
2288 return GD_FORMAT_CRDR_9;
2289 if (memcmp((char *)buf, s_1st, strlen(s_1st)) == 0)
2290 return GD_FORMAT_FIRSTB;
2292 return GD_FORMAT_UNKNOWN;
2296 Load caveset from memory buffer.
2297 Loads the caveset from a memory buffer.
2298 returns: List * of caves.
2300 List *gd_caveset_import_from_buffer (const guint8 *buf, gsize length)
2303 int cavenum, intermissionnum, num;
2304 int cavelength, bufp;
2305 List *caveset = NULL, *iter;
2306 guint32 encodedlength;
2307 GdCavefileFormat format;
2309 if (length != -1 && length < 12)
2311 Warn("buffer too short to be a GDash datafile");
2315 encodedlength = GUINT32_FROM_LE(*((guint32 *)(buf + 8)));
2316 if (length != -1 && encodedlength != length - 12)
2318 Warn("file length and data size mismatch in GDash datafile");
2322 format = gd_caveset_imported_get_format(buf);
2323 if (format == GD_FORMAT_UNKNOWN)
2325 Warn("buffer does not contain a GDash datafile");
2330 length = encodedlength;
2335 while (bufp < length)
2338 /* default is to append cave to caveset; list_insert appends when pos = -1 */
2341 newcave = gd_cave_new();
2343 cavelength = 0; /* to avoid compiler warning */
2347 case GD_FORMAT_BD1: /* boulder dash 1 */
2348 case GD_FORMAT_BD1_ATARI: /* boulder dash 1, atari version */
2349 case GD_FORMAT_DC1: /* deluxe caves 1 */
2350 case GD_FORMAT_BD2: /* boulder dash 2 */
2351 case GD_FORMAT_BD2_ATARI: /* boulder dash 2 */
2352 /* these are not in the data so we guess */
2353 newcave->selectable = (cavenum < 16) && (cavenum % 4 == 0);
2354 newcave->intermission = cavenum > 15;
2356 /* no name, so we make up one */
2357 if (newcave->intermission)
2358 snprintf(newcave->name, sizeof(newcave->name), _("Intermission %d"), cavenum - 15);
2360 snprintf(newcave->name, sizeof(newcave->name), _("Cave %c"), 'A' + cavenum);
2365 case GD_FORMAT_BD1_ATARI:
2367 cavelength = cave_copy_from_bd1(newcave, buf + bufp, length - bufp, format);
2370 case GD_FORMAT_BD2_ATARI:
2371 cavelength = cave_copy_from_bd2(newcave, buf + bufp, length - bufp, format);
2378 /* original bd1 had level order ABCDEFGH... and then the last four were the intermissions.
2379 * those should be inserted between D-E, H-I... caves. */
2381 insertpos = (cavenum - 15) * 5 - 1;
2384 case GD_FORMAT_FIRSTB:
2385 cavelength = cave_copy_from_1stb(newcave, buf + bufp, length - bufp);
2387 /* every fifth cave (4+1 intermission) is selectable. */
2388 newcave->selectable = cavenum % 5 == 0;
2391 case GD_FORMAT_PLC: /* peter liepa construction kit */
2392 case GD_FORMAT_PLC_ATARI: /* peter liepa construction kit, atari version */
2393 cavelength = cave_copy_from_plck(newcave, buf + bufp, length - bufp, format);
2397 /* no one's delight boulder dash, something like rle compressed plck caves */
2398 /* but there are 20 of them, as if it was a bd1 or bd2 game. also num%5 = 4 is intermission. */
2399 /* we have to set intermission flag on our own, as the file did not contain the info explicitly */
2400 newcave->intermission = (cavenum % 5) == 4;
2401 if (newcave->intermission)
2403 /* also set visible size */
2408 newcave->selectable = cavenum % 5 == 0; /* original selection scheme */
2409 if (newcave->intermission)
2410 snprintf(newcave->name, sizeof(newcave->name), _("Intermission %d"), cavenum / 5 + 1);
2412 snprintf(newcave->name, sizeof(newcave->name), _("Cave %c"), 'A'+(cavenum % 5 + cavenum / 5 * 4));
2414 cavelength = cave_copy_from_dlb (newcave, buf + bufp, length - bufp);
2417 case GD_FORMAT_CRLI:
2418 cavelength = cave_copy_from_crli (newcave, buf + bufp, length - bufp);
2421 case GD_FORMAT_CRDR_7:
2422 cavelength = cave_copy_from_crdr_7 (newcave, buf + bufp, length - bufp);
2425 case GD_FORMAT_CRDR_9:
2426 cavelength = cave_copy_from_crli (newcave, buf + bufp, length - bufp);
2427 if (cavelength != -1)
2428 crazy_dream_9_add_specials(newcave, buf, cavelength);
2431 case GD_FORMAT_UNKNOWN:
2435 if (cavelength == -1)
2437 gd_cave_free(newcave);
2439 Error("Aborting cave import.");
2444 caveset = list_insert(caveset, newcave, insertpos);
2450 /* hack: some dlb files contain junk data after 20 caves. */
2451 if (format == GD_FORMAT_DLB && cavenum == 20)
2454 Warn("excess data in dlb file, %d bytes", (int)(length-bufp));
2459 /* try to detect if plc caves are in standard layout. */
2460 /* that is, caveset looks like an original, (4 cave,1 intermission)+ */
2461 if (format == GD_FORMAT_PLC)
2462 /* if no selection table stored by any2gdash */
2463 if ((buf[2 + 0x1f0] != buf[2 + 0x1f1] - 1) ||
2464 (buf[2 + 0x1f0] != 0x19 && buf[2 + 0x1f0] != 0x0e))
2470 standard = (list_length(caveset)%5) == 0; /* cave count % 5 != 0 -> nonstandard */
2472 for (n = 0, iter = caveset; iter != NULL; n++, iter = iter->next)
2474 GdCave *cave = iter->data;
2476 if ((n % 5 == 4 && !cave->intermission) ||
2477 (n % 5 != 4 && cave->intermission))
2478 standard = FALSE; /* 4 cave, 1 intermission */
2481 /* if test passed, update selectability */
2483 for (n = 0, iter = caveset; iter != NULL; n++, iter = iter->next)
2485 GdCave *cave = iter->data;
2487 /* update "selectable" */
2488 cave->selectable = (n % 5) == 0;
2492 /* try to give some names for the caves */
2494 intermissionnum = 1;
2497 /* use numbering instead of letters, if following formats or too many caves
2498 (as we would run out of letters) */
2499 numbering = format == GD_FORMAT_PLC || format == GD_FORMAT_CRLI || list_length(caveset) > 26;
2501 for (iter = caveset; iter != NULL; iter = iter->next)
2503 GdCave *cave = (GdCave *)iter->data;
2505 if (!strEqual(cave->name, "")) /* if it already has a name, skip */
2508 if (cave->intermission)
2512 snprintf(cave->name, sizeof(cave->name), _("Intermission %02d"), num);
2514 snprintf(cave->name, sizeof(cave->name), _("Intermission %d"), intermissionnum);
2517 snprintf(cave->name, sizeof(cave->name), _("Cave %02d"), num);
2519 snprintf(cave->name, sizeof(cave->name), _("Cave %c"), 'A' - 1 + cavenum);
2523 if (cave->intermission)
2529 /* if the user requests, we make all caves selectable. intermissions not. */
2530 if (gd_import_as_all_caves_selectable)
2532 for (iter = caveset; iter != NULL; iter = iter->next)
2534 GdCave *cave = (GdCave *)iter->data;
2536 /* make selectable if not an intermission. */
2537 /* also selectable, if it was selectable originally, for some reason. */
2538 cave->selectable = cave->selectable || !cave->intermission;
2545 /* to be called at program start. */
2547 gd_c64_import_init_tables(void)