20100212
[gdash.git] / src / c64import.c
blob51ce10ecb6cc452b2c1ebff6740b0cdd2a8666ba
1 /*
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.
16 #include <glib.h>
17 #include <glib/gi18n.h>
18 #include <string.h>
19 #include "settings.h"
20 #include "cave.h"
21 #include "caveobject.h"
22 #include "cavedb.h"
23 #include "util.h"
25 #include "c64import.h"
27 /* conversion table for imported bd1 caves. */
28 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[]={
49 /* 0 */ O_STONE, O_DIAMOND, O_MAGIC_WALL, O_BRICK,
50 /* 4 */ O_STEEL, O_H_EXPANDING_WALL, O_VOODOO, O_DIRT,
51 /* 8 */ O_FIREFLY_1, O_BUTTER_4, O_AMOEBA, O_SLIME,
52 /* 12 */ O_PRE_INVIS_OUTBOX, O_PRE_OUTBOX, O_INBOX, O_SPACE
55 /* conversion table for imported 1stb caves. */
56 static const GdElement firstboulder_import_table[]={
57 /* 0 */ O_SPACE, O_DIRT, O_BRICK, O_MAGIC_WALL,
58 /* 4 */ O_PRE_OUTBOX, O_OUTBOX, O_PRE_INVIS_OUTBOX, O_INVIS_OUTBOX,
59 /* 8 */ O_FIREFLY_1, O_FIREFLY_2, O_FIREFLY_3, O_FIREFLY_4,
60 /* c */ O_FIREFLY_1, O_FIREFLY_2, O_FIREFLY_3, O_FIREFLY_4,
61 /* 10 */ O_STONE, O_STONE, O_STONE_F, O_STONE_F,
62 /* 14 */ O_DIAMOND, O_DIAMOND, O_DIAMOND_F, O_DIAMOND_F,
63 /* 18 */ O_PRE_CLOCK_1, O_PRE_CLOCK_2, O_PRE_CLOCK_3, O_PRE_CLOCK_4,
64 /* 1c */ O_BITER_SWITCH, O_BITER_SWITCH, O_BLADDER_SPENDER, O_PRE_DIA_1,
65 /* 20 */ O_PRE_DIA_1, O_PRE_DIA_2, O_PRE_DIA_3, O_PRE_DIA_4,
66 /* 24 */ O_PRE_DIA_5, O_INBOX, O_PRE_PL_1, O_PRE_PL_2,
67 /* 28 */ O_PRE_PL_3, O_CLOCK, O_H_EXPANDING_WALL, O_H_EXPANDING_WALL, /* CLOCK: not mentioned in marek's bd inside faq */
68 /* 2c */ O_CREATURE_SWITCH, O_CREATURE_SWITCH, O_EXPANDING_WALL_SWITCH, O_EXPANDING_WALL_SWITCH,
69 /* 30 */ O_BUTTER_3, O_BUTTER_4, O_BUTTER_1, O_BUTTER_2,
70 /* 34 */ O_BUTTER_3, O_BUTTER_4, O_BUTTER_1, O_BUTTER_2,
71 /* 38 */ O_STEEL, O_SLIME, O_BOMB, O_SWEET,
72 /* 3c */ O_PRE_STONE_1, O_PRE_STONE_2, O_PRE_STONE_3, O_PRE_STONE_4,
73 /* 40 */ O_BLADDER, O_BLADDER_1, O_BLADDER_2, O_BLADDER_3,
74 /* 44 */ O_BLADDER_4, O_BLADDER_5, O_BLADDER_6, O_BLADDER_7,
75 /* 48 */ O_BLADDER_8, O_BLADDER_8, O_EXPLODE_1, O_EXPLODE_1,
76 /* 4c */ O_EXPLODE_2, O_EXPLODE_3, O_EXPLODE_4, O_EXPLODE_5,
77 /* 50 */ O_PLAYER, O_PLAYER, O_PLAYER_BOMB, O_PLAYER_BOMB,
78 /* 54 */ O_PLAYER_GLUED, O_PLAYER_GLUED, O_VOODOO, O_AMOEBA,
79 /* 58 */ O_AMOEBA, O_BOMB_TICK_1, O_BOMB_TICK_2, O_BOMB_TICK_3,
80 /* 5c */ O_BOMB_TICK_4, O_BOMB_TICK_5, O_BOMB_TICK_6, O_BOMB_TICK_7,
81 /* 60 */ O_BOMB_EXPL_1, O_BOMB_EXPL_2, O_BOMB_EXPL_3, O_BOMB_EXPL_4,
82 /* 64 */ O_GHOST, O_GHOST, O_GHOST_EXPL_1, O_GHOST_EXPL_2,
83 /* 68 */ O_GHOST_EXPL_3, O_GHOST_EXPL_4, O_GRAVESTONE, O_STONE_GLUED,
84 /* 6c */ O_DIAMOND_GLUED, O_DIAMOND_KEY, O_TRAPPED_DIAMOND, O_GRAVESTONE,
85 /* 70 */ O_WAITING_STONE, O_WAITING_STONE, O_CHASING_STONE, O_CHASING_STONE,
86 /* 74 */ O_PRE_STEEL_1, O_PRE_STEEL_2, O_PRE_STEEL_3, O_PRE_STEEL_4,
87 /* 78 */ O_BITER_1, O_BITER_2, O_BITER_3, O_BITER_4,
88 /* 7c */ O_BITER_1, O_BITER_2, O_BITER_3, O_BITER_4,
91 /* conversion table for imported crazy dream caves. */
92 static const GdElement crazydream_import_table[]={
93 /* 0 */ O_SPACE, O_DIRT, O_BRICK, O_MAGIC_WALL,
94 /* 4 */ O_PRE_OUTBOX, O_OUTBOX, O_PRE_INVIS_OUTBOX, O_INVIS_OUTBOX,
95 /* 8 */ O_FIREFLY_1, O_FIREFLY_2, O_FIREFLY_3, O_FIREFLY_4,
96 /* c */ O_FIREFLY_1, O_FIREFLY_2, O_FIREFLY_3, O_FIREFLY_4,
97 /* 10 */ O_STONE, O_STONE, O_STONE_F, O_STONE_F,
98 /* 14 */ O_DIAMOND, O_DIAMOND, O_DIAMOND_F, O_DIAMOND_F,
99 /* 18 */ O_PRE_CLOCK_1, O_PRE_CLOCK_2, O_PRE_CLOCK_3, O_PRE_CLOCK_4,
100 /* 1c */ O_BITER_SWITCH, O_BITER_SWITCH, O_BLADDER_SPENDER, O_PRE_DIA_1, /* 6 different stages */
101 /* 20 */ O_PRE_DIA_1, O_PRE_DIA_2, O_PRE_DIA_3, O_PRE_DIA_4,
102 /* 24 */ O_PRE_DIA_5, O_INBOX, O_PRE_PL_1, O_PRE_PL_2,
103 /* 28 */ O_PRE_PL_3, O_CLOCK, O_H_EXPANDING_WALL, O_H_EXPANDING_WALL, /* CLOCK: not mentioned in marek's bd inside faq */
104 /* 2c */ O_CREATURE_SWITCH, O_CREATURE_SWITCH, O_EXPANDING_WALL_SWITCH, O_EXPANDING_WALL_SWITCH,
105 /* 30 */ O_BUTTER_3, O_BUTTER_4, O_BUTTER_1, O_BUTTER_2,
106 /* 34 */ O_BUTTER_3, O_BUTTER_4, O_BUTTER_1, O_BUTTER_2,
107 /* 38 */ O_STEEL, O_SLIME, O_BOMB, O_SWEET,
108 /* 3c */ O_PRE_STONE_1, O_PRE_STONE_2, O_PRE_STONE_3, O_PRE_STONE_4,
109 /* 40 */ O_BLADDER, O_BLADDER_1, O_BLADDER_2, O_BLADDER_3,
110 /* 44 */ O_BLADDER_4, O_BLADDER_5, O_BLADDER_6, O_BLADDER_7,
111 /* 48 */ O_BLADDER_8, O_BLADDER_8|SCANNED, O_EXPLODE_1, O_EXPLODE_1,
112 /* 4c */ O_EXPLODE_2, O_EXPLODE_3, O_EXPLODE_4, O_EXPLODE_5,
113 /* 50 */ O_PLAYER, O_PLAYER, O_PLAYER_BOMB, O_PLAYER_BOMB,
114 /* 54 */ O_PLAYER_GLUED, O_PLAYER_GLUED, O_VOODOO, O_AMOEBA,
115 /* 58 */ O_AMOEBA, O_BOMB_TICK_1, O_BOMB_TICK_2, O_BOMB_TICK_3,
116 /* 5c */ O_BOMB_TICK_4, O_BOMB_TICK_5, O_BOMB_TICK_6, O_BOMB_TICK_7,
117 /* 60 */ O_BOMB_EXPL_1, O_BOMB_EXPL_2, O_BOMB_EXPL_3, O_BOMB_EXPL_4,
118 /* 64 */ O_GHOST, O_GHOST, O_GHOST_EXPL_1, O_GHOST_EXPL_2,
119 /* 68 */ O_GHOST_EXPL_3, O_GHOST_EXPL_4, O_GRAVESTONE, O_STONE_GLUED,
120 /* 6c */ O_DIAMOND_GLUED, O_DIAMOND_KEY, O_TRAPPED_DIAMOND, O_GRAVESTONE,
121 /* 70 */ O_WAITING_STONE, O_WAITING_STONE, O_CHASING_STONE, O_CHASING_STONE,
122 /* 74 */ O_PRE_STEEL_1, O_PRE_STEEL_2, O_PRE_STEEL_3, O_PRE_STEEL_4,
123 /* 78 */ O_BITER_1, O_BITER_2, O_BITER_3, O_BITER_4,
124 /* 7c */ O_BITER_1, O_BITER_2, O_BITER_3, O_BITER_4,
126 /* 80 */ O_POT, O_PLAYER_STIRRING, O_GRAVITY_SWITCH, O_GRAVITY_SWITCH,
127 /* 84 */ O_PNEUMATIC_HAMMER, O_PNEUMATIC_HAMMER, O_BOX, O_BOX,
128 /* 88 */ O_UNKNOWN, O_UNKNOWN, O_ACID, O_ACID,
129 /* 8c */ O_KEY_1, O_KEY_2, O_KEY_3, O_UNKNOWN,
130 /* 90 */ O_UNKNOWN, O_UNKNOWN, O_UNKNOWN, O_UNKNOWN,
131 /* 94 */ O_UNKNOWN, O_TELEPORTER, O_UNKNOWN, O_SKELETON,
132 /* 98 */ O_WATER, O_WATER_16, O_WATER_15, O_WATER_14,
133 /* 9c */ O_WATER_13, O_WATER_12, O_WATER_11, O_WATER_10,
134 /* a0 */ O_WATER_9, O_WATER_8, O_WATER_7, O_WATER_6,
135 /* a4 */ O_WATER_5, O_WATER_4, O_WATER_3, O_WATER_2,
136 /* a8 */ O_WATER_1, O_COW_ENCLOSED_1, O_COW_ENCLOSED_2, O_COW_ENCLOSED_3,
137 /* ac */ O_COW_ENCLOSED_4, O_COW_ENCLOSED_5, O_COW_ENCLOSED_6, O_COW_ENCLOSED_7,
138 /* b0 */ O_COW_1, O_COW_2, O_COW_3, O_COW_4,
139 /* b4 */ O_COW_1, O_COW_2, O_COW_3, O_COW_4,
140 /* b8 */ O_DIRT_GLUED, O_STEEL_EXPLODABLE, O_DOOR_1, O_DOOR_2,
141 /* bc */ O_DOOR_3, O_FALLING_WALL, O_FALLING_WALL_F, O_FALLING_WALL_F,
142 /* c0 */ O_WALLED_DIAMOND, O_UNKNOWN, O_WALLED_KEY_1, O_WALLED_KEY_2,
143 /* c5=brick?! (vital key), c7=dirt?! (think twice) */
144 /* c7=dirt, as it has a code which will change it to dirt. */
145 /* c4 */ O_WALLED_KEY_3, O_BRICK, O_UNKNOWN, O_DIRT,
146 /* c8 */ O_DIRT2, O_UNKNOWN, O_UNKNOWN, O_UNKNOWN,
147 /* cc */ O_UNKNOWN, O_UNKNOWN, O_UNKNOWN, O_UNKNOWN,
148 /* d0 */ O_UNKNOWN, O_UNKNOWN, O_UNKNOWN, O_UNKNOWN,
149 /* d4 */ O_UNKNOWN, O_UNKNOWN, O_UNKNOWN, O_UNKNOWN,
150 /* d8 */ O_UNKNOWN, O_UNKNOWN, O_UNKNOWN, O_UNKNOWN,
151 /* dc */ O_UNKNOWN, O_UNKNOWN, O_UNKNOWN, O_UNKNOWN,
152 /* e0 */ O_ALT_FIREFLY_1, O_ALT_FIREFLY_2, O_ALT_FIREFLY_3, O_ALT_FIREFLY_4,
153 /* e4 */ O_ALT_FIREFLY_1, O_ALT_FIREFLY_2, O_ALT_FIREFLY_3, O_ALT_FIREFLY_4,
154 /* e8 */ O_ALT_BUTTER_3, O_ALT_BUTTER_4, O_ALT_BUTTER_1, O_ALT_BUTTER_2,
155 /* ec */ O_ALT_BUTTER_3, O_ALT_BUTTER_4, O_ALT_BUTTER_1, O_ALT_BUTTER_2,
156 /* f0 */ O_WATER, O_WATER, O_WATER, O_WATER,
157 /* f4 */ O_WATER, O_WATER, O_WATER, O_WATER,
158 /* f8 */ O_WATER, O_WATER, O_WATER, O_WATER,
159 /* fc */ O_WATER, O_WATER, O_WATER, O_WATER,
162 /* conversion table for imported 1stb caves. */
163 const GdElement gd_crazylight_import_table[]={
164 /* 0 */ O_SPACE, O_DIRT, O_BRICK, O_MAGIC_WALL,
165 /* 4 */ O_PRE_OUTBOX, O_OUTBOX, O_PRE_INVIS_OUTBOX, O_INVIS_OUTBOX,
166 /* 8 */ O_FIREFLY_1, O_FIREFLY_2, O_FIREFLY_3, O_FIREFLY_4,
167 /* c */ O_FIREFLY_1|SCANNED, O_FIREFLY_2|SCANNED, O_FIREFLY_3|SCANNED, O_FIREFLY_4|SCANNED,
168 /* 10 */ O_STONE, O_STONE|SCANNED, O_STONE_F, O_STONE_F|SCANNED,
169 /* 14 */ O_DIAMOND, O_DIAMOND|SCANNED, O_DIAMOND_F, O_DIAMOND_F|SCANNED,
170 /* 18 */ O_PRE_CLOCK_1, O_PRE_CLOCK_2, O_PRE_CLOCK_3, O_PRE_CLOCK_4,
171 /* 1c */ O_BITER_SWITCH, O_BITER_SWITCH, O_BLADDER_SPENDER, O_PRE_DIA_1, /* 6 different stages, the first is the pre_dia_0 */
172 /* 20 */ O_PRE_DIA_1, O_PRE_DIA_2, O_PRE_DIA_3, O_PRE_DIA_4,
173 /* 24 */ O_PRE_DIA_5, O_INBOX, O_PRE_PL_1, O_PRE_PL_2,
174 /* 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 */
175 /* 2c */ O_CREATURE_SWITCH, O_CREATURE_SWITCH, O_EXPANDING_WALL_SWITCH, O_EXPANDING_WALL_SWITCH,
176 /* 30 */ O_BUTTER_3, O_BUTTER_4, O_BUTTER_1, O_BUTTER_2,
177 /* 34 */ O_BUTTER_3|SCANNED, O_BUTTER_4|SCANNED, O_BUTTER_1|SCANNED, O_BUTTER_2|SCANNED,
178 /* 38 */ O_STEEL, O_SLIME, O_BOMB, O_SWEET,
179 /* 3c */ O_PRE_STONE_1, O_PRE_STONE_2, O_PRE_STONE_3, O_PRE_STONE_4,
180 /* 40 */ O_BLADDER, O_BLADDER_1, O_BLADDER_2, O_BLADDER_3,
181 /* 44 */ O_BLADDER_4, O_BLADDER_5, O_BLADDER_6, O_BLADDER_7,
182 /* 48 */ O_BLADDER_8, O_BLADDER_8|SCANNED, O_EXPLODE_1, O_EXPLODE_1,
183 /* 4c */ O_EXPLODE_2, O_EXPLODE_3, O_EXPLODE_4, O_EXPLODE_5,
184 /* 50 */ O_PLAYER, O_PLAYER|SCANNED, O_PLAYER_BOMB, O_PLAYER_BOMB|SCANNED,
185 /* 54 */ O_PLAYER_GLUED, O_PLAYER_GLUED|SCANNED, O_VOODOO, O_AMOEBA,
186 /* 58 */ O_AMOEBA|SCANNED, O_BOMB_TICK_1, O_BOMB_TICK_2, O_BOMB_TICK_3,
187 /* 5c */ O_BOMB_TICK_4, O_BOMB_TICK_5, O_BOMB_TICK_6, O_BOMB_TICK_7,
188 /* 60 */ O_BOMB_EXPL_1, O_BOMB_EXPL_2, O_BOMB_EXPL_3, O_BOMB_EXPL_4,
189 /* 64 */ O_ACID, O_ACID, O_FALLING_WALL, O_FALLING_WALL_F,
190 /* 68 */ O_FALLING_WALL_F|SCANNED, O_BOX, O_GRAVESTONE, O_STONE_GLUED,
191 /* 6c */ O_DIAMOND_GLUED, O_DIAMOND_KEY, O_TRAPPED_DIAMOND, O_GRAVESTONE,
192 /* 70 */ O_WAITING_STONE, O_WAITING_STONE|SCANNED, O_CHASING_STONE, O_CHASING_STONE|SCANNED,
193 /* 74 */ O_PRE_STEEL_1, O_PRE_STEEL_2, O_PRE_STEEL_3, O_PRE_STEEL_4,
194 /* 78 */ O_BITER_1, O_BITER_2, O_BITER_3, O_BITER_4,
195 /* 7c */ O_BITER_1|SCANNED, O_BITER_2|SCANNED, O_BITER_3|SCANNED, O_BITER_4|SCANNED,
198 #if 0
199 static guint8 no1_default_colors[]={
200 4, 10, 1, 8, 9, 3, 12, 11, 1, 6, 14, 7, 14, 3, 7,
201 5, 8, 7, 4, 9, 3, 10, 5, 1, 5, 4, 1, 9, 6, 1,
202 12, 11, 5, 4, 2, 7, 14, 4, 7, 10, 8, 1, 8, 5, 7,
203 14, 2, 3, 3, 11, 1, 7, 5, 1, 11, 10, 7, 9, 8, 1
205 #endif
218 GdPropertyDefault gd_defaults_bd1[] = {
219 {CAVE_OFFSET(level_amoeba_threshold), 200},
220 {CAVE_OFFSET(amoeba_growth_prob), 31250},
221 {CAVE_OFFSET(amoeba_fast_growth_prob), 250000},
222 {CAVE_OFFSET(amoeba_timer_started_immediately), TRUE},
223 {CAVE_OFFSET(amoeba_timer_wait_for_hatching), FALSE},
224 {CAVE_OFFSET(lineshift), TRUE},
225 {CAVE_OFFSET(wraparound_objects), TRUE},
226 {CAVE_OFFSET(diagonal_movements), FALSE},
227 {CAVE_OFFSET(voodoo_collects_diamonds), FALSE},
228 {CAVE_OFFSET(voodoo_dies_by_stone), FALSE},
229 {CAVE_OFFSET(voodoo_disappear_in_explosion), TRUE},
230 {CAVE_OFFSET(voodoo_any_hurt_kills_player), FALSE},
231 {CAVE_OFFSET(creatures_backwards), FALSE},
232 {CAVE_OFFSET(creatures_direction_auto_change_on_start), FALSE},
233 {CAVE_OFFSET(creatures_direction_auto_change_time), 0},
234 {CAVE_OFFSET(level_hatching_delay_time[0]), 2},
235 {CAVE_OFFSET(intermission_instantlife), TRUE},
236 {CAVE_OFFSET(intermission_rewardlife), FALSE},
237 {CAVE_OFFSET(magic_wall_stops_amoeba), TRUE},
238 {CAVE_OFFSET(magic_timer_wait_for_hatching), FALSE},
239 {CAVE_OFFSET(pushing_stone_prob), 250000},
240 {CAVE_OFFSET(pushing_stone_prob_sweet), 1000000},
241 {CAVE_OFFSET(active_is_first_found), FALSE},
242 {CAVE_OFFSET(short_explosions), TRUE},
243 {CAVE_OFFSET(slime_predictable), TRUE},
244 {CAVE_OFFSET(snap_element), O_SPACE},
245 {CAVE_OFFSET(max_time), 999},
247 {CAVE_OFFSET(scheduling), GD_SCHEDULING_BD1},
248 {CAVE_OFFSET(pal_timing), TRUE},
249 {-1},
252 GdPropertyDefault gd_defaults_bd2[] = {
253 {CAVE_OFFSET(level_amoeba_threshold), 200},
254 {CAVE_OFFSET(amoeba_growth_prob), 31250},
255 {CAVE_OFFSET(amoeba_fast_growth_prob), 250000},
256 {CAVE_OFFSET(amoeba_timer_started_immediately), FALSE},
257 {CAVE_OFFSET(amoeba_timer_wait_for_hatching), FALSE},
258 {CAVE_OFFSET(lineshift), TRUE},
259 {CAVE_OFFSET(wraparound_objects), TRUE},
260 {CAVE_OFFSET(diagonal_movements), FALSE},
261 {CAVE_OFFSET(voodoo_collects_diamonds), FALSE},
262 {CAVE_OFFSET(voodoo_dies_by_stone), FALSE},
263 {CAVE_OFFSET(voodoo_disappear_in_explosion), TRUE},
264 {CAVE_OFFSET(voodoo_any_hurt_kills_player), FALSE},
265 {CAVE_OFFSET(creatures_backwards), FALSE},
266 {CAVE_OFFSET(creatures_direction_auto_change_on_start), FALSE},
267 {CAVE_OFFSET(creatures_direction_auto_change_time), 0},
268 {CAVE_OFFSET(level_hatching_delay_time[0]), 2},
269 {CAVE_OFFSET(intermission_instantlife), TRUE},
270 {CAVE_OFFSET(intermission_rewardlife), FALSE},
271 {CAVE_OFFSET(magic_wall_stops_amoeba), FALSE}, /* marek roth bd inside faq 3.0 */
272 {CAVE_OFFSET(magic_timer_wait_for_hatching), FALSE},
273 {CAVE_OFFSET(pushing_stone_prob), 250000},
274 {CAVE_OFFSET(pushing_stone_prob_sweet), 1000000},
275 {CAVE_OFFSET(active_is_first_found), FALSE},
276 {CAVE_OFFSET(short_explosions), TRUE},
277 {CAVE_OFFSET(slime_predictable), TRUE},
278 {CAVE_OFFSET(snap_element), O_SPACE},
279 {CAVE_OFFSET(max_time), 999},
281 {CAVE_OFFSET(pal_timing), TRUE},
282 {CAVE_OFFSET(scheduling), GD_SCHEDULING_BD2},
283 {-1},
286 GdPropertyDefault gd_defaults_plck[] = {
287 {CAVE_OFFSET(amoeba_growth_prob), 31250},
288 {CAVE_OFFSET(amoeba_fast_growth_prob), 250000},
289 {CAVE_OFFSET(amoeba_timer_started_immediately), FALSE},
290 {CAVE_OFFSET(amoeba_timer_wait_for_hatching), FALSE},
291 {CAVE_OFFSET(lineshift), TRUE},
292 {CAVE_OFFSET(wraparound_objects), TRUE},
293 {CAVE_OFFSET(border_scan_first_and_last), FALSE},
294 {CAVE_OFFSET(diagonal_movements), FALSE},
295 {CAVE_OFFSET(voodoo_collects_diamonds), FALSE},
296 {CAVE_OFFSET(voodoo_dies_by_stone), FALSE},
297 {CAVE_OFFSET(voodoo_disappear_in_explosion), TRUE},
298 {CAVE_OFFSET(voodoo_any_hurt_kills_player), FALSE},
299 {CAVE_OFFSET(creatures_backwards), FALSE},
300 {CAVE_OFFSET(creatures_direction_auto_change_on_start), FALSE},
301 {CAVE_OFFSET(creatures_direction_auto_change_time), 0},
302 {CAVE_OFFSET(level_hatching_delay_time[0]), 2},
303 {CAVE_OFFSET(intermission_instantlife), TRUE},
304 {CAVE_OFFSET(intermission_rewardlife), FALSE},
305 {CAVE_OFFSET(magic_wall_stops_amoeba), FALSE},
306 {CAVE_OFFSET(magic_timer_wait_for_hatching), FALSE},
307 {CAVE_OFFSET(pushing_stone_prob), 250000},
308 {CAVE_OFFSET(pushing_stone_prob_sweet), 1000000},
309 {CAVE_OFFSET(active_is_first_found), FALSE},
310 {CAVE_OFFSET(short_explosions), TRUE},
311 {CAVE_OFFSET(snap_element), O_SPACE},
312 {CAVE_OFFSET(max_time), 999},
314 {CAVE_OFFSET(pal_timing), TRUE},
315 {CAVE_OFFSET(scheduling), GD_SCHEDULING_PLCK},
316 {-1},
319 GdPropertyDefault gd_defaults_1stb[] = {
320 {CAVE_OFFSET(amoeba_growth_prob), 31250},
321 {CAVE_OFFSET(amoeba_fast_growth_prob), 250000},
322 {CAVE_OFFSET(amoeba_timer_started_immediately), FALSE},
323 {CAVE_OFFSET(amoeba_timer_wait_for_hatching), TRUE},
324 {CAVE_OFFSET(lineshift), TRUE},
325 {CAVE_OFFSET(wraparound_objects), TRUE},
326 {CAVE_OFFSET(voodoo_collects_diamonds), TRUE},
327 {CAVE_OFFSET(voodoo_dies_by_stone), TRUE},
328 {CAVE_OFFSET(voodoo_disappear_in_explosion), FALSE},
329 {CAVE_OFFSET(voodoo_any_hurt_kills_player), FALSE},
330 {CAVE_OFFSET(creatures_direction_auto_change_on_start), TRUE},
331 {CAVE_OFFSET(level_hatching_delay_time[0]), 2},
332 {CAVE_OFFSET(intermission_instantlife), FALSE},
333 {CAVE_OFFSET(intermission_rewardlife), TRUE},
334 {CAVE_OFFSET(magic_timer_wait_for_hatching), TRUE},
335 {CAVE_OFFSET(pushing_stone_prob), 250000},
336 {CAVE_OFFSET(pushing_stone_prob_sweet), 1000000},
337 {CAVE_OFFSET(active_is_first_found), TRUE},
338 {CAVE_OFFSET(short_explosions), FALSE},
339 {CAVE_OFFSET(slime_predictable), TRUE},
340 {CAVE_OFFSET(snap_element), O_SPACE},
341 {CAVE_OFFSET(max_time), 999},
343 {CAVE_OFFSET(pal_timing), TRUE},
344 {CAVE_OFFSET(scheduling), GD_SCHEDULING_PLCK},
345 {CAVE_OFFSET(amoeba_enclosed_effect), O_PRE_DIA_1}, /* not immediately to diamond, but with animation */
346 {CAVE_OFFSET(dirt_looks_like), O_DIRT2},
347 {-1},
350 GdPropertyDefault gd_defaults_crdr_7[] = {
351 {CAVE_OFFSET(amoeba_growth_prob), 31250},
352 {CAVE_OFFSET(amoeba_fast_growth_prob), 250000},
353 {CAVE_OFFSET(amoeba_timer_started_immediately), FALSE},
354 {CAVE_OFFSET(amoeba_timer_wait_for_hatching), TRUE},
355 {CAVE_OFFSET(lineshift), TRUE},
356 {CAVE_OFFSET(wraparound_objects), TRUE},
357 {CAVE_OFFSET(voodoo_collects_diamonds), TRUE},
358 {CAVE_OFFSET(voodoo_dies_by_stone), TRUE},
359 {CAVE_OFFSET(voodoo_disappear_in_explosion), FALSE},
360 {CAVE_OFFSET(voodoo_any_hurt_kills_player), FALSE},
361 {CAVE_OFFSET(creatures_direction_auto_change_on_start), FALSE},
362 {CAVE_OFFSET(level_hatching_delay_time[0]), 2},
363 {CAVE_OFFSET(intermission_instantlife), FALSE},
364 {CAVE_OFFSET(intermission_rewardlife), TRUE},
365 {CAVE_OFFSET(magic_timer_wait_for_hatching), TRUE},
366 {CAVE_OFFSET(pushing_stone_prob), 250000},
367 {CAVE_OFFSET(pushing_stone_prob_sweet), 1000000},
368 {CAVE_OFFSET(active_is_first_found), TRUE},
369 {CAVE_OFFSET(short_explosions), FALSE},
370 {CAVE_OFFSET(slime_predictable), TRUE},
371 {CAVE_OFFSET(snap_element), O_SPACE},
372 {CAVE_OFFSET(max_time), 999},
374 {CAVE_OFFSET(pal_timing), TRUE},
375 {CAVE_OFFSET(scheduling), GD_SCHEDULING_CRDR},
376 {CAVE_OFFSET(amoeba_enclosed_effect), O_PRE_DIA_1}, /* not immediately to diamond, but with animation */
377 {CAVE_OFFSET(water_does_not_flow_down), TRUE},
378 {CAVE_OFFSET(skeletons_worth_diamonds), 1}, /* in crdr, skeletons can also be used to open the gate */
379 {CAVE_OFFSET(gravity_affects_all), FALSE}, /* the intermission "survive" needs this flag */
380 {-1},
383 GdPropertyDefault gd_defaults_crli[] = {
384 {CAVE_OFFSET(amoeba_growth_prob), 31250},
385 {CAVE_OFFSET(amoeba_fast_growth_prob), 250000},
386 {CAVE_OFFSET(amoeba_timer_started_immediately), FALSE},
387 {CAVE_OFFSET(amoeba_timer_wait_for_hatching), TRUE},
388 {CAVE_OFFSET(lineshift), TRUE},
389 {CAVE_OFFSET(wraparound_objects), TRUE},
390 {CAVE_OFFSET(voodoo_collects_diamonds), TRUE},
391 {CAVE_OFFSET(voodoo_dies_by_stone), TRUE},
392 {CAVE_OFFSET(voodoo_disappear_in_explosion), FALSE},
393 {CAVE_OFFSET(voodoo_any_hurt_kills_player), FALSE},
394 {CAVE_OFFSET(creatures_direction_auto_change_on_start), FALSE},
395 {CAVE_OFFSET(level_hatching_delay_time[0]), 2},
396 {CAVE_OFFSET(intermission_instantlife), FALSE},
397 {CAVE_OFFSET(intermission_rewardlife), TRUE},
398 {CAVE_OFFSET(magic_timer_wait_for_hatching), TRUE},
399 {CAVE_OFFSET(pushing_stone_prob), 250000},
400 {CAVE_OFFSET(pushing_stone_prob_sweet), 1000000},
401 {CAVE_OFFSET(active_is_first_found), TRUE},
402 {CAVE_OFFSET(short_explosions), FALSE},
403 {CAVE_OFFSET(slime_predictable), TRUE},
404 {CAVE_OFFSET(max_time), 999},
406 {CAVE_OFFSET(pal_timing), TRUE},
407 {CAVE_OFFSET(scheduling), GD_SCHEDULING_PLCK},
408 {CAVE_OFFSET(amoeba_enclosed_effect), O_PRE_DIA_1}, /* not immediately to diamond, but with animation */
409 {-1},
412 /* internal character (letter) codes in c64 games.
413 missing: "triple line" after >, diamond between ()s, player's head after )
414 used for converting names of caves imported from crli and other types of binary data */
415 const char gd_bd_internal_chars[]=" ,!./0123456789:*<=> ABCDEFGHIJKLMNOPQRSTUVWXYZ( ) _";
417 /* used for bdcff engine flag. */
418 const char *gd_engines[]={"BD1", "BD2", "PLCK", "1stB", "CrDr", "CrLi"};
423 /* to convert predictable slime values to bit masks */
424 static int
425 slime_shift_msb(int c64_data)
427 int i, perm;
429 perm=0;
430 for (i=0; i<c64_data; i++)
431 /* shift in this many msb 1's */
432 perm=(0x100|perm)>>1;
433 return perm;
438 static GdElement
439 bd1_import(guint8 c, int i)
441 if (c<G_N_ELEMENTS(bd1_import_table))
442 return bd1_import_table[c];
443 g_warning("Invalid BD1 element in imported file at cave data %d: %d", i, c);
444 return O_UNKNOWN;
447 /* deluxe caves 1 contained a special element, non-sloped brick. */
448 static GdElement
449 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;
456 return e;
459 static GdElement
460 firstboulder_import(guint8 c, int i)
462 if (c<G_N_ELEMENTS(firstboulder_import_table))
463 return firstboulder_import_table[c];
464 g_warning("Invalid 1stB element in imported file at cave data %d: %d", i, c);
465 return O_UNKNOWN;
468 static GdElement
469 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 */
473 g_warning("Invalid CrLi element in imported file at cave data %d: %d", i, c);
474 return O_UNKNOWN;
480 #if 0
481 typedef enum _dirt_mod {
482 DIRT_MOD_NEVER,
483 DIRT_MOD_SLIME,
484 DIRT_MOD_AMOEBA,
485 DIRT_MOD_BOTH,
486 } DirtModType;
488 static void
489 set_dirt_mod (GdCave *cave, DirtModType mod_type)
491 GdElement elem1, elem2;
492 gboolean dirt=FALSE;
493 GList *iter;
494 int i;
496 /* routine below can check for two different elements; if we need only one,
497 set variables to same value */
498 switch (mod_type) {
499 default:
500 case DIRT_MOD_NEVER:
501 return;
502 case DIRT_MOD_SLIME:
503 elem1=elem2=O_SLIME;
504 break;
505 case DIRT_MOD_AMOEBA:
506 elem1=elem2=O_AMOEBA;
507 break;
508 case DIRT_MOD_BOTH:
509 elem1=O_SLIME;
510 elem2=O_AMOEBA;
511 break;
514 if (cave->map) {
515 int x, y;
516 for (y=0; y<cave->h; y++)
517 for (x=0; x<cave->w; x++)
518 if (cave->map[y][x]==elem1 || cave->map[y][x]==elem2)
519 dirt=TRUE;
521 for (i=0; i<G_N_ELEMENTS(cave->random_fill); i++)
522 if (cave->random_fill[i]==elem1 || cave->random_fill[i]==elem2)
523 dirt=TRUE;
524 for (iter=cave->objects; iter!=NULL; iter=iter->next) {
525 GdObject *object=(GdObject *) iter->data;
527 if (object->element==elem1 || object->fill_element==elem1 ||
528 object->element==elem2 || object->fill_element==elem2)
529 dirt=TRUE;
531 if (dirt)
532 cave->dirt_looks_like=O_DIRT2;
533 return;
535 #endif
541 GdPropertyDefault *
542 gd_get_engine_default_array(GdEngine engine)
544 switch(engine) {
545 case GD_ENGINE_BD1:
546 return gd_defaults_bd1;
547 break;
548 case GD_ENGINE_BD2:
549 return gd_defaults_bd2;
550 break;
551 case GD_ENGINE_PLCK:
552 return gd_defaults_plck;
553 break;
554 case GD_ENGINE_1STB:
555 return gd_defaults_1stb;
556 break;
557 case GD_ENGINE_CRDR7:
558 return gd_defaults_crdr_7;
559 break;
560 case GD_ENGINE_CRLI:
561 return gd_defaults_crli;
562 break;
564 /* to avoid compiler warning */
565 case GD_ENGINE_INVALID:
566 g_assert_not_reached();
567 break;
570 return gd_defaults_bd1;
574 void
575 gd_cave_set_engine_defaults(GdCave *cave, GdEngine engine)
577 gd_cave_set_defaults_from_array(cave, gd_get_engine_default_array(engine));
579 /* these have hardcoded ckdelay. */
580 /* setting this ckdelay array does not fit into the gd_struct_default scheme. */
581 if (engine==GD_ENGINE_BD1) {
582 cave->level_ckdelay[0]=12;
583 cave->level_ckdelay[1]=6;
584 cave->level_ckdelay[2]=3;
585 cave->level_ckdelay[3]=1;
586 cave->level_ckdelay[4]=0;
588 if (engine==GD_ENGINE_BD2) {
589 cave->level_ckdelay[0]=9; /* 180ms */
590 cave->level_ckdelay[1]=8; /* 160ms */
591 cave->level_ckdelay[2]=7; /* 140ms */
592 cave->level_ckdelay[3]=6; /* 120ms */
593 cave->level_ckdelay[4]=6; /* 120ms (!) not faster than level4 */
598 GdEngine
599 gd_cave_get_engine_from_string(const char *param)
601 int i;
603 for (i=0; i<GD_ENGINE_INVALID; i++)
604 if (g_ascii_strcasecmp(param, gd_engines[i])==0)
605 return (GdEngine) i;
607 return GD_ENGINE_INVALID;
612 /****************************************************************************
614 * cave import routines.
615 * take a cave, data, and maybe remaining bytes.
616 * return the number of bytes read, -1 if error.
618 ****************************************************************************/
623 take care of required diamonds values==0 or >100.
624 in original bd, the counter was only two-digit. so bd3 cave f
625 says 150 diamonds required, but you only had to collect 50.
626 also, gate opening is triggered by incrementing diamond
627 count and THEN checking if more required; so if required was
628 0, you had to collect 100. (also check crazy light 8 cave "1000")
630 http://www.boulder-dash.nl/forum/viewtopic.php?t=88
633 /* import bd1 cave data into our format. */
634 static int
635 cave_copy_from_bd1(GdCave *cave, const guint8 *data, int remaining_bytes, GdCavefileFormat format)
637 int length, direction;
638 int index;
639 int level;
640 int x1, y1, x2, y2;
641 guint8 code;
642 GdElement elem;
643 int i;
644 GdElement (* import_func) (guint8 c, int i);
646 gd_error_set_context(cave->name);
648 /* some checks */
649 g_assert(format==GD_FORMAT_BD1 || format==GD_FORMAT_DC1 || format==GD_FORMAT_BD1_ATARI);
650 /* cant be shorted than this: header + no objects + delimiter */
651 if (remaining_bytes<33) {
652 g_critical("truncated BD1 cave data, %d bytes", remaining_bytes);
653 return -1;
656 gd_cave_set_engine_defaults(cave, GD_ENGINE_BD1);
657 if (format==GD_FORMAT_BD1_ATARI)
658 cave->scheduling=GD_SCHEDULING_BD1_ATARI;
659 if (format==GD_FORMAT_DC1)
660 import_func=deluxecaves_1_import;
661 else
662 import_func=bd1_import;
663 /* set visible size for intermission */
664 if (cave->intermission) {
665 cave->x2=19;
666 cave->y2=11;
669 /* cave number data[0] */
670 cave->diamond_value=data[2];
671 cave->extra_diamond_value=data[3];
673 for (level=0; level<5; level++) {
674 cave->level_amoeba_time[level]=data[1];
675 if (cave->level_amoeba_time[level]==0) /* 0 immediately underflowed to 999, so we use 999. example: sendydash 3, cave 02. */
676 cave->level_amoeba_time[level]=999;
677 cave->level_magic_wall_time[level]=data[1];
678 cave->level_rand[level]=data[4 + level];
679 cave->level_diamonds[level]=data[9 + level] % 100; /* check comment above */
680 if (cave->level_diamonds[level]==0) /* gate opening is checked AFTER adding to diamonds collected, so 0 here means 100 to collect */
681 cave->level_diamonds[level]=100;
682 cave->level_time[level]=data[14 + level];
685 /* LogicDeLuxe extension: acid
686 $16 Acid speed (unused in the original BD1)
687 $17 Bit 2: if set, Acid's original position converts to explosion puff during spreading. Otherwise, Acid remains intact, ie. it's just growing. (unused in the original BD1)
688 $1C Acid eats this element. (also Probability of element 1)
690 there is no problem importing these; as other bd1 caves did not contain acid at all, so it does not matter
691 how we set the values.
693 cave->acid_eats_this=import_func(data[0x1c]&0x3F, 0x1c); /* 0x1c index: same as probability1 !!!!! don't be surprised. we do a &0x3f because of this */
694 cave->acid_spread_ratio=data[0x16]/255.0*1E6+0.5; /* acid speed, *1e6 as probabilities are stored in int */
695 cave->acid_turns_to=(data[0x17]&(1<<2))?O_EXPLODE_3:O_ACID;
697 if (format==GD_FORMAT_BD1_ATARI) {
698 /* atari colors */
699 cave->color1=gd_atari_color(data[0x13]);
700 cave->color2=gd_atari_color(data[0x14]);
701 cave->color3=gd_atari_color(data[0x15]);
702 cave->color4=gd_atari_color(data[0x16]); /* in atari, amoeba was green */
703 cave->color5=gd_atari_color(data[0x16]); /* in atari, slime was green */
704 cave->colorb=gd_atari_color(data[0x17]); /* border = background */
705 cave->color0=gd_atari_color(data[0x17]); /* background */
706 } else {
707 /* c64 colors */
708 cave->colorb=gd_c64_color(0); /* border = background, fixed color */
709 cave->color0=gd_c64_color(0); /* background, fixed color */
710 cave->color1=gd_c64_color(data[0x13]&0xf);
711 cave->color2=gd_c64_color(data[0x14]&0xf);
712 cave->color3=gd_c64_color(data[0x15]&0x7); /* lower 3 bits only (vic-ii worked this way) */
713 cave->color4=cave->color3; /* in bd1, amoeba was color3 */
714 cave->color5=cave->color3; /* no slime, but let it be color 3 */
717 /* random fill */
718 for (i=0; i < 4; i++) {
719 cave->random_fill[i]=import_func(data[24+i], 24+i);
720 cave->random_fill_probability[i]=data[28+i];
724 * Decode the explicit cave data
726 index=32;
727 while(data[index]!=0xFF && index<remaining_bytes && index<255) {
728 code=data[index];
729 /* crazy dream 3 extension: */
730 if (code==0x0f) {
731 int x1, y1, nx, ny, dx, dy;
732 int x, y;
734 /* as this one uses nonstandard dx dy values, create points instead */
735 elem=import_func(data[index+1], index+1);
736 x1=data[index+2];
737 y1=data[index+3]-2;
738 nx=data[index+4];
739 ny=data[index+5];
740 dx=data[index+6];
741 dy=data[index+7]+1;
743 for (y=0; y<ny; y++)
744 for (x=0; x<nx; x++) {
745 int pos=x1+ y1*40+ y*dy*40 +x*dx;
747 cave->objects=g_list_append(cave->objects, gd_object_new_point(GD_OBJECT_LEVEL_ALL, pos%40, pos/40, elem));
749 index+=8;
750 } else {
751 /* object is code&3f, object type is upper 2 bits */
752 elem=import_func(code & 0x3F, index);
754 switch ((code >> 6) & 3) {
755 case 0: /* 00: POINT */
756 x1=data[index+1];
757 y1=data[index+2]-2;
758 if (x1>=cave->w || y1>=cave->h)
759 g_warning("invalid point coordinates %d,%d at byte %d", x1, y1, index);
760 cave->objects=g_list_append(cave->objects, gd_object_new_point(GD_OBJECT_LEVEL_ALL, x1, y1, elem));
761 index+=3;
762 break;
763 case 1: /* 01: LINE */
764 x1=data[index+1];
765 y1=data[index+2]-2;
766 length=(gint8)data[index+3]-1;
767 direction=data[index+4];
768 if (length<0) {
769 g_warning("line length negative, not displaying line at all, at byte %d", index);
770 } else {
771 if (direction>MV_UP_LEFT) {
772 g_warning("invalid line direction %d at byte %d", direction, index);
773 direction=MV_STILL;
775 x2=x1+length*gd_dx[direction+1];
776 y2=y1+length*gd_dy[direction+1];
777 if (x1>=cave->w || y1>=cave->h || x2>=cave->w || y2>=cave->h)
778 g_warning("invalid line coordinates %d,%d %d,%d at byte %d", x1, y1, x2, y2, index);
779 cave->objects=g_list_append(cave->objects, gd_object_new_line(GD_OBJECT_LEVEL_ALL, x1, y1, x2, y2, elem));
781 index+=5;
782 break;
783 case 2: /* 10: FILLED RECTANGLE */
784 x1=data[index+1];
785 y1=data[index+2]-2;
786 x2=x1+data[index+3]-1; /* width */
787 y2=y1+data[index+4]-1; /* height */
788 if (x1>=cave->w || y1>=cave->h || x2>=cave->w || y2>=cave->h)
789 g_warning("invalid filled rectangle coordinates %d,%d %d,%d at byte %d", x1, y1, x2, y2, index);
790 cave->objects=g_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)));
791 index+=6;
792 break;
793 case 3: /* 11: OPEN RECTANGLE (OUTLINE) */
794 x1=data[index+1];
795 y1=data[index+2]-2;
796 x2=x1+data[index+3]-1;
797 y2=y1+data[index+4]-1;
798 if (x1>=cave->w || y1>=cave->h || x2>=cave->w || y2>=cave->h)
799 g_warning("invalid rectangle coordinates %d,%d %d,%d at byte %d", x1, y1, x2, y2, index);
800 cave->objects=g_list_append(cave->objects, gd_object_new_rectangle(GD_OBJECT_LEVEL_ALL, x1, y1, x2, y2, elem));
801 index+=5;
802 break;
806 if (data[index]!=0xFF) {
807 g_critical("import error, cave not delimited with 0xFF");
808 return -1;
811 return index+1;
814 /* import bd2 cave data into our format. return number of bytes if pointer passed.
815 this is pretty much the same as above, only the encoding was different. */
816 static int
817 cave_copy_from_bd2(GdCave *cave, const guint8 *data, int remaining_bytes, GdCavefileFormat format)
819 int index;
820 int i;
821 int x, y, rx, ry;
822 int x1, y1, x2, y2, dx, dy;
823 GdElement elem;
825 g_assert(format==GD_FORMAT_BD2 || format==GD_FORMAT_BD2_ATARI);
827 gd_error_set_context(cave->name);
828 if (remaining_bytes<0x1A+5) {
829 g_critical("truncated BD2 cave data, %d bytes", remaining_bytes);
830 return -1;
832 gd_cave_set_engine_defaults(cave, GD_ENGINE_BD2);
833 if (format==GD_FORMAT_BD2_ATARI)
834 cave->scheduling=GD_SCHEDULING_BD2_PLCK_ATARI;
836 /* set visible size for intermission */
837 if (cave->intermission) {
838 cave->x2=19;
839 cave->y2=11;
842 cave->diamond_value=data[1];
843 cave->extra_diamond_value=data[2];
845 for (i=0; i<5; i++) {
846 /* 0 immediately underflowed to 999, so we use 999. example: sendydash 3, cave 02. */
847 cave->level_amoeba_time[i]=data[0]==0?999:data[0];
848 cave->level_rand[i]=data[13+i];
849 /* gate opening is checked AFTER adding to diamonds collected, so 0 here is 1000 needed */
850 cave->level_diamonds[i]=data[8+i]==0?1000:data[8+i];
851 cave->level_time[i]=data[3+i];
852 cave->level_magic_wall_time[i]=data[0];
855 for (i=0; i<4; i++) {
856 cave->random_fill[i]=bd1_import(data[0x16+i], 0x16+i);
857 cave->random_fill_probability[i]=data[0x12+i];
861 * Decode the explicit cave data
863 index=0x1A;
864 while (data[index]!=0xFF && index<remaining_bytes) {
865 int nx, ny;
866 unsigned int addr;
867 int val, n, bytes;
868 int length, direction;
870 switch (data[index]) {
871 case 0: /* LINE */
872 elem=bd1_import(data[index+1], index+1);
873 y1=data[index+2];
874 x1=data[index+3];
875 direction=data[index+4]/2; /* they are multiplied by two - 0 is up, 2 is upright, 4 is right... */
876 length=data[index+5]-1;
877 if (direction>MV_UP_LEFT) {
878 g_warning("invalid line direction %d at byte %d", direction, index);
879 direction=MV_STILL;
881 x2=x1+length*gd_dx[direction+1];
882 y2=y1+length*gd_dy[direction+1];
883 if (x1>=cave->w || y1>=cave->h || x2>=cave->w || y2 >=cave->h)
884 g_warning("invalid line coordinates %d,%d %d,%d at byte %d", x1, y1, x2, y2, index);
885 cave->objects=g_list_append(cave->objects, gd_object_new_line(GD_OBJECT_LEVEL_ALL, x1, y1, x2, y2, elem));
886 index+=6;
887 break;
888 case 1: /* OPEN RECTANGLE */
889 elem=bd1_import(data[index+1], index+1);
890 y1=data[index+2];
891 x1=data[index+3];
892 y2=y1+data[index+4]-1; /* height */
893 x2=x1+data[index+5]-1;
894 if (x1>=cave->w || y1>=cave->h || x2>=cave->w || y2 >=cave->h)
895 g_warning("invalid rectangle coordinates %d,%d %d,%d at byte %d", x1, y1, x2, y2, index);
896 cave->objects=g_list_append(cave->objects, gd_object_new_rectangle(GD_OBJECT_LEVEL_ALL, x1, y1, x2, y2, elem));
897 index+=6;
898 break;
899 case 2: /* FILLED RECTANGLE */
900 elem=bd1_import(data[index+1], index+1);
901 y1=data[index+2];
902 x1=data[index+3];
903 y2=y1+data[index+4]-1;
904 x2=x1+data[index+5]-1;
905 if (x1>=cave->w || y1>=cave->h || x2>=cave->w || y2 >=cave->h)
906 g_warning("invalid filled rectangle coordinates %d,%d %d,%d at byte %d", x1, y1, x2, y2, index);
907 cave->objects=g_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)));
908 index+=7;
909 break;
910 case 3: /* POINT */
911 elem=bd1_import(data[index+1], index+1);
912 y1=data[index+2];
913 x1=data[index+3];
914 if (x1>=cave->w || y1>=cave->h)
915 g_warning("invalid point coordinates %d,%d at byte %d", x1, y1, index);
916 cave->objects=g_list_append(cave->objects, gd_object_new_point(GD_OBJECT_LEVEL_ALL, x1, y1, elem));
917 index+=4;
918 break;
919 case 4: /* RASTER */
920 elem=bd1_import(data[index+1], index+1);
921 y1=data[index+2]; /* starting pos */
922 x1=data[index+3];
923 ny=data[index+4]-1; /* number of elements */
924 nx=data[index+5]-1;
925 dy=data[index+6]; /* displacement */
926 dx=data[index+7];
927 y2=y1+dy*ny; /* calculate rectangle */
928 x2=x1+dx*nx;
929 if (dy<1) dy=1; /* guess this has to be here, after x2,y2 calculation, because of some bugs in imported data */
930 if (dx<1) dx=1;
931 if (x1>=cave->w || y1>=cave->h || x2>=cave->w || y2>=cave->h)
932 g_warning("invalid raster coordinates %d,%d %d,%d at byte %d", x1, y1, x2, y2, index);
933 cave->objects=g_list_append(cave->objects, gd_object_new_raster(GD_OBJECT_LEVEL_ALL, x1, y1, x2, y2, dx, dy, elem));
934 index+=8;
935 break;
936 case 5:
937 /* profi boulder extension: bitmap */
938 elem=bd1_import(data[index+1], index+1);
939 bytes=data[index+2]; /* number of bytes in bitmap */
940 if (bytes>=cave->w*cave->h/8)
941 g_warning("invalid bitmap length at byte %d", index-4);
942 addr=0;
943 addr+=data[index+3]; /*msb */
944 addr+=data[index+4] << 8; /*lsb */
945 addr-=0x0850; /* this was a pointer to the cave work memory (used during game). */
946 if (addr>=cave->w*cave->h)
947 g_warning("invalid bitmap start address at byte %d", index-4);
948 x1=addr%40;
949 y1=addr/40;
950 for (i=0; i<bytes; i++) { /* for ("bytes" number of bytes) */
951 val=data[index+5+i];
952 for (n=0; n<8; n++) { /* for (8 bits in a byte) */
953 if ((val&1)!=0) /* convert to single points... */
954 cave->objects=g_list_append(cave->objects, gd_object_new_point(GD_OBJECT_LEVEL_ALL, x1, y1, elem));
955 val>>=1;
956 x1++; /* next cave pos */
957 if (x1>=cave->w) { /* maybe next line in map */
958 x1=0;
959 y1++;
963 index+=5+bytes; /* 5 description bytes and "bytes" data bytes */
964 break;
965 case 6: /* JOIN */
966 dy=data[index+3]/40;
967 dx=data[index+3]%40; /* same byte!!! */
968 cave->objects=g_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)));
969 index+=4;
970 break;
971 case 7: /* SLIME PERMEABILITY */
972 /* interesting this is set here, and not in the cave header */
973 for (i=0; i<5; i++)
974 cave->level_slime_permeability_c64[i]=data[index+1];
975 index+=2;
976 break;
977 case 9:
978 /* profi boulder extension by player: plck-like cave map. the import routine (any2gdash) inserts it here. */
979 if (cave->map!=NULL) {
980 g_critical("contains more than one PLCK map");
981 gd_cave_map_free(cave->map);
983 cave->map=gd_cave_map_new(cave, GdElement);
984 for (x=0; x<cave->w; x++) {
985 /* fill the first and the last row with steel wall. */
986 cave->map[0][x]=O_STEEL;
987 cave->map[cave->h-1][x]=O_STEEL;
989 n=0; /* number of bytes read from map */
990 for (y=1; y<cave->h-1; y++) /* the first and the last rows are not stored. */
991 for (x=0; x<cave->w; x+=2) {
992 cave->map[y][x]=plck_import_nybble[data[index+3+n] >> 4]; /* msb 4 bits */
993 cave->map[y][x+1]=plck_import_nybble[data[index+3+n] % 16]; /* lsb 4 bits */
994 n++;
996 /* the position of inbox is stored. this is to check the cave */
997 ry=data[index+1]-2;
998 rx=data[index+2];
999 /* at the start of the cave, bd scrolled to the last player placed during the drawing (setup) of the cave.
1000 i think this is why a map also stored the coordinates of the player - we can use this to check its integrity */
1001 if (rx>=cave->w || ry<0 || ry>=cave->h || cave->map[ry][rx]!=O_INBOX)
1002 g_warning ("embedded PLCK map may be corrupted, player coordinates %d,%d", rx, rx);
1003 index+=3+n;
1004 break;
1005 default:
1006 g_warning ("unknown bd2 extension no. %02x at byte %d", data[index], index);
1007 index+=1; /* skip that byte */
1010 if (data[index]!=0xFF) {
1011 g_critical("import error, cave not delimited with 0xFF");
1012 return -1;
1014 index++; /* skip delimiter */
1015 index++; /* animation byte - told the engine which objects to animate - to make game faster */
1017 /* the colors from the memory dump are appended here by any2gdash */
1018 if (format==GD_FORMAT_BD2) {
1019 /* c64 colors */
1020 cave->color0=gd_c64_color(0);
1021 cave->color1=gd_c64_color(data[index+0]&0xf);
1022 cave->color2=gd_c64_color(data[index+1]&0xf);
1023 cave->color3=gd_c64_color(data[index+2]&0x7); /* lower 3 bits only! */
1024 cave->color4=cave->color1; /* in bd2, amoeba was color1 */
1025 cave->color5=cave->color1; /* slime too */
1026 index+=3;
1027 } else {
1028 /* atari colors */
1029 cave->color1=gd_atari_color(data[index+0]);
1030 cave->color2=gd_atari_color(data[index+1]);
1031 cave->color3=gd_atari_color(data[index+2]);
1032 cave->color4=gd_atari_color(data[index+3]); /* amoeba and slime */
1033 cave->color5=gd_atari_color(data[index+3]);
1034 cave->colorb=gd_atari_color(data[index+4]); /* background and border */
1035 cave->color0=gd_atari_color(data[index+4]);
1036 index+=5;
1039 return index;
1042 /* import plck cave data into our format.
1043 length is always 512 bytes, and contains if it is an intermission cave. */
1044 static int
1045 cave_copy_from_plck(GdCave *cave, const guint8 *data, int remaining_bytes, GdCavefileFormat format)
1047 /* i don't really think that all this table is needed, but included to be complete. */
1048 /* this is for the dirt and expanding wall looks like effect. */
1049 /* it also contains the individual frames */
1050 static GdElement plck_graphic_table[]={
1051 /* 3000 */ O_UNKNOWN, O_UNKNOWN, O_UNKNOWN, O_UNKNOWN, O_UNKNOWN, O_UNKNOWN, O_UNKNOWN, O_UNKNOWN,
1052 /* 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,
1053 /* 3200 */ O_AMOEBA, O_VOODOO, O_STONE, O_DIRT, O_DIAMOND, O_STEEL, O_PLAYER, O_BRICK,
1054 /* 3300 */ O_SPACE, O_OUTBOX_OPEN, O_FIREFLY_1, O_EXPLODE_1, O_EXPLODE_2, O_EXPLODE_3, O_MAGIC_WALL, O_MAGIC_WALL,
1055 /* 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,
1056 /* 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,
1057 /* 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,
1058 /* 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,
1059 /* 3800 */ O_AMOEBA, O_AMOEBA, O_AMOEBA, O_AMOEBA, O_AMOEBA, O_AMOEBA, O_AMOEBA, O_AMOEBA,
1062 int i;
1063 int x, y;
1064 gboolean steels;
1066 g_assert(format==GD_FORMAT_PLC || format==GD_FORMAT_PLC_ATARI);
1068 /* hack: check that the "first" (really last - dlp 155) line of the cave is only steel wall. */
1069 /* check from SECOND byte; sometimes the really first byte was a $55, don't know why. that is ignored. */
1070 steels=TRUE;
1071 for (x=1; x<20; x++)
1072 if (data[x]!=0x44)
1073 steels=FALSE;
1074 if (data[0]!=0x44 && data[0]!=0x55)
1075 steels=FALSE;
1077 if (remaining_bytes<512) {
1078 g_critical("truncated plck cave data!");
1079 return -1;
1082 gd_cave_set_engine_defaults(cave, GD_ENGINE_PLCK);
1083 if (format==GD_FORMAT_PLC_ATARI)
1084 cave->scheduling=GD_SCHEDULING_BD2_PLCK_ATARI;
1085 cave->intermission=data[0x1da]!=0;
1086 if (cave->intermission) { /* set visible size for intermission */
1087 cave->x2=19;
1088 cave->y2=11;
1091 /* cave selection table, was not part of cave data, rather given in game packers.
1092 * if a new enough version of any2gdash is used, it will put information after the cave.
1093 * detect this here and act accordingly */
1094 if ((data[0x1f0]==data[0x1f1]-1) && (data[0x1f0]==0x19 || data[0x1f0]==0x0e)) {
1095 int j;
1097 /* found selection table */
1098 cave->selectable=data[0x1f0]==0x19;
1099 gd_strcpy(cave->name, " ");
1100 for (j=0; j<12; j++)
1101 cave->name[j]=data[0x1f2+j];
1102 g_strchomp(cave->name); /* remove spaces */
1103 } else
1104 /* no selection info found, let intermissions be unselectable */
1105 cave->selectable=!cave->intermission;
1107 cave->diamond_value=data[0x1be];
1108 cave->extra_diamond_value=data[0x1c0];
1109 for (i=0; i<5; i++) {
1110 /* plck doesnot really have levels, so just duplicate data five times */
1111 cave->level_amoeba_time[i]=data[0x1c4];
1112 if (cave->level_amoeba_time[i]==0) /* immediately underflowed to 999, so we use 999. example: sendydash 3, cave 02. */
1113 cave->level_amoeba_time[i]=999;
1114 cave->level_time[i]=data[0x1ba];
1115 cave->level_diamonds[i]=data[0x1bc];
1116 if (cave->level_diamonds[i]==0) /* gate opening is checked AFTER adding to diamonds collected, so 0 here is 1000 needed */
1117 cave->level_diamonds[i]=1000;
1118 cave->level_ckdelay[i]=data[0x1b8];
1119 cave->level_magic_wall_time[i]=data[0x1c6];
1120 cave->level_slime_permeability_c64[i]=slime_shift_msb(data[0x1c2]);
1123 if (format==GD_FORMAT_PLC_ATARI) {
1124 /* use atari colors */
1125 cave->colorb=gd_atari_color(0); /* border */
1126 /* indexes in data are not the same order as on c64!!! */
1127 cave->color0=gd_atari_color(data[0x1e3]); /* background */
1128 cave->color1=gd_atari_color(data[0x1db]);
1129 cave->color2=gd_atari_color(data[0x1dd]);
1130 cave->color3=gd_atari_color(data[0x1df]);
1131 /* in atari plck, slime and amoeba could not coexist in the same cave. */
1132 /* if amoeba was used, the graphics turned to green, and data at 0x1e1 was set to 0xd4. */
1133 /* if slime was used, graphics to blue, and data at 0x1e1 was set to 0x72. */
1134 /* these two colors could not be changed in the editor at all. */
1135 /* (maybe they could have been changed in a hex editor) */
1136 cave->color4=gd_atari_color(data[0x1e1]);
1137 cave->color5=gd_atari_color(data[0x1e1]);
1138 } else {
1139 /* use c64 colors */
1140 cave->colorb=gd_c64_color(data[0x1db]&0xf); /* border */
1141 cave->color0=gd_c64_color(data[0x1dd]&0xf);
1142 cave->color1=gd_c64_color(data[0x1df]&0xf);
1143 cave->color2=gd_c64_color(data[0x1e1]&0xf);
1144 cave->color3=gd_c64_color(data[0x1e3]&0x7); /* lower 3 bits only! */
1145 cave->color4=cave->color3; /* in plck, amoeba was color3 */
1146 cave->color5=cave->color3; /* same for slime */
1149 /* ... the cave is stored like a map. */
1150 cave->map=gd_cave_map_new(cave, GdElement);
1151 /* cave map looked like this. */
1152 /* two rows of steel wall ($44's), then cave description, 20 bytes (40 nybbles) for each line. */
1153 /* the bottom and top lines were not stored... originally. */
1154 /* some games write to the top line; so we import that, too. */
1155 /* also dlp 155 allowed writing to the bottom line; the first 20 $44-s now store the bottom line. */
1156 /* so the cave is essentially shifted one row down in the file: cave->map[y][x]=data[... y+1 mod height ][x] */
1157 for (y=0; y<cave->h; y++)
1158 for (x=0; x<cave->w; x+=2) {
1159 cave->map[y][x]=plck_import_nybble[data[((y+1)%cave->h)*20 + x/2] >> 4]; /* msb 4 bits: we do not check index ranges, as >>4 and %16 will result in 0..15 */
1160 cave->map[y][x+1]=plck_import_nybble[data[((y+1)%cave->h)*20 + x/2] % 16]; /* lsb 4 bits */
1162 /* FOR NOW, WE DO NOT IMPORT THE BOTTOM BORDER */
1163 for (x=0; x<cave->w; x++)
1164 cave->map[cave->h-1][x]=O_STEEL;
1166 if (steels && data[0]==0x55)
1167 cave->map[cave->h-1][0]=cave->map[cave->h-1][1]=O_STEEL;
1170 /* check for diego-effects */
1171 /* c64 magic values (byte sequences) 0x20 0x90 0x46, also 0xa9 0x1c 0x85 */
1172 if ((data[0x1e5]==0x20 && data[0x1e6]==0x90 && data[0x1e7]==0x46) || (data[0x1e5]==0xa9 && data[0x1e6]==0x1c && data[0x1e7]==0x85)) {
1173 /* diego effects enabled. */
1174 cave->stone_bouncing_effect=bd1_import(data[0x1ea], 0x1ea);
1175 cave->diamond_falling_effect=bd1_import(data[0x1eb], 0x1eb);
1176 /* explosions: 0x1e was explosion 5, if this is set to default, we also do not read it,
1177 as in our engine this would cause an O_EXPLODE_5 to stay there. */
1178 if (data[0x1ec]!=0x1e)
1179 cave->explosion_effect=bd1_import(data[0x1ec], 0x1ec);
1180 /* pointer to element graphic.
1181 two bytes/column (one element), that is data[xxx]%16/2.
1182 also there are 16bytes/row.
1183 that is, 0x44=stone, upper left character. 0x45=upper right, 0x54=lower right, 0x55=lower right.
1184 so high nybble must be shifted right twice -> data[xxx]/16*4. */
1185 cave->dirt_looks_like=plck_graphic_table[(data[0x1ed]/16)*4 + (data[0x1ed]%16)/2];
1186 cave->expanding_wall_looks_like=plck_graphic_table[(data[0x1ee]/16)*4 + (data[0x1ee]%16)/2];
1187 for (i=0; i<5; i++)
1188 cave->level_amoeba_threshold[i]=data[0x1ef];
1191 return 512;
1194 /* no one's delight boulder dash
1195 essentially: rle compressed plck maps. */
1196 static int
1197 cave_copy_from_dlb(GdCave *cave, const guint8 *data, int remaining_bytes)
1199 guint8 decomp[512];
1200 enum {
1201 START, /* initial state */
1202 SEPARATOR, /* got a separator */
1203 RLE, /* after a separator, got the byte to duplicate */
1204 NORMAL /* normal, copy bytes till separator */
1205 } state;
1206 int pos, cavepos, i, x, y;
1207 guint8 byte, separator;
1209 gd_error_set_context(cave->name);
1210 gd_cave_set_engine_defaults(cave, GD_ENGINE_PLCK); /* essentially the plck engine */
1212 for (i=0; i<5; i++) {
1213 /* does not really have levels, so just duplicate data five times */
1214 cave->level_time[i]=data[1];
1215 cave->level_diamonds[i]=data[2];
1216 if (cave->level_diamonds[i]==0) /* gate opening is checked AFTER adding to diamonds collected, so 0 here is 1000 needed */
1217 cave->level_diamonds[i]=1000;
1218 cave->level_ckdelay[i]=data[0];
1219 cave->level_amoeba_time[i]=data[6]; if (cave->level_amoeba_time[i]==0) /* 0 immediately underflowed to 999, so we use 999. example: sendydash 3, cave 02. */
1220 cave->level_amoeba_time[i]=999;
1221 cave->level_magic_wall_time[i]=data[7];
1222 cave->level_slime_permeability_c64[i]=slime_shift_msb(data[5]);
1224 cave->diamond_value=data[3];
1225 cave->extra_diamond_value=data[4];
1227 /* then 5 color bytes follow */
1228 cave->colorb=gd_c64_color(data[8]&0xf); /* border */
1229 cave->color0=gd_c64_color(data[9]&0xf);
1230 cave->color1=gd_c64_color(data[10]&0xf);
1231 cave->color2=gd_c64_color(data[11]&0xf);
1232 cave->color3=gd_c64_color(data[12]&0x7); /* lower 3 bits only! */
1233 cave->color4=cave->color3; /* in plck, amoeba was color3 */
1234 cave->color5=cave->color3; /* same for slime */
1236 /* cave map */
1237 pos=13; /* those 13 bytes were the cave values above */
1238 cavepos=0;
1239 byte=0; /* just to get rid of compiler warning */
1240 separator=0; /* just to get rid of compiler warning */
1241 /* employ a state machine. */
1242 state=START;
1243 while (cavepos<400 && pos<remaining_bytes) {
1244 switch (state) {
1245 case START:
1246 /* first byte is a separator. remember it */
1247 separator=data[pos];
1248 /* after the first separator, no rle data, just copy. */
1249 state=NORMAL;
1250 break;
1251 case SEPARATOR:
1252 /* we had a separator. remember this byte, as this will be duplicated (or more) */
1253 byte=data[pos];
1254 state=RLE;
1255 break;
1256 case RLE:
1257 /* we had the first byte, duplicate this n times. */
1258 if (data[pos]==0xff) {
1259 /* if it is a 0xff, we will have another byte, which is also a length specifier. */
1260 /* and for this one, duplicate only 254 times */
1261 if (cavepos+254>400) {
1262 g_critical("DLB import error: RLE data overflows buffer");
1263 return -1;
1265 for (i=0; i<254; i++)
1266 decomp[cavepos++]=byte;
1267 } else {
1268 /* if not 0xff, duplicate n times and back to copy mode */
1269 if (cavepos+data[pos]>400) {
1270 g_critical("DLB import error: RLE data overflows buffer");
1271 return -1;
1273 for (i=0; i<data[pos]; i++)
1274 decomp[cavepos++]=byte;
1275 state=NORMAL;
1277 break;
1278 case NORMAL:
1279 /* bytes duplicated; now only copy the remaining, till the next separator. */
1280 if (data[pos]==separator)
1281 state=SEPARATOR;
1282 else
1283 decomp[cavepos++]=data[pos]; /* copy this byte and state is still NORMAL */
1284 break;
1286 pos++;
1288 if (cavepos!=400) {
1289 g_critical("DLB import error: RLE processing, cave length %d, should be 400", cavepos);
1290 return -1;
1293 /* process uncompressed map */
1294 cave->map=gd_cave_map_new (cave, GdElement);
1295 for (x=0; x<cave->w; x++) {
1296 /* fill the first and the last row with steel wall. */
1297 cave->map[0][x]=O_STEEL;
1298 cave->map[cave->h-1][x]=O_STEEL;
1300 for (y=1; y<cave->h-1; y++)
1301 for (x=0; x<cave->w; x+=2) {
1302 cave->map[y][x]=plck_import_nybble[decomp[((y-1)*cave->w+x)/2] >> 4]; /* msb 4 bits */
1303 cave->map[y][x+1]=plck_import_nybble[decomp[((y-1)*cave->w+x)/2] % 16]; /* lsb 4 bits */
1306 /* return number of bytes read from buffer */
1307 return pos;
1312 /* import plck cave data into our format. */
1313 static int
1314 cave_copy_from_1stb(GdCave *cave, const guint8 *data, int remaining_bytes)
1316 int i;
1317 int x, y;
1319 if (remaining_bytes<1024) {
1320 g_critical("truncated 1stb cave data!");
1321 return -1;
1324 gd_cave_set_engine_defaults(cave, GD_ENGINE_1STB);
1326 /* copy name */
1327 gd_strcpy(cave->name, " ");
1328 for (i=0; i<14; i++) {
1329 int c=data[0x3a0+i];
1331 /* import cave name; a conversion table is used for each character */
1332 if (c<0x40)
1333 c=gd_bd_internal_chars[c];
1334 else if (c==0x74)
1335 c=' ';
1336 else if (c==0x76)
1337 c='?';
1338 else
1339 c=' '; /* don't know this, so change to space */
1340 if (i>0)
1341 c=g_ascii_tolower(c);
1343 cave->name[i]=c;
1345 g_strchomp(cave->name);
1346 gd_error_set_context(cave->name);
1348 cave->intermission=data[0x389]!=0;
1349 /* if it is intermission but not scrollable */
1350 if (cave->intermission && !data[0x38c]) {
1351 cave->x2=19;
1352 cave->y2=11;
1355 cave->diamond_value=100*data[0x379] + 10*data[0x379+1] + data[0x379+2];
1356 cave->extra_diamond_value=100*data[0x376] + 10*data[0x376+1] + data[0x376+2];
1357 for (i=0; i < 5; i++) {
1358 /* plck doesnot really have levels, so just duplicate data five times */
1359 cave->level_time[i]=100*data[0x370] + 10*data[0x370+1] + data[0x370+2];
1360 if (cave->level_time[i]==0) /* same as gate opening after 0 diamonds */
1361 cave->level_time[i]=1000;
1362 cave->level_diamonds[i]=100*data[0x373] + 10*data[0x373+1] + data[0x373+2];
1363 if (cave->level_diamonds[i]==0) /* gate opening is checked AFTER adding to diamonds collected, so 0 here is 1000 (!) needed */
1364 cave->level_diamonds[i]=1000;
1365 cave->level_ckdelay[i]=data[0x38a];
1366 cave->level_amoeba_time[i]=256*(int)data[0x37c]+data[0x37d];
1367 if (cave->level_amoeba_time[i]==0) /* 0 immediately underflowed to 999, so we use 999. example: sendydash 3, cave 02. */
1368 cave->level_amoeba_time[i]=999;
1369 cave->level_magic_wall_time[i]=256*(int)data[0x37e]+data[0x37f];
1370 cave->level_slime_permeability_c64[i]=data[0x38b];
1371 cave->level_bonus_time[i]=data[0x392];
1372 cave->level_penalty_time[i]=data[0x393];
1373 cave->level_amoeba_threshold[i]=256*(int)data[0x390] + data[0x390+1];
1375 /* also has no random data... */
1377 cave->colorb=gd_c64_color(data[0x384]&0xf); /* border */
1378 cave->color0=gd_c64_color(data[0x385]&0xf);
1379 cave->color1=gd_c64_color(data[0x386]&0xf);
1380 cave->color2=gd_c64_color(data[0x387]&0xf);
1381 cave->color3=gd_c64_color(data[0x388]&0x7); /* lower 3 bits only! */
1382 cave->color4=cave->color1;
1383 cave->color5=cave->color1;
1385 cave->amoeba_growth_prob=(4.0*1E6/(data[0x382]+1))+0.5; /* probabilities store *1M */
1386 if (cave->amoeba_growth_prob>1000000)
1387 cave->amoeba_growth_prob=1000000;
1388 cave->amoeba_fast_growth_prob=(4.0*1E6/(data[0x383]+1))+0.5;
1389 if (cave->amoeba_fast_growth_prob>1000000)
1390 cave->amoeba_fast_growth_prob=1000000;
1392 if (data[0x380]!=0)
1393 cave->creatures_direction_auto_change_time=data[0x381];
1394 else
1395 cave->diagonal_movements=data[0x381]!=0;
1397 /* ... the cave is stored like a map. */
1398 cave->map=gd_cave_map_new (cave, GdElement);
1399 for (y=0; y < cave->h; y++)
1400 for (x=0; x < cave->w; x++)
1401 cave->map[y][x]=firstboulder_import(data[y*40+x], y*40+x);
1403 cave->magic_wall_sound=data[0x38d]==0xf1;
1404 /* 2d was a normal switch, 2e a changed one. */
1405 cave->creatures_backwards=data[0x38f]==0x2d;
1406 /* 2e horizontal, 2f vertical. */
1407 cave->expanding_wall_changed=data[0x38e]==0x2f;
1409 cave->biter_delay_frame=data[0x394];
1410 cave->magic_wall_stops_amoeba=data[0x395]==0; /* negated!! */
1411 cave->bomb_explosion_effect=firstboulder_import(data[0x396], 0x396);
1412 cave->explosion_effect=firstboulder_import(data[0x397], 0x397);
1413 cave->stone_bouncing_effect=firstboulder_import(data[0x398], 0x398);
1414 cave->diamond_birth_effect=firstboulder_import(data[0x399], 0x399);
1415 cave->magic_diamond_to=firstboulder_import(data[0x39a], 0x39a);
1417 cave->bladder_converts_by=firstboulder_import(data[0x39b], 0x39b);
1418 cave->diamond_falling_effect=firstboulder_import(data[0x39c], 0x39c);
1419 cave->biter_eat=firstboulder_import(data[0x39d], 0x39d);
1420 cave->slime_eats_1=firstboulder_import(data[0x39e], 0x39e);
1421 cave->slime_converts_1=firstboulder_import(data[0x39e]+3, 0x39e);
1422 cave->slime_eats_2=firstboulder_import(data[0x39f], 0x39f);
1423 cave->slime_converts_2=firstboulder_import(data[0x39f]+3, 0x39f);
1424 cave->magic_diamond_to=firstboulder_import(data[0x39a], 0x39a);
1426 /* length is always 1024 bytes */
1427 return 1024;
1431 /* crazy dream 7 */
1432 static int
1433 cave_copy_from_crdr_7(GdCave *cave, const guint8 *data, int remaining_bytes)
1435 int i, index;
1436 guint8 checksum;
1438 /* if we have name, convert */
1439 gd_strcpy(cave->name, " ");
1440 for (i=0; i<14; i++) {
1441 int c=data[i];
1443 /* import cave name; a conversion table is used for each character */
1444 if (c<0x40)
1445 c=gd_bd_internal_chars[c];
1446 else if (c==0x74)
1447 c=' ';
1448 else if (c==0x76)
1449 c='?';
1450 else
1451 c=' ';
1452 if (i>0)
1453 c=g_ascii_tolower(c);
1455 cave->name[i]=c;
1457 g_strchomp(cave->name); /* remove trailing and leading spaces */
1458 gd_error_set_context(cave->name);
1460 cave->selectable=data[14]!=0;
1462 /* jump 15 bytes, 14 was the name and 15 selectability */
1463 data+=15;
1464 if (memcmp((char *)data+0x30, "V4\0020", 4)!=0)
1465 g_warning("unknown crdr version %c%c%c%c", data[0x30], data[0x31], data[0x32], data[0x33]);
1467 gd_cave_set_engine_defaults(cave, GD_ENGINE_CRDR7);
1469 for (i=0; i<5; i++) {
1470 cave->level_time[i]=(int)data[0x0]*100 + data[0x1]*10 + data[0x2];
1471 if (cave->level_time[i]==0) /* same as gate opening after 0 diamonds */
1472 cave->level_time[i]=1000;
1473 cave->level_diamonds[i]=(int)data[0x3]*100+data[0x4]*10+data[0x5];
1474 if (cave->level_diamonds[i]==0) /* gate opening is checked AFTER adding to diamonds collected, so 0 here is 1000 (!) needed */
1475 cave->level_diamonds[i]=1000;
1476 cave->level_ckdelay[i]=data[0x1A];
1477 cave->level_rand[i]=data[0x40];
1478 cave->level_amoeba_time[i]=(int)data[0xC] * 256 + data[0xD];
1479 if (cave->level_amoeba_time[i]==0) /* 0 immediately underflowed to 999, so we use 999. example: sendydash 3, cave 02. */
1480 cave->level_amoeba_time[i]=999;
1481 cave->level_magic_wall_time[i]=(int)data[0xE] * 256 + data[0xF];
1482 cave->level_slime_permeability_c64[i]=data[0x1B];
1483 cave->level_bonus_time[i]=data[0x22];
1484 cave->level_penalty_time[i]=data[0x23];
1485 cave->level_bonus_time[i]=data[0x22];
1486 cave->level_penalty_time[i]=data[0x23];
1487 cave->level_amoeba_threshold[i]=256*(int)data[0x20]+data[0x21];
1489 cave->extra_diamond_value=(int)data[0x6] * 100 + data[0x7] * 10 + data[0x8];
1490 cave->diamond_value=(int)data[0x9] * 100 + data[0xA] * 10 + data[0xB];
1491 if (data[0x10])
1492 cave->creatures_direction_auto_change_time=data[0x11];
1493 cave->colorb=gd_c64_color(data[0x14]&0xf); /* border */
1494 cave->color0=gd_c64_color(data[0x15]&0xf);
1495 cave->color1=gd_c64_color(data[0x16]&0xf);
1496 cave->color2=gd_c64_color(data[0x17]&0xf);
1497 cave->color3=gd_c64_color(data[0x18]&0x7); /* lower 3 bits only! */
1498 cave->color4=cave->color3;
1499 cave->color5=cave->color1;
1500 cave->intermission=data[0x19]!=0;
1501 /* if it is intermission but not scrollable */
1502 if (cave->intermission && !data[0x1c]) {
1503 cave->x2=19;
1504 cave->y2=11;
1507 /* AMOEBA in crazy dash 8:
1508 jsr $2500 ; generate true random
1509 and $94 ; binary and the current "probability"
1510 cmp #$04 ; compare to 4
1511 bcs out ; jump out (do not expand) if carry set, ie. result was less than 4.
1513 prob values can be like num=3, 7, 15, 31, 63, ... n lsb bits count.
1514 0..3>=4? 0..7>=4? 0..15>=4? and similar.
1515 this way, probability of growing is 4/(num+1)
1517 cave->amoeba_growth_prob=(4.0*1E6/(data[0x12]+1))+0.5; /* probabilities store *1M */
1518 if (cave->amoeba_growth_prob>1000000)
1519 cave->amoeba_growth_prob=1000000;
1520 cave->amoeba_fast_growth_prob=(4.0*1E6/(data[0x13]+1))+0.5;
1521 if (cave->amoeba_fast_growth_prob>1000000)
1522 cave->amoeba_fast_growth_prob=1000000;
1523 /* expanding wall direction change - 2e horizontal, 2f vertical */
1524 cave->expanding_wall_changed=data[0x1e]==0x2f;
1525 /* 2c was a normal switch, 2d a changed one. */
1526 cave->creatures_backwards=data[0x1f]==0x2d;
1527 cave->biter_delay_frame=data[0x24];
1528 cave->magic_wall_stops_amoeba=data[0x25]==0; /* negated!! */
1529 cave->bomb_explosion_effect=crazydream_import_table[data[0x26]];
1530 cave->explosion_effect=crazydream_import_table[data[0x27]];
1531 cave->stone_bouncing_effect=crazydream_import_table[data[0x28]];
1532 cave->diamond_birth_effect=crazydream_import_table[data[0x29]];
1533 cave->magic_diamond_to=crazydream_import_table[data[0x2a]];
1535 cave->bladder_converts_by=crazydream_import_table[data[0x2b]];
1536 cave->diamond_falling_effect=crazydream_import_table[data[0x2c]];
1537 cave->biter_eat=crazydream_import_table[data[0x2d]];
1538 cave->slime_eats_1=crazydream_import_table[data[0x2e]];
1539 cave->slime_converts_1=crazydream_import_table[data[0x2e]+3];
1540 cave->slime_eats_2=crazydream_import_table[data[0x2f]];
1541 cave->slime_converts_2=crazydream_import_table[data[0x2f]+3];
1543 cave->diagonal_movements=(data[0x34]&1)!=0;
1544 cave->gravity_change_time=data[0x35];
1545 cave->pneumatic_hammer_frame=data[0x36];
1546 cave->hammered_wall_reappear_frame=data[0x37];
1547 cave->hammered_walls_reappear=data[0x3f]!=0;
1549 acid in crazy dream 8:
1550 jsr $2500 ; true random
1551 cmp $03a8 ; compare to ratio
1552 bcs out ; if it was smaller, forget it for now.
1554 ie. random<=ratio, then acid grows.
1556 cave->acid_spread_ratio=data[0x38]/255.0*1E6+0.5; /* 1e6, probabilities are stored as int */
1557 cave->acid_eats_this=crazydream_import_table[data[0x39]];
1558 switch(data[0x3a]&3) {
1559 case 0: cave->gravity=MV_UP; break;
1560 case 1: cave->gravity=MV_DOWN; break;
1561 case 2: cave->gravity=MV_LEFT; break;
1562 case 3: cave->gravity=MV_RIGHT; break;
1564 cave->snap_element=((data[0x3a]&4)!=0)?O_EXPLODE_1:O_SPACE;
1565 /* we do not know the values for these, so do not import */
1566 // cave->dirt_looks_like... data[0x3c]
1567 // cave->expanding_wall_looks_like... data[0x3b]
1568 for (i=0; i<4; i++) {
1569 cave->random_fill[i]=crazydream_import_table[data[0x41+i]];
1570 cave->random_fill_probability[i]=data[0x45+i];
1573 data+=0x49;
1574 index=0;
1575 while (data[index]!=0xff) {
1576 GdElement elem;
1577 int x1, y1, x2, y2, dx, dy;
1578 int nx, ny;
1579 int length, direction;
1580 static int cx1, cy1, cw, ch; /* for copy&paste; copy&paste are different objects, static=ugly solution :) */
1582 switch(data[index]) {
1583 case 1: /* point */
1584 elem=crazydream_import_table[data[index+1]];
1585 x1=data[index+2];
1586 y1=data[index+3];
1587 if (x1>=cave->w || y1>=cave->h)
1588 g_warning("invalid point coordinates %d,%d at byte %d", x1, y1, index);
1589 cave->objects=g_list_append(cave->objects, gd_object_new_point(GD_OBJECT_LEVEL_ALL, x1, y1, elem));
1590 index+=4;
1591 break;
1592 case 2: /* rectangle */
1593 elem=crazydream_import_table[data[index+1]];
1594 x1=data[index+2];
1595 y1=data[index+3];
1596 x2=x1+data[index+4]-1;
1597 y2=y1+data[index+5]-1; /* height */
1598 if (x1>=cave->w || y1>=cave->h || x2>=cave->w || y2>=cave->h)
1599 g_warning("invalid rectangle coordinates %d,%d %d,%d at byte %d", x1, y1, x2, y2, index);
1600 cave->objects=g_list_append(cave->objects, gd_object_new_rectangle(GD_OBJECT_LEVEL_ALL, x1, y1, x2, y2, elem));
1601 index+=6;
1602 break;
1603 case 3: /* fillrect */
1604 x1=data[index+2];
1605 y1=data[index+3];
1606 x2=x1+data[index+4]-1;
1607 y2=y1+data[index+5]-1;
1608 if (x1>=cave->w || y1>=cave->h || x2>=cave->w || y2>=cave->h)
1609 g_warning("invalid filled rectangle coordinates %d,%d %d,%d at byte %d", x1, y1, x2, y2, index);
1610 /* border and inside of fill is the same element. */
1611 cave->objects=g_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]]));
1612 index+=6;
1613 break;
1615 case 4: /* line */
1616 elem=crazydream_import_table[data[index+1]];
1617 if (elem==O_UNKNOWN)
1618 g_warning("unknown element at %d: %x", index+1, data[index+1]);
1619 x1=data[index+2];
1620 y1=data[index+3];
1621 length=data[index+4];
1623 direction=data[index+5];
1624 nx=((signed)direction-128)%40;
1625 ny=((signed)direction-128)/40;
1626 x2=x1+(length-1)*nx;
1627 y2=y1+(length-1)*ny;
1628 /* if either is bigger than one, we cannot treat this as a line. create points instead */
1629 if (ABS(nx)>=2 || ABS(ny>=2)) {
1630 for (i=0; i<length; i++) {
1631 cave->objects=g_list_append(cave->objects, gd_object_new_point(GD_OBJECT_LEVEL_ALL, x1, y1, elem));
1632 x1+=nx;
1633 y1+=ny;
1635 } else {
1636 /* this is a normal line, and will be appended. only do the checking here */
1637 if (x1>=cave->w || y1>=cave->h || x2>=cave->w || y2>=cave->h)
1638 g_warning("invalid line coordinates %d,%d %d,%d at byte %d", x1, y1, x2, y2, index-5);
1639 cave->objects=g_list_append(cave->objects, gd_object_new_line(GD_OBJECT_LEVEL_ALL, x1, y1, x2, y2, elem));
1642 index+=6;
1643 break;
1644 case 6: /* copy */
1645 cx1=data[index+1];
1646 cy1=data[index+2];
1647 cw=data[index+3];
1648 ch=data[index+4];
1649 if (cx1>=cave->w || cy1>=cave->h || cx1+cw>cave->w || cy1+ch>cave->h)
1650 g_warning("invalid copy coordinates %d,%d or size %d,%d at byte %d", cx1, cy1, cw, ch, index);
1651 index+=5;
1652 break;
1653 case 7: /* paste */
1654 x1=cx1;
1655 y1=cy1;
1656 x2=cx1+cw-1; /* original stored width and height, we store the coordinates of the source area */
1657 y2=cy1+ch-1;
1658 dx=data[index+1]; /* new pos */
1659 dy=data[index+2];
1660 if (dx>=cave->w || dy>=cave->h || dx+cw>cave->w || dy+ch>cave->h)
1661 g_warning("invalid paste coordinates %d,%d at byte %d", dx, dy, index);
1662 cave->objects=g_list_append(cave->objects, gd_object_new_copy_paste(GD_OBJECT_LEVEL_ALL, x1, y1, x2, y2, dx, dy, FALSE, FALSE));
1663 index+=3;
1664 break;
1665 case 11: /* raster */
1666 elem=crazydream_import_table[data[index+1]];
1667 x1=data[index+2];
1668 y1=data[index+3];
1669 dx=data[index+4];
1670 dy=data[index+5];
1671 nx=data[index+6]-1;
1672 ny=data[index+7]-1;
1673 x2=x1+dx*nx; /* calculate rectangle we use */
1674 y2=y1+dy*ny;
1675 if (dx<1) dx=1;
1676 if (dy<1) dy=1;
1677 if (x1>=cave->w || y1>=cave->h || x2>=cave->w || y2>=cave->h)
1678 g_warning("invalid raster coordinates %d,%d %d,%d at byte %d", x1, y1, x2, y2, index);
1679 cave->objects=g_list_append(cave->objects, gd_object_new_raster(GD_OBJECT_LEVEL_ALL, x1, y1, x2, y2, dx, dy, elem));
1680 index+=8;
1681 break;
1682 default:
1683 g_warning ("unknown crdr extension no. %02x at byte %d", data[index], index);
1684 index+=1; /* skip that byte */
1685 break;
1688 index++; /* skip $ff */
1690 /* crazy dream 7 hack */
1691 checksum=0;
1692 for (i=0; i<0x3b0; i++)
1693 checksum=checksum^data[i];
1694 if (g_str_equal(cave->name, "Crazy maze") && checksum==195)
1695 cave->skeletons_needed_for_pot=0;
1697 return 15+0x49+index;
1700 static void
1701 crazy_dream_9_add_specials(GdCave *cave, const guint8 *buf, const int length)
1703 guint8 checksum;
1704 int i;
1706 /* crazy dream 9 hack */
1707 checksum=0;
1708 for (i=0; i<length; i++)
1709 checksum=checksum^buf[i];
1711 /* check cave name and the checksum. both are hardcoded here */
1712 if (g_str_equal(cave->name, "Rockfall") && checksum==134) {
1713 GdElement rand[4]={O_DIAMOND, O_STONE, O_ACID, O_DIRT};
1714 gint32 prob[4]={37, 32, 2, 0};
1715 gint32 seeds[5]={-1, -1, -1, -1, -1};
1716 cave->objects=g_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));
1719 if (g_str_equal(cave->name, "Roll dice now!") && checksum==235) {
1720 GdElement rand[4]={O_STONE, O_BUTTER_3, O_DIRT, O_DIRT};
1721 gint32 prob[4]={0x18, 0x08, 0, 0};
1722 gint32 seeds[5]={-1, -1, -1, -1, -1};
1723 cave->objects=g_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));
1726 if (g_str_equal(cave->name, "Random maze") && checksum==24) {
1727 gint32 seeds[5]={-1, -1, -1, -1, -1};
1728 cave->objects=g_list_append(cave->objects, gd_object_new_maze(GD_OBJECT_LEVEL_ALL, 1, 4, 35, 20, 1, 1, O_NONE, O_DIRT, 50, seeds));
1731 if (g_str_equal(cave->name, "Metamorphosis") && checksum==53) {
1732 gint32 seeds[5]={-1, -1, -1, -1, -1};
1733 GdElement rand[4]={O_STONE, O_DIRT, O_DIRT, O_DIRT};
1734 gint32 prob[4]={0x18, 0, 0, 0};
1735 cave->objects=g_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));
1736 cave->objects=g_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));
1737 cave->creatures_backwards=TRUE; /* for some reason, this level worked like that */
1740 if (g_str_equal(cave->name, "All the way") && checksum==33) {
1741 gint32 seeds[5]={-1, -1, -1, -1, -1};
1742 cave->objects=g_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));
1743 /* a point which "breaks" the unicursal maze, making it one very long path */
1744 cave->objects=g_list_append(cave->objects, gd_object_new_point(GD_OBJECT_LEVEL_ALL, 35, 18, O_BRICK));
1750 /* crazy light contruction kit */
1751 static int
1752 cave_copy_from_crli(GdCave *cave, const guint8 *data, int remaining_bytes)
1754 guint8 uncompressed[1024];
1755 int datapos, cavepos, i, x, y;
1756 gboolean cavefile;
1757 const char *versions[]={"V2.2", "V2.6", "V3.0"};
1758 enum {
1759 none,
1760 V2_2, /* XXX whats the difference between 2.2 and 2.6?*/
1761 V2_6,
1762 V3_0
1763 } version=none;
1764 GdElement (*import) (guint8 c, int i)=NULL; /* import function */
1766 gd_cave_set_engine_defaults(cave, GD_ENGINE_CRLI);
1768 /* detect if this is a cavefile */
1769 if (data[0]==0 && data[1]==0xc4 && data[2] == 'D' && data[3] == 'L' && data[4] == 'P') {
1770 datapos=5; /* cavefile, skipping 0x00 0xc4 D L P */
1771 cavefile=TRUE;
1773 else {
1774 datapos=15; /* converted from snapshot, skip "selectable" and 14byte name */
1775 cavefile=FALSE;
1778 /* if we have name, convert */
1779 if (!cavefile) {
1780 gd_strcpy(cave->name, " ");
1781 for (i=0; i<14; i++) {
1782 int c=data[i+1];
1784 /* import cave name; a conversion table is used for each character */
1785 if (c<0x40)
1786 c=gd_bd_internal_chars[c];
1787 else if (c==0x74)
1788 c=' ';
1789 else if (c==0x76)
1790 c='?';
1791 else
1792 c=' ';
1793 if (i>0)
1794 c=g_ascii_tolower(c);
1796 cave->name[i]=c;
1798 g_strchomp(cave->name); /* remove trailing and leading spaces */
1800 gd_error_set_context(cave->name);
1802 /* uncompress rle data */
1803 cavepos=0;
1804 while (cavepos<0x3b0) { /* <- loop until the uncompressed reaches its size */
1805 if (datapos>=remaining_bytes) {
1806 g_critical("truncated crli cave data");
1807 return -1;
1809 if (data[datapos] == 0xbf) { /* magic value 0xbf is the escape byte */
1810 if (datapos+2>=remaining_bytes) {
1811 g_critical("truncated crli cave data");
1812 return -1;
1814 if(data[datapos+2]+datapos>=sizeof(uncompressed)) {
1815 /* we would run out of buffer, this must be some error */
1816 g_critical("invalid crli cave data - RLE length value is too big");
1817 return -1;
1819 /* 0xbf, number, byte to dup */
1820 for (i=0; i<data[datapos+2]; i++)
1821 uncompressed[cavepos++]=data[datapos+1];
1823 datapos+=3;
1825 else
1826 uncompressed[cavepos++]=data[datapos++];
1829 /* check crli version */
1830 for (i=0; i<G_N_ELEMENTS(versions); i++)
1831 if (memcmp((char *)uncompressed+0x3a0, versions[i], 4)==0)
1832 version=i+1;
1834 /* v3.0 has falling wall and box, and no ghost. */
1835 import= version>=V3_0 ? crazylight_import:firstboulder_import;
1837 if (version==none) {
1838 g_warning("unknown crli version %c%c%c%c", uncompressed[0x3a0], uncompressed[0x3a1], uncompressed[0x3a2], uncompressed[0x3a3]);
1839 import=crazylight_import;
1842 /* process map */
1843 cave->map=gd_cave_map_new (cave, GdElement);
1844 for (y=0; y<cave->h; y++)
1845 for (x=0; x<cave->w; x++) {
1846 int index=y*cave->w+x;
1848 cave->map[y][x]=import(uncompressed[index], index);
1851 /* crli has no levels */
1852 for (i=0; i<5; i++) {
1853 cave->level_time[i]=(int)uncompressed[0x370] * 100 + uncompressed[0x371] * 10 + uncompressed[0x372];
1854 if (cave->level_time[i]==0) /* same as gate opening after 0 diamonds */
1855 cave->level_time[i]=1000;
1856 cave->level_diamonds[i]=(int)uncompressed[0x373] * 100 + uncompressed[0x374] * 10 + uncompressed[0x375];
1857 if (cave->level_diamonds[i]==0) /* gate opening is checked AFTER adding to diamonds collected, so 0 here is 1000 (!) needed */
1858 cave->level_diamonds[i]=1000;
1859 cave->level_ckdelay[i]=uncompressed[0x38A];
1860 cave->level_amoeba_time[i]=(int)uncompressed[0x37C] * 256 + uncompressed[0x37D];
1861 if (cave->level_amoeba_time[i]==0) /* 0 immediately underflowed to 999, so we use 999. example: sendydash 3, cave 02. */
1862 cave->level_amoeba_time[i]=999;
1863 cave->level_magic_wall_time[i]=(int)uncompressed[0x37E] * 256 + uncompressed[0x37F];
1864 cave->level_slime_permeability_c64[i]=uncompressed[0x38B];
1865 cave->level_bonus_time[i]=uncompressed[0x392];
1866 cave->level_penalty_time[i]=uncompressed[0x393];
1867 cave->level_amoeba_threshold[i]=256*(int)uncompressed[0x390]+uncompressed[0x390+1];
1869 cave->extra_diamond_value=(int)uncompressed[0x376] * 100 + uncompressed[0x377] * 10 + uncompressed[0x378];
1870 cave->diamond_value=(int)uncompressed[0x379] * 100 + uncompressed[0x37A] * 10 + uncompressed[0x37B];
1871 if (uncompressed[0x380])
1872 cave->creatures_direction_auto_change_time=uncompressed[0x381];
1873 cave->colorb=gd_c64_color(uncompressed[0x384]&0xf); /* border */
1874 cave->color0=gd_c64_color(uncompressed[0x385]&0xf);
1875 cave->color1=gd_c64_color(uncompressed[0x386]&0xf);
1876 cave->color2=gd_c64_color(uncompressed[0x387]&0xf);
1877 cave->color3=gd_c64_color(uncompressed[0x388]&0x7); /* lower 3 bits only! */
1878 cave->color4=cave->color3;
1879 cave->color5=cave->color1;
1880 cave->intermission=uncompressed[0x389]!=0;
1881 /* if it is intermission but not scrollable */
1882 if (cave->intermission && !uncompressed[0x38c]) {
1883 cave->x2=19;
1884 cave->y2=11;
1887 /* AMOEBA in crazy dash 8:
1888 jsr $2500 ; generate true random
1889 and $94 ; binary and the current "probability"
1890 cmp #$04 ; compare to 4
1891 bcs out ; jump out (do not expand) if carry set, ie. result was less than 4.
1893 prob values can be like num=3, 7, 15, 31, 63, ... n lsb bits count.
1894 0..3>=4? 0..7>=4? 0..15>=4? and similar.
1895 this way, probability of growing is 4/(num+1)
1897 cave->amoeba_growth_prob=(1E6*4.0/(uncompressed[0x382]+1))+0.5; /* probabilities store *1M */
1898 if (cave->amoeba_growth_prob>1000000)
1899 cave->amoeba_growth_prob=1000000;
1900 cave->amoeba_fast_growth_prob=(1E6*4.0/(uncompressed[0x383]+1))+0.5;
1901 if (cave->amoeba_fast_growth_prob>1000000)
1902 cave->amoeba_fast_growth_prob=1000000;
1903 /* 2c was a normal switch, 2d a changed one. */
1904 cave->creatures_backwards=uncompressed[0x38f]==0x2d;
1905 cave->magic_wall_sound=uncompressed[0x38d]==0xf1;
1906 /* 2e horizontal, 2f vertical. we implement this by changing them */
1907 if (uncompressed[0x38e]==0x2f)
1908 for (y=0; y<cave->h; y++)
1909 for (x=0; x<cave->w; x++) {
1910 if (cave->map[y][x]==O_H_EXPANDING_WALL)
1911 cave->map[y][x]=O_V_EXPANDING_WALL;
1913 cave->biter_delay_frame=uncompressed[0x394];
1914 cave->magic_wall_stops_amoeba=uncompressed[0x395]==0; /* negated!! */
1915 cave->bomb_explosion_effect=import(uncompressed[0x396], 0x396);
1916 cave->explosion_effect=import(uncompressed[0x397], 0x397);
1917 cave->stone_bouncing_effect=import(uncompressed[0x398], 0x398);
1918 cave->diamond_birth_effect=import(uncompressed[0x399], 0x399);
1919 cave->magic_diamond_to=import(uncompressed[0x39a], 0x39a);
1921 cave->bladder_converts_by=import(uncompressed[0x39b], 0x39b);
1922 cave->diamond_falling_effect=import(uncompressed[0x39c], 0x39c);
1923 cave->biter_eat=import(uncompressed[0x39d], 0x39d);
1924 cave->slime_eats_1=import(uncompressed[0x39e], 0x39e);
1925 cave->slime_converts_1=import(uncompressed[0x39e]+3, 0x39e);
1926 cave->slime_eats_2=import(uncompressed[0x39f], 0x39f);
1927 cave->slime_converts_2=import(uncompressed[0x39f]+3, 0x39f);
1929 /* v3.0 has some new properties. */
1930 if (version>=V3_0) {
1931 cave->diagonal_movements=uncompressed[0x3a4]!=0;
1932 cave->amoeba_too_big_effect=import(uncompressed[0x3a6], 0x3a6);
1933 cave->amoeba_enclosed_effect=import(uncompressed[0x3a7], 0x3a7);
1935 acid in crazy dream 8:
1936 jsr $2500 ; true random
1937 cmp $03a8 ; compare to ratio
1938 bcs out ; if it was smaller, forget it for now.
1940 ie. random<=ratio, then acid grows.
1942 cave->acid_spread_ratio=uncompressed[0x3a8]/255.0*1E6; /* *1e6, probabilities are stored as int */
1943 cave->acid_eats_this=import(uncompressed[0x3a9], 0x3a9);
1944 cave->expanding_wall_looks_like=import(uncompressed[0x3ab], 0x3ab);
1945 cave->dirt_looks_like=import(uncompressed[0x3ac], 0x3ac);
1946 } else {
1947 /* version is <= 3.0, so this is a 1stb cave. */
1948 /* the only parameters, for which this matters, are these: */
1949 if (uncompressed[0x380]!=0)
1950 cave->creatures_direction_auto_change_time=uncompressed[0x381];
1951 else
1952 cave->diagonal_movements=uncompressed[0x381]!=0;
1955 if (cavefile)
1956 cave->selectable=!cave->intermission; /* best we can do */
1957 else
1958 cave->selectable=!data[0]; /* given by converter */
1960 return datapos;
1964 GdCavefileFormat
1965 gd_caveset_imported_get_format(const guint8 *buf)
1967 const char *s_bd1="GDashBD1";
1968 const char *s_bd1_atari="GDashB1A";
1969 const char *s_dc1="GDashDC1";
1970 const char *s_bd2="GDashBD2";
1971 const char *s_bd2_atari="GDashB2A";
1972 const char *s_plc="GDashPLC";
1973 const char *s_plc_atari="GDashPCA";
1974 const char *s_dlb="GDashDLB";
1975 const char *s_crl="GDashCRL";
1976 const char *s_cd7="GDashCD7";
1977 const char *s_cd9="GDashCD9";
1978 const char *s_1st="GDash1ST";
1980 if (memcmp((char *)buf, s_bd1, strlen(s_bd1))==0)
1981 return GD_FORMAT_BD1;
1982 if (memcmp((char *)buf, s_bd1_atari, strlen(s_bd1_atari))==0)
1983 return GD_FORMAT_BD1_ATARI;
1984 if (memcmp((char *)buf, s_dc1, strlen(s_dc1))==0)
1985 return GD_FORMAT_DC1;
1986 if (memcmp((char *)buf, s_bd2, strlen(s_bd2))==0)
1987 return GD_FORMAT_BD2;
1988 if (memcmp((char *)buf, s_bd2_atari, strlen(s_bd2_atari))==0)
1989 return GD_FORMAT_BD2_ATARI;
1990 if (memcmp((char *)buf, s_plc, strlen(s_plc))==0)
1991 return GD_FORMAT_PLC;
1992 if (memcmp((char *)buf, s_plc_atari, strlen(s_plc_atari))==0)
1993 return GD_FORMAT_PLC_ATARI;
1994 if (memcmp((char *)buf, s_dlb, strlen(s_dlb))==0)
1995 return GD_FORMAT_DLB;
1996 if (memcmp((char *)buf, s_crl, strlen(s_crl))==0)
1997 return GD_FORMAT_CRLI;
1998 if (memcmp((char *)buf, s_cd7, strlen(s_cd7))==0)
1999 return GD_FORMAT_CRDR_7;
2000 if (memcmp((char *)buf, s_cd9, strlen(s_cd9))==0)
2001 return GD_FORMAT_CRDR_9;
2002 if (memcmp((char *)buf, s_1st, strlen(s_1st))==0)
2003 return GD_FORMAT_FIRSTB;
2005 return GD_FORMAT_UNKNOWN;
2010 Load caveset from memory buffer.
2011 Loads the caveset from a memory buffer.
2012 returns: GList * of caves.
2014 GList *
2015 gd_caveset_import_from_buffer (const guint8 *buf, gsize length)
2017 gboolean numbering;
2018 int cavenum, intermissionnum, num;
2019 int cavelength, bufp;
2020 GList *caveset=NULL, *iter;
2021 guint32 encodedlength;
2022 GdCavefileFormat format;
2024 if (length!=-1 && length<12) {
2025 g_warning("buffer too short to be a GDash datafile");
2026 return NULL;
2028 encodedlength=GUINT32_FROM_LE(*((guint32 *)(buf+8)));
2029 if (length!=-1 && encodedlength!=length-12) {
2030 g_warning("file length and data size mismatch in GDash datafile");
2031 return NULL;
2033 format=gd_caveset_imported_get_format(buf);
2034 if (format==GD_FORMAT_UNKNOWN) {
2035 g_warning("buffer does not contain a GDash datafile");
2036 return NULL;
2039 buf+=12;
2040 length=encodedlength;
2042 bufp=0;
2044 cavenum=0;
2045 while (bufp<length) {
2046 GdCave *newcave;
2047 int insertpos=-1; /* default is to append cave to caveset; g_list_insert appends when pos=-1 */
2049 newcave=gd_cave_new();
2051 cavelength=0; /* to avoid compiler warning */
2053 switch (format) {
2054 case GD_FORMAT_BD1: /* boulder dash 1 */
2055 case GD_FORMAT_BD1_ATARI: /* boulder dash 1, atari version */
2056 case GD_FORMAT_DC1: /* deluxe caves 1 */
2057 case GD_FORMAT_BD2: /* boulder dash 2 */
2058 case GD_FORMAT_BD2_ATARI: /* boulder dash 2 */
2059 /* these are not in the data so we guess */
2060 newcave->selectable=(cavenum<16) && (cavenum%4 == 0);
2061 newcave->intermission=cavenum>15;
2062 /* no name, so we make up one */
2063 if (newcave->intermission)
2064 g_snprintf(newcave->name, sizeof(newcave->name), _("Intermission %d"), cavenum-15);
2065 else
2066 g_snprintf(newcave->name, sizeof(newcave->name), _("Cave %c"), 'A'+cavenum);
2068 switch(format) {
2069 case GD_FORMAT_BD1:
2070 case GD_FORMAT_BD1_ATARI:
2071 case GD_FORMAT_DC1:
2072 cavelength=cave_copy_from_bd1(newcave, buf+bufp, length-bufp, format);
2073 break;
2074 case GD_FORMAT_BD2:
2075 case GD_FORMAT_BD2_ATARI:
2076 cavelength=cave_copy_from_bd2(newcave, buf+bufp, length-bufp, format);
2077 break;
2078 default:
2079 g_assert_not_reached();
2082 /* original bd1 had level order ABCDEFGH... and then the last four were the intermissions.
2083 * those should be inserted between D-E, H-I... caves. */
2084 if (cavenum>15)
2085 insertpos=(cavenum-15)*5-1;
2086 break;
2088 case GD_FORMAT_FIRSTB:
2089 cavelength=cave_copy_from_1stb(newcave, buf+bufp, length-bufp);
2090 /* every fifth cave (4+1 intermission) is selectable. */
2091 newcave->selectable=cavenum%5==0;
2092 break;
2094 case GD_FORMAT_PLC: /* peter liepa construction kit */
2095 case GD_FORMAT_PLC_ATARI: /* peter liepa construction kit, atari version */
2096 gd_error_set_context("cave %d", cavenum);
2097 cavelength=cave_copy_from_plck(newcave, buf+bufp, length-bufp, format);
2098 break;
2100 case GD_FORMAT_DLB: /* no one's delight boulder dash, something like rle compressed plck caves */
2101 /* but there are 20 of them, as if it was a bd1 or bd2 game. also num%5=4 is intermission. */
2102 /* we have to set intermission flag on our own, as the file did not contain the info explicitly */
2103 newcave->intermission=(cavenum%5)==4;
2104 if (newcave->intermission) { /* also set visible size */
2105 newcave->x2=19;
2106 newcave->y2=11;
2108 newcave->selectable=cavenum % 5 == 0; /* original selection scheme */
2109 if (newcave->intermission)
2110 g_snprintf(newcave->name, sizeof(newcave->name), _("Intermission %d"), cavenum/5+1);
2111 else
2112 g_snprintf(newcave->name, sizeof(newcave->name), _("Cave %c"), 'A'+(cavenum%5+cavenum/5*4));
2114 cavelength=cave_copy_from_dlb (newcave, buf+bufp, length-bufp);
2115 break;
2117 case GD_FORMAT_CRLI:
2118 cavelength=cave_copy_from_crli (newcave, buf+bufp, length-bufp);
2119 break;
2121 case GD_FORMAT_CRDR_7:
2122 cavelength=cave_copy_from_crdr_7 (newcave, buf+bufp, length-bufp);
2123 break;
2125 case GD_FORMAT_CRDR_9:
2126 cavelength=cave_copy_from_crli (newcave, buf+bufp, length-bufp);
2127 if (cavelength!=-1)
2128 crazy_dream_9_add_specials(newcave, buf, cavelength);
2129 break;
2131 case GD_FORMAT_UNKNOWN:
2132 g_assert_not_reached();
2133 break;
2136 gd_error_set_context(NULL);
2137 if (cavelength==-1) {
2138 gd_cave_free(newcave);
2139 g_critical("Aborting cave import.");
2140 break;
2141 } else
2142 caveset=g_list_insert(caveset, newcave, insertpos);
2143 cavenum++;
2144 bufp+=cavelength;
2146 /* hack: some dlb files contain junk data after 20 caves. */
2147 if (format==GD_FORMAT_DLB && cavenum==20) {
2148 if (bufp<length)
2149 g_warning("excess data in dlb file, %d bytes", (int)(length-bufp));
2150 break;
2154 /* try to detect if plc caves are in standard layout. */
2155 /* that is, caveset looks like an original, (4 cave,1 intermission)+ */
2156 if (format==GD_FORMAT_PLC)
2157 /* if no selection table stored by any2gdash */
2158 if ((buf[2+0x1f0]!=buf[2+0x1f1]-1) || (buf[2+0x1f0]!=0x19 && buf[2+0x1f0]!=0x0e)) {
2159 GList *iter;
2160 int n;
2161 gboolean standard;
2163 standard=(g_list_length(caveset)%5)==0; /* cave count % 5 != 0 -> nonstandard */
2165 for (n=0, iter=caveset; iter!=NULL; n++, iter=iter->next) {
2166 GdCave *cave=iter->data;
2168 if ((n%5==4 && !cave->intermission) || (n%5!=4 && cave->intermission))
2169 standard=FALSE; /* 4 cave, 1 intermission */
2172 /* if test passed, update selectability */
2173 if (standard)
2174 for (n=0, iter=caveset; iter!=NULL; n++, iter=iter->next) {
2175 GdCave *cave=iter->data;
2177 /* update "selectable" */
2178 cave->selectable=(n%5)==0;
2182 /* try to give some names for the caves */
2183 cavenum=1; intermissionnum=1;
2184 num=1;
2185 /* use numbering instead of letters, if following formats or too many caves (as we would run out of letters) */
2186 numbering=format==GD_FORMAT_PLC || format==GD_FORMAT_CRLI || g_list_length(caveset)>26;
2187 for (iter=caveset; iter!=NULL; iter=iter->next) {
2188 GdCave *cave=(GdCave *)iter->data;
2190 if (!g_str_equal(cave->name, "")) /* if it already has a name, skip */
2191 continue;
2193 if (cave->intermission) {
2194 /* intermission */
2195 if (numbering)
2196 g_snprintf(cave->name, sizeof(cave->name), _("Intermission %02d"), num);
2197 else
2198 g_snprintf(cave->name, sizeof(cave->name), _("Intermission %d"), intermissionnum);
2199 } else {
2200 if (numbering)
2201 g_snprintf(cave->name, sizeof(cave->name), _("Cave %02d"), num);
2202 else
2203 g_snprintf(cave->name, sizeof(cave->name), _("Cave %c"), 'A'-1+cavenum);
2206 num++;
2207 if (cave->intermission)
2208 intermissionnum++;
2209 else
2210 cavenum++;
2213 gd_error_set_context(NULL);
2215 /* if the uses requests, we make all caves selectable. intermissions not. */
2216 if (gd_import_as_all_caves_selectable)
2217 for (iter=caveset; iter!=NULL; iter=iter->next) {
2218 GdCave *cave=(GdCave *)iter->data;
2220 /* make selectable if not an intermission. */
2221 /* also selectable, if it was selectable originally, for some reason. */
2222 cave->selectable=cave->selectable || !cave->intermission;
2225 return caveset;
2232 /* to be called at program start. */
2233 void
2234 gd_c64_import_init_tables()
2236 g_assert(gd_defaults_bd1[G_N_ELEMENTS(gd_defaults_bd1)-1].offset==-1);
2237 g_assert(gd_defaults_bd2[G_N_ELEMENTS(gd_defaults_bd2)-1].offset==-1);
2238 g_assert(gd_defaults_plck[G_N_ELEMENTS(gd_defaults_plck)-1].offset==-1);
2239 g_assert(gd_defaults_1stb[G_N_ELEMENTS(gd_defaults_1stb)-1].offset==-1);
2240 g_assert(gd_defaults_crdr_7[G_N_ELEMENTS(gd_defaults_crdr_7)-1].offset==-1);
2241 g_assert(gd_defaults_crli[G_N_ELEMENTS(gd_defaults_crli)-1].offset==-1);