3 * handle binary emc cave file format
9 /* convert emc caves to intermediate cave format.
11 * the intermediate format supports most emc caves, but some internal
12 * objects are not supported.
15 * - active objects - use global flags instead of individual on/off
16 * - falling or paused objects - become still objects
17 * - sand states - become either sand with/without stone
18 * - collected objects - become a common pause object
19 * - drip states - become a normal drip
22 * - exploding objects (not in emc player either)
24 * pushed objects are supported in the cave, eaters and magic ball.
25 * they behave almost the same as in the emc player, pushing over
26 * steel wall, androids, players etc. a compile time option chooses
27 * if pushed objects go into the acid.
29 * acid is handled completely different in my player. acid top is a
30 * separate object, which can be put anywhere and the beasts will
31 * be gobbled, even if they go in from below. in the emc player, an
32 * acid top without a bottom becomes plant.
34 * borderless caves are supported, almost the same as in the emc
35 * player. going off the left edge of the screen resulted in the
36 * beast/player moving up 1 square (and the player disappeared).
37 * going off the right edge of the screen, the beast/player would
38 * go down 1 square. in my player, everything stays on the same y
39 * coord, which is sensible, but breaks caves which expect the old
43 static const short map_emc[256] =
45 Xstone, Xstone, Xdiamond, Xdiamond,
46 Xalien, Xalien, Xblank, Xblank,
47 Xtank_1_n, Xtank_1_e, Xtank_1_s, Xtank_1_w,
48 Xtank_2_n, Xtank_2_e, Xtank_2_s, Xtank_2_w,
50 Xbomb, Xbomb, Xemerald, Xemerald,
51 Xbug_1_n, Xbug_1_e, Xbug_1_s, Xbug_1_w,
52 Xbug_2_n, Xbug_2_e, Xbug_2_s, Xbug_2_w,
53 Xdrip, Xdrip, Xdrip, Xdrip,
55 Xstone, Xbomb, Xdiamond, Xemerald,
56 Xwonderwall, Xnut, Xnut, Xnut,
57 Xwheel, Xeater_n, Xeater_s, Xeater_w,
58 Xeater_e, Xsand_stone, Xblank, Xblank,
60 Xblank, Xsand, Xsand, Xsand,
61 Xsand_stone, Xsand_stone, Xsand_stone, Xsand,
62 Xstone, Xslide_ew, Xslide_ns, Xdynamite_1,
63 Xdynamite_2, Xdynamite_3, Xdynamite_4, Xacid_s,
65 Xexit_1, Xexit_2, Xexit_3, Xballoon,
66 Xplant, Xspring, Xspring_fall, Xspring_w,
67 Xspring_e, Xball_1, Xball_2, Xandroid,
68 Xblank, Xandroid, Xandroid, Xandroid,
70 Xandroid, Xandroid, Xandroid, Xandroid,
71 Xandroid, Xblank, Xblank, Xblank,
72 Xblank, Xblank, Xblank, Xblank,
73 Xblank, Xblank, Xblank, Xblank,
75 Xblank, Xblank, Xblank, Xpush_spring_w,
76 Xpush_spring_e, Xacid_1, Xacid_2, Xacid_3,
77 Xacid_4, Xacid_5, Xacid_6, Xacid_7,
78 Xacid_8, Xblank, Xblank, Xblank,
80 Xblank, Xblank, Xpush_nut_w, Xpush_nut_e,
81 Xsteel_1, Xblank, Xblank, Xpush_bomb_w,
82 Xpush_bomb_e, Xpush_stone_w, Xpush_stone_e, Xblank,
83 Xblank, Xblank, Xblank, Xblank,
85 Xblank, Xroundwall_1, Xgrass, Xsteel_1,
86 Xwall_1, Xkey_1, Xkey_2, Xkey_3,
87 Xkey_4, Xdoor_1, Xdoor_2, Xdoor_3,
88 Xdoor_4, Xfake_amoeba, Xfake_door_1, Xfake_door_2,
90 Xfake_door_3, Xfake_door_4, Xwonderwall, Xwheel,
91 Xsand, Xacid_nw, Xacid_ne, Xacid_sw,
92 Xacid_se, Xfake_blank, Xamoeba_1, Xamoeba_2,
93 Xamoeba_3, Xamoeba_4, Xexit, Xalpha_arrow_w,
95 Xfake_grass, Xlenses, Xmagnify, Xfake_blank,
96 Xfake_grass, Xswitch, Xswitch, Xblank,
97 Xdecor_8, Xdecor_9, Xdecor_10, Xdecor_5,
98 Xalpha_comma, Xalpha_quote, Xalpha_minus, Xdynamite,
100 Xsteel_3, Xdecor_6, Xdecor_7, Xsteel_2,
101 Xroundwall_2, Xdecor_2, Xdecor_4, Xdecor_3,
102 Xwind_any, Xwind_e, Xwind_s, Xwind_w,
103 Xwind_n, Xdirt, Xplant, Xkey_5,
105 Xkey_6, Xkey_7, Xkey_8, Xdoor_5,
106 Xdoor_6, Xdoor_7, Xdoor_8, Xbumper,
107 Xalpha_a, Xalpha_b, Xalpha_c, Xalpha_d,
108 Xalpha_e, Xalpha_f, Xalpha_g, Xalpha_h,
110 Xalpha_i, Xalpha_j, Xalpha_k, Xalpha_l,
111 Xalpha_m, Xalpha_n, Xalpha_o, Xalpha_p,
112 Xalpha_q, Xalpha_r, Xalpha_s, Xalpha_t,
113 Xalpha_u, Xalpha_v, Xalpha_w, Xalpha_x,
115 Xalpha_y, Xalpha_z, Xalpha_0, Xalpha_1,
116 Xalpha_2, Xalpha_3, Xalpha_4, Xalpha_5,
117 Xalpha_6, Xalpha_7, Xalpha_8, Xalpha_9,
118 Xalpha_perio, Xalpha_excla, Xalpha_colon, Xalpha_quest,
120 Xalpha_arrow_e, Xdecor_1, Xfake_door_5, Xfake_door_6,
121 Xfake_door_7, Xfake_door_8, Xblank, Xblank,
122 Xblank, Xblank, Xblank, Xblank,
123 Xblank, Xblank, Xalpha_copyr, Xfake_acid_1
126 static int get_em_element(unsigned short em_element_raw, int file_version)
128 int em_element = map_emc[em_element_raw];
130 if (file_version < FILE_VERSION_EM_V5)
132 /* versions below V5 had no grass, but only sand/dirt */
133 if (em_element == Xgrass)
140 void convert_em_level(unsigned char *src, int file_version)
142 static int eater_offset[8] =
144 2048, 2057, 2066, 2075,
145 2112, 2121, 2130, 2139
149 lev.time_seconds = src[2110] << 8 | src[2111];
150 if (lev.time_seconds > 9999)
151 lev.time_seconds = 9999;
153 lev.required_initial = src[2095];
155 for (i = 0; i < 2; i++)
157 temp = src[2096 + i * 2] << 8 | src[2097 + i * 2];
158 ply[i].x_initial = (temp & 63);
159 ply[i].y_initial = (temp >> 6 & 31);
162 temp = (src[2100] << 8 | src[2101]) * 28;
165 lev.amoeba_time = temp;
167 lev.android_move_time = src[2164] << 8 | src[2165];
168 lev.android_clone_time = src[2166] << 8 | src[2167];
170 lev.ball_random = src[2162] & 1 ? 1 : 0;
171 lev.ball_state_initial = src[2162] & 128 ? 1 : 0;
172 lev.ball_time = src[2160] << 8 | src[2161];
174 lev.emerald_score = src[2084];
175 lev.diamond_score = src[2085];
176 lev.alien_score = src[2086];
177 lev.tank_score = src[2087];
178 lev.bug_score = src[2088];
179 lev.eater_score = src[2089];
180 lev.nut_score = src[2090];
181 lev.dynamite_score = src[2091];
182 lev.key_score = src[2092];
183 lev.exit_score = src[2093] * 8 / 5;
185 lev.lenses_score = src[2151];
186 lev.magnify_score = src[2152];
187 lev.slurp_score = src[2153];
189 lev.lenses_time = src[2154] << 8 | src[2155];
190 lev.magnify_time = src[2156] << 8 | src[2157];
191 lev.wheel_time = src[2104] << 8 | src[2105];
193 lev.wind_cnt_initial = src[2149] & 15 ? lev.wind_time : 0;
195 lev.wind_direction_initial = (temp & 8 ? 0 :
200 lev.wonderwall_time_initial = src[2102] << 8 | src[2103];
202 for (i = 0; i < 8; i++)
203 for (x = 0; x < 9; x++)
204 lev.eater_array[i][x] =
205 get_em_element(src[eater_offset[i] + x], file_version);
207 temp = get_em_element(src[2159], file_version);
208 for (y = 0; y < 8; y++)
212 for (x = 0; x < 8; x++)
213 lev.ball_array[y][x] = temp;
217 lev.ball_array[y][1] = (src[2163] & 1) ? temp : Xblank; /* north */
218 lev.ball_array[y][6] = (src[2163] & 2) ? temp : Xblank; /* south */
219 lev.ball_array[y][3] = (src[2163] & 4) ? temp : Xblank; /* west */
220 lev.ball_array[y][4] = (src[2163] & 8) ? temp : Xblank; /* east */
221 lev.ball_array[y][7] = (src[2163] & 16) ? temp : Xblank; /* southeast */
222 lev.ball_array[y][5] = (src[2163] & 32) ? temp : Xblank; /* southwest */
223 lev.ball_array[y][2] = (src[2163] & 64) ? temp : Xblank; /* northeast */
224 lev.ball_array[y][0] = (src[2163] & 128)? temp : Xblank; /* northwest */
228 temp = src[2168] << 8 | src[2169];
230 lev.android_emerald = (temp & 1) != 0;
231 lev.android_diamond = (temp & 2) != 0;
232 lev.android_stone = (temp & 4) != 0;
233 lev.android_bomb = (temp & 8) != 0;
234 lev.android_nut = (temp & 16) != 0;
235 lev.android_tank = (temp & 32) != 0;
236 lev.android_eater = (temp & 64) != 0;
237 lev.android_bug = (temp & 128) != 0;
238 lev.android_alien = (temp & 256) != 0;
239 lev.android_spring = (temp & 512) != 0;
240 lev.android_balloon = (temp & 1024) != 0;
241 lev.android_amoeba = (temp & 2048) != 0;
242 lev.android_dynamite = (temp & 4096) != 0;
244 for (temp = 1; temp < 2047; temp++)
248 case 36: /* wonderwall */
249 lev.wonderwall_state_initial = 1;
250 lev.wonderwall_time_initial = 9999;
254 lev.wheel_x_initial = temp & 63;
255 lev.wheel_y_initial = temp >> 6;
256 lev.wheel_cnt_initial = lev.wheel_time;
259 case 163: /* fake blank */
260 lev.lenses_cnt_initial = 9999;
263 case 164: /* fake grass */
264 lev.magnify_cnt_initial = 9999;
269 /* first fill the complete playfield with the default border element */
270 for (y = 0; y < CAVE_HEIGHT; y++)
271 for (x = 0; x < CAVE_WIDTH; x++)
272 native_em_level.cave[x][y] = Zborder;
274 /* then copy the real level contents from level file into the playfield */
276 for (y = 0; y < lev.height; y++)
277 for (x = 0; x < lev.width; x++)
278 native_em_level.cave[x][y] =
279 get_em_element(src[temp++], file_version);
281 /* at last, set the two players at their positions in the playfield */
282 /* (native EM[C] levels always have exactly two players in a level) */
283 for (i = 0; i < 2; i++)
284 native_em_level.cave[ply[i].x_initial][ply[i].y_initial] = Zplayer;
286 native_em_level.file_version = file_version;
290 /* convert all emerald mine caves to emc version 6 cave format.
292 * caves are filtered to get rid of invalid or unsupported tiles.
294 * although the result is a somewhat clean cave, it is meant only
295 * to give a common structure for the binary cave format. it is not
296 * for archiving purposes (it is better to keep the raw cave as-is)
297 * and it is not meant for serializing (the intermediate structure
298 * is better defined).
300 * acid top is added to acid bottom in both the cave and the eaters.
301 * fake acid (only in v4) does not exist because it adds nothing to
302 * the game, and is different even in different versions of the emc
305 * v4/v5 time is converted to 10x old time (as it should be).
306 * the reason the kingsoft player used 5x time was copy protection.
308 * note: emc v6 converter has an error in converting v4 eaters to the
309 * wrong bug(24 instead of 20) and tank(12 instead of 8).
312 static const unsigned char map_v6[256] =
316 0,0,2,2, 4,4,118,118, 8,9,10,11, 12,13,14,15,
317 16,16,18,18, 20,21,22,23, 24,25,26,27, 28,28,118,28,
318 0,16,2,18, 36,37,37,37, 40,41,42,43, 44,45,128,128,
319 128,148,148, 148,45,45,45, 148,0,57,58, 59,60,61,62,63,
321 64,65,66,67, 68,69,69,71, 72,73,74,75, 118,75,75,75,
322 75,75,75,75, 75,153,153,153, 153,153,153,153, 153,153,153,153,
323 153,153,153,99, 100,68,68,68, 68,68,68,68, 68,118,118,118,
324 118,118,114,115, 131,118,118,119, 120,121,122,118, 118,118,118,118,
326 128,129,130,131, 132,133,134,135, 136,137,138,139, 140,141,142,143,
327 144,145,146,147, 148,149,150,151, 152,153,154,155, 156,157,158,159,
328 160,161,162,163, 164,165,165,118, 168,169,170,171, 172,173,174,175,
329 176,177,178,179, 180,181,182,183, 184,185,186,187, 188,189,68,191,
331 192,193,194,195, 196,197,198,199, 200,201,202,203, 204,205,206,207,
332 208,209,210,211, 212,213,214,215, 216,217,218,219, 220,221,222,223,
333 224,225,226,227, 228,229,230,231, 232,233,234,235, 236,237,238,239,
334 240,241,242,243, 244,245,153,153, 153,153,153,153, 153,153,153,153
337 static const unsigned char map_v5[256] =
341 0,0,2,2, 4,4,118,118, 8,9,10,11, 12,13,14,15,
342 16,16,18,18, 20,21,22,23, 24,25,26,27, 28,28,118,28,
343 0,16,2,18, 36,37,37,37, 147,41,42,43, 44,45,128,128,
344 128,148,148,148, 45,45,45,148, 0,57,58,59, 60,61,62,63,
346 64,65,66,67, 68,153,153,153, 153,153,153,153, 153,153,153,153,
347 153,153,153,153, 153,153,153,153, 153,153,153,153, 153,153,153,153,
348 153,153,153,153, 153,68,68,68, 68,68,68,68, 68,118,118,118,
349 118,118,114,115, 131,118,118,119, 120,121,122,118, 118,118,118,118,
351 128,129,130,131, 132,133,134,135, 136,137,138,139, 140,141,142,143,
352 144,145,146,147, 148,149,150,151, 152,153,154,155, 156,157,158,159,
353 160,153,153,153, 153,153,153,118, 168,169,170,171, 172,173,174,175,
354 176,177,178,179, 180,181,182,183, 184,185,186,187, 188,189,68,153,
356 153,153,153,153, 153,153,153,153, 200,201,202,203, 204,205,206,207,
357 208,209,210,211, 212,213,214,215, 216,217,218,219, 220,221,222,223,
358 224,225,226,227, 228,229,230,231, 232,233,234,235, 236,237,238,239,
359 240,241,153,153, 153,153,153,153, 153,153,153,153, 153,153,153,153
362 static const unsigned char map_v4[256] =
366 0,0,2,2, 4,4,118,118, 8,9,10,11, 12,13,14,15,
367 16,16,18,18, 20,21,22,23, 24,25,26,27, 28,28,118,28,
368 0,16,2,18, 36,37,37,37, 147,41,42,43, 44,45,128,128,
369 128,148,148,148, 45,45,45,148, 0,153,153,59, 60,61,62,63,
371 64,65,66,153, 153,153,153,153, 153,153,153,153, 153,153,153,153,
372 153,153,153,153, 153,153,153,153, 153,153,153,153, 153,153,153,153,
373 153,153,153,153, 153,153,153,153, 153,153,153,153, 153,153,153,153,
374 153,118,114,115, 131,118,118,119, 120,121,122,118, 118,118,118,118,
376 128,129,130,131, 132,133,134,135, 136,137,138,139, 140,141,142,143,
377 144,145,146,147, 148,149,150,151, 152,68,154,155, 156,157,158,160,
378 160,160,160,160, 160,160,160,160, 160,160,160,160, 160,160,160,175,
379 153,153,153,153, 153,153,153,153, 153,153,153,153, 153,153,68,153,
381 153,153,153,153, 153,153,153,153, 200,201,202,203, 204,205,206,207,
382 208,209,210,211, 212,213,214,215, 216,217,218,219, 220,221,222,223,
383 224,225,226,227, 228,229,230,231, 232,233,234,235, 236,237,238,239,
384 240,241,153,153, 153,153,153,153, 153,153,153,153, 153,153,153,153
387 static const unsigned char map_v4_eater[32] =
389 /* filter for v4 eater */
391 128,18,2,0, 4,8,16,20, 28,37,41,45, 130,129,131,132,
392 133,134,135,136, 146,147,175,65, 66,64,2,18, 128,128,128,128
395 static boolean filename_has_v1_format(char *filename)
397 char *basename = getBaseNamePtr(filename);
399 return (strlen(basename) == 3 &&
400 basename[0] == 'a' &&
401 basename[1] >= 'a' && basename[1] <= 'k' &&
402 basename[2] >= '0' && basename[2] <= '9');
405 int cleanup_em_level(unsigned char *src, int length, char *filename)
407 int file_version = FILE_VERSION_EM_UNKNOWN;
410 if (length >= 2172 &&
411 src[2106] == 255 && /* version id: */
412 src[2107] == 54 && /* '6' */
413 src[2108] == 48 && /* '0' */
414 src[2109] == 48) /* '0' */
416 /* ---------- this cave has V6 file format ---------- */
417 file_version = FILE_VERSION_EM_V6;
419 /* remap elements to internal EMC level format */
420 for (i = 0; i < 2048; i++)
421 src[i] = map_v6[src[i]];
422 for (i = 2048; i < 2084; i++)
423 src[i] = map_v6[src[i]];
424 for (i = 2112; i < 2148; i++)
425 src[i] = map_v6[src[i]];
427 else if (length >= 2110 &&
428 src[2106] == 255 && /* version id: */
429 src[2107] == 53 && /* '5' */
430 src[2108] == 48 && /* '0' */
431 src[2109] == 48) /* '0' */
433 /* ---------- this cave has V5 file format ---------- */
434 file_version = FILE_VERSION_EM_V5;
436 /* remap elements to internal EMC level format */
437 for (i = 0; i < 2048; i++)
438 src[i] = map_v5[src[i]];
439 for (i = 2048; i < 2084; i++)
440 src[i] = map_v5[src[i]];
441 for (i = 2112; i < 2148; i++)
442 src[i] = src[i - 64];
444 else if (length >= 2106 &&
445 (src[1983] == 27 || /* encrypted (only EM I/II/III) */
446 src[1983] == 116 || /* unencrypted (usual case) */
447 src[1983] == 131)) /* unencrypted (rare case) */
449 /* ---------- this cave has V1, V2 or V3 file format ---------- */
451 boolean fix_copyright = FALSE;
454 byte at position 1983 (0x07bf) is used as "magic byte":
455 - 27 (0x1b) => encrypted level (V3 only / Kingsoft original games)
456 - 116 (0x74) => unencrypted level (byte is corrected to 131 (0x83))
457 - 131 (0x83) => unencrypted level (happens only in very rare cases)
460 if (src[1983] == 27) /* (0x1b) -- after decryption: 116 (0x74) */
462 /* this is original (encrypted) Emerald Mine I, II or III level file */
464 int first_byte = src[0];
465 unsigned char code0 = 0x65;
466 unsigned char code1 = 0x11;
468 /* decode encrypted level data */
469 for (i = 0; i < 2106; i++)
474 code0 = (code0 + 7) & 0xff;
477 src[1] = 131; /* needed for all Emerald Mine levels */
479 /* first byte is either 0xf1 (EM I and III) or 0xf5 (EM II) */
480 if (first_byte == 0xf5)
482 src[0] = 131; /* only needed for Emerald Mine II levels */
484 fix_copyright = TRUE;
487 /* ---------- this cave has V3 file format ---------- */
488 file_version = FILE_VERSION_EM_V3;
490 else if (filename_has_v1_format(filename))
492 /* ---------- this cave has V1 file format ---------- */
493 file_version = FILE_VERSION_EM_V1;
497 /* ---------- this cave has V2 file format ---------- */
498 file_version = FILE_VERSION_EM_V2;
501 /* remap elements to internal EMC level format */
502 for (i = 0; i < 2048; i++)
503 src[i] = map_v4[src[i]];
504 for (i = 2048; i < 2084; i++)
505 src[i] = map_v4_eater[src[i] >= 28 ? 0 : src[i]];
506 for (i = 2112; i < 2148; i++)
507 src[i] = src[i - 64];
509 if (fix_copyright) /* fix "(c)" sign in Emerald Mine II levels */
511 for (i = 0; i < 2048; i++)
513 src[i] = 254; /* replace 'Xdecor_1' with 'Xalpha_copyr' */
518 /* ---------- this cave has unknown file format ---------- */
520 /* if file has length of old-style level file, print (wrong) magic byte */
522 Error(ERR_WARN, "unknown magic byte 0x%02x at position 0x%04x",
525 return FILE_VERSION_EM_UNKNOWN;
528 if (file_version < FILE_VERSION_EM_V6)
531 src[2106] = 255; /* version id: */
532 src[2107] = 54; /* '6' */
533 src[2108] = 48; /* '0' */
534 src[2109] = 48; /* '0' */
538 /* stored level time of levels for the V2 player was changed to 50% of the
539 time for the V1 player (original V3 levels already considered this) */
540 if (file_version != FILE_VERSION_EM_V1 &&
541 file_version != FILE_VERSION_EM_V3)
546 for (i = 2148; i < 2172; i++)
553 /* ---------- at this stage, the cave data always has V6 format ---------- */
556 for (i = 0; i < 2048; i++)
559 for (i++; i < 2048; i++)
564 for (i = 64; i < 2048; i++)
565 if (src[i] == 63) /* replace element above 'Xacid_s' ... */
566 src[i - 64] = 101; /* ... with 'Xacid_1' */
568 /* fix acid with no base beneath it (see below for details (*)) */
569 for (i = 64; i < 2048 - 1; i++)
571 if (file_version <= FILE_VERSION_EM_V2 &&
572 src[i - 64] == 101 && src[i] != 63) /* acid without base */
574 if (src[i - 1] == 101 || /* remove acid over acid row */
576 src[i - 64] = 6; /* replace element above with 'Xblank' */
578 src[i - 64] = 255; /* replace element above with 'Xfake_acid_1' */
582 /* fix acid in eater 1 */
583 for (i = 2051; i < 2057; i++)
587 /* fix acid in eater 2 */
588 for (i = 2060; i < 2066; i++)
592 /* fix acid in eater 3 */
593 for (i = 2069; i < 2075; i++)
597 /* fix acid in eater 4 */
598 for (i = 2078; i < 2084; i++)
602 /* fix acid in eater 5 */
603 for (i = 2115; i < 2121; i++)
607 /* fix acid in eater 6 */
608 for (i = 2124; i < 2130; i++)
612 /* fix acid in eater 7 */
613 for (i = 2133; i < 2139; i++)
617 /* fix acid in eater 8 */
618 for (i = 2142; i < 2148; i++)
627 src[src[2096] << 8 | src[2097]] = 128;
631 src[src[2098] << 8 | src[2099]] = 128;
634 if ((src[2100] << 8 | src[2101]) > 9999)
640 /* time wonderwall */
641 if ((src[2102] << 8 | src[2103]) > 9999)
648 if ((src[2110] << 8 | src[2111]) > 9999)
661 if ((src[2154] << 8 | src[2155]) > 9999)
668 if ((src[2156] << 8 | src[2157]) > 9999)
676 src[2159] = map_v6[src[2159]];
679 if ((src[2160] << 8 | src[2161]) > 9999)
690 /* android move pause */
691 if ((src[2164] << 8 | src[2165]) > 9999)
697 /* android clone pause */
698 if ((src[2166] << 8 | src[2167]) > 9999)
707 /* size of v6 cave */
711 Error(ERR_DEBUG, "EM level file version: %d", file_version);
720 structure of emerald mine level disk files
721 ----------------------------------------------------------------------
723 if(len >= 2172 && (buf[2106] == 255 && buf[2107] == 54 && buf[2108] == 48 && buf[2109] == 48)) // v6
724 if(len >= 2110 && (buf[2106] == 255 && buf[2107] == 53 && buf[2108] == 48 && buf[2109] == 48)) // v5
725 if(len >= 2106 && (buf[1983] == 116 || buf[2047] == 116)) // v4
726 if(len >= 2106 && (buf[1983] == 27 || buf[2047] == 219)) // v3
728 buf[0]=241;buf[1]=248;for(i=0,j=101;i<2106;i++,j+=7)buf[i]=(buf[i]^j)-17; // decrypt
730 number of movements (calls to logic) = time * 50 / 8
732 {} reserved (but some broken levels use them)
734 ----------------------------------------------------------------------
754 2095: emeralds needed
758 2102: wonderwall time
760 2106: ID (0xff363030)
766 2148: flags bit#7=NOI #6=RIS
767 2149: wind direction bit#0=right #1=down #2=left #3=up
768 2150: cave number bit#7=teamwork
777 2162: ball info bit#15=switch state #8=random
778 ; bit#0=N #1=S #2=W #3=E #4=SE #5=SW #6=NE #7=NW
779 2164: android move speed
780 2166: android clone speed
782 ; bit#0=emerald #1=diamond #2=stone #3=bomb #4=nut #5=tank #6=eater
783 ; #7=bug #8=alien #9=spring #10=balloon #11=ameuba #12=dynamite
788 1: stone {stone_fall}
790 3: diamond {diamond_fall}
792 5: alien {alien_pause}
806 19: emerald {emerald_fall}
817 30: blank {drip_stretchB}
818 31: drip {drip_stretch}
819 32: stone {stone_pause}
820 33: bomb {bomb_pause}
821 34: diamond {diamond_pause}
822 35: emerald {emerald_pause}
823 36: wonderwall {wonderwallB}
833 46: blank {sand_stonein_2}
834 47: blank {sand_stonein_3}
835 48: blank {sand_stonein_4}
836 49: sand {sand_stonesand_2}
837 50: sand {sand_stonesand_3}
838 51: sand {sand_stonesand_4}
839 52: sand_stone {sand_sandstone_2}
840 53: sand_stone {sand_sandstone_3}
841 54: sand_stone {sand_sandstone_4}
842 55: sand {sand_stonesand_4}
843 56: stone {sand_stoneout_2}
857 70: spring {spring_fall}
858 71: spring {spring_w}
859 72: spring {spring_e}
864 77: android {android_n_1}
865 78: android {android_n_2}
866 79: android {android_s_1}
867 80: android {android_s_2}
868 81: android {android_e_1}
869 82: android {android_e_2}
870 83: android {android_w_1}
871 84: android {android_w_2}
886 99: spring {push_spring_w}
887 100: spring {push_spring_e}
896 109: pause {grass_wB}
897 110: pause {grass_eB}
898 111: pause {grass_nB}
899 112: pause {grass_sB}
900 113: pause {dynamite_blank}
901 114: nut {push_nut_w}
902 115: nut {push_nut_e}
903 116: steel_2 {end of level}
905 118: pause {emerald_blank}
906 119: bomb {push_bomb_w}
907 120: bomb {push_bomb_e}
908 121: stone {push_stone_w}
909 122: stone {push_stone_e}
910 123: pause {diamond_blank}
951 163: fake_blank {fake_blankB}
952 164: fake_grass {fake_grassB}
954 166: switch {switchB}
1045 ----------------------------------------------------------------------
1061 2091: dynamite value
1065 2095: emeralds needed
1069 2102: wonderwall time
1071 2106: ID (0xff353030)
1075 1: stone {stone_fall}
1077 3: diamond {diamond_fall}
1079 5: alien {alien_pause}
1091 17: bomb {bomb_fall}
1093 19: emerald {emerald_fall}
1103 29: drip {drip_fall}
1104 30: blank {drip_stretchB}
1105 31: drip {drip_stretch}
1106 32: stone {stone_pause}
1107 33: bomb {bomb_pause}
1108 34: diamond {diamond_pause}
1109 35: emerald {emerald_pause}
1110 36: wonderwall {wonderwallB}
1120 46: blank {sand_stonein_2}
1121 47: blank {sand_stonein_3}
1122 48: blank {sand_stonein_4}
1123 49: sand {sand_stonesand_2}
1124 50: sand {sand_stonesand_3}
1125 51: sand {sand_stonesand_4}
1126 52: sand_stone {sand_sandstone_2}
1127 53: sand_stone {sand_sandstone_3}
1128 54: sand_stone {sand_sandstone_4}
1129 55: sand {sand_stonesand_4}
1130 56: stone {sand_stoneout_2}
1183 109: pause {grass_wB}
1184 110: pause {grass_eB}
1185 111: pause {grass_nB}
1186 112: pause {grass_sB}
1187 113: pause {dynamite_blank}
1188 114: nut {push_nut_w}
1189 115: nut {push_nut_e}
1190 116: steel_2 {end of level}
1191 117: dynamite_4 {boom_2}
1192 118: pause {emerald_blank}
1193 119: bomb {push_bomb_w}
1194 120: bomb {push_bomb_e}
1195 121: stone {push_stone_w}
1196 122: stone {push_stone_e}
1197 123: pause {diamond_blank}
1198 124: pause {dirt_wB}
1199 125: pause {dirt_eB}
1200 126: pause {dirt_nB}
1201 127: pause {dirt_sB}
1332 ----------------------------------------------------------------------
1348 2091: dynamite value
1352 2095: emeralds needed
1356 2102: wonderwall time
1386 26: diamond {diamond_shine}
1387 27: emerald {emerald_shine}
1390 1: stone {stone_fall}
1392 3: diamond {diamond_fall}
1394 5: alien {alien_pause}
1406 17: bomb {bomb_fall}
1408 19: emerald {emerald_fall}
1418 29: drip {drip_fall}
1419 30: blank {drip_stretchB}
1420 31: drip {drip_stretch}
1421 32: stone {stone_pause}
1422 33: bomb {bomb_pause}
1423 34: diamond {diamond_pause}
1424 35: emerald {emerald_pause}
1425 36: wonderwall {wonderwallB}
1435 46: blank {sand_stonein_2}
1436 47: blank {sand_stonein_3}
1437 48: blank {sand_stonein_4}
1438 49: sand {sand_stonesand_2}
1439 50: sand {sand_stonesand_3}
1440 51: sand {sand_stonesand_4}
1441 52: sand_stone {sand_sandstone_2}
1442 53: sand_stone {sand_sandstone_3}
1443 54: sand_stone {sand_sandstone_4}
1444 55: sand {sand_stonesand_4}
1445 56: stone {sand_stoneout_2}
1502 113: pause {dynamite_blank}
1503 114: nut {push_nut_w}
1504 115: nut {push_nut_e}
1505 116: steel_1 {end of level}
1506 117: dynamite_4 {boom_2}
1507 118: pause {emerald_blank}
1508 119: bomb {push_bomb_w}
1509 120: bomb {push_bomb_e}
1510 121: stone {push_stone_w}
1511 122: stone {push_stone_e}
1512 123: pause {diamond_blank}
1513 124: pause {dirt_wB}
1514 125: pause {dirt_eB}
1515 126: pause {dirt_nB}
1516 127: pause {dirt_sB}
1549 159: fake_grass {dirt}
1550 160: fake_grass {dirt}
1551 161: fake_grass {dirt}
1552 162: fake_grass {dirt}
1553 163: fake_grass {dirt}
1554 164: fake_grass {dirt}
1555 165: fake_grass {dirt}
1556 166: fake_grass {dirt}
1557 167: fake_grass {dirt}
1558 168: fake_grass {dirt}
1559 169: fake_grass {dirt}
1560 170: fake_grass {dirt}
1561 171: fake_grass {dirt}
1562 172: fake_grass {dirt}
1563 173: fake_grass {dirt}
1564 174: fake_grass {dirt}
1630 240: alpha_arrow_e {}
1631 241: decor_1 {alpha_copyr}
1647 ----------------------------------------------------------------------