/* 2000-08-20T09:41:18Z
 *
 * identify all emerald mine caves and turn them into v6 format.
 * fixes illegal tiles, acid, wheel, limits times, cleans flags.
 *
 * these tables weed out bad tiles for older caves (eg. wheel on -> wheel off)
 * and clean up v6 caves (acid, number limits) which should(!) be
 * inconsequential, but no doubt it will break some caves.
 */

#include "main_em.h"


static unsigned char remap_v6[256] =
{
  /* filter crap for v6 */

  0,0,2,2,         4,4,118,118,     8,9,10,11,       12,13,14,15,
  16,16,18,18,     20,21,22,23,     24,25,26,27,     28,28,118,28,
  0,16,2,18,       36,37,37,37,     40,41,42,43,     44,45,128,128,
  128,148,148,     148,45,45,45,    148,0,57,58,     59,60,61,62,63,

  64,65,66,67,     68,69,69,69,     69,73,74,75,     118,75,75,75,
  75,75,75,75,     75,153,153,153,  153,153,153,153, 153,153,153,153,
  153,153,153,99,  100,68,68,68,    68,68,68,68,     68,118,118,118,
  118,118,114,115, 131,118,118,119, 120,121,122,118, 118,118,118,118,

  128,129,130,131, 132,133,134,135, 136,137,138,139, 140,141,142,143,
  144,145,146,147, 148,149,150,151, 152,153,154,155, 156,157,158,159,
  160,161,162,163, 164,165,165,118, 168,169,170,171, 172,173,174,175,
  176,177,178,179, 180,181,182,183, 184,185,186,187, 188,189,68,191,

  192,193,194,195, 196,197,198,199, 200,201,202,203, 204,205,206,207,
  208,209,210,211, 212,213,214,215, 216,217,218,219, 220,221,222,223,
  224,225,226,227, 228,229,230,231, 232,233,234,235, 236,237,238,239,
  240,241,242,243, 244,245,153,153, 153,153,153,153, 153,153,153,153
};

static unsigned char remap_v5[256] =
{
  /* filter crap for v5 */

  0,0,2,2,         4,4,118,118,     8,9,10,11,       12,13,14,15,
  16,16,18,18,     20,21,22,23,     24,25,26,27,     28,28,118,28,
  0,16,2,18,       36,37,37,37,     147,41,42,43,    44,45,128,128,
  128,148,148,148, 45,45,45,148,    0,57,58,59,      60,61,62,63,

  64,65,66,67,     68,153,153,153,  153,153,153,153, 153,153,153,153,
  153,153,153,153, 153,153,153,153, 153,153,153,153, 153,153,153,153,
  153,153,153,153, 153,68,68,68,68, 68,68,68,68,118, 118,118,
  118,118,114,115, 131,118,118,119, 120,121,122,118, 118,118,118,118,

  128,129,130,131, 132,133,134,135, 136,137,138,139, 140,141,142,143,
  144,145,146,147, 148,149,150,151, 152,153,154,155, 156,157,158,159,
  160,153,153,153, 153,153,153,118, 168,169,170,171, 172,173,174,175,
  176,177,178,179, 180,181,182,183, 184,185,186,187, 188,189,68,153,

  153,153,153,153, 153,153,153,153, 200,201,202,203, 204,205,206,207,
  208,209,210,211, 212,213,214,215, 216,217,218,219, 220,221,222,223,
  224,225,226,227, 228,229,230,231, 232,233,234,235, 236,237,238,239,
  240,241,153,153, 153,153,153,153, 153,153,153,153, 153,153,153,153
};

static unsigned char remap_v4[256] =
{
  /* filter crap for v4 */

  0,0,2,2,         4,4,118,118,     8,9,10,11,       12,13,14,15,
  16,16,18,18,     20,21,22,23,     24,25,26,27,     28,28,118,28,
  0,16,2,18,       36,37,37,37,     147,41,42,43,    44,45,128,128,
  128,148,148,148, 45,45,45,148,    0,153,153,59,    60,61,62,63,

  64,65,66,153,    153,153,153,153, 153,153,153,153, 153,153,153,153,
  153,153,153,153, 153,153,153,153, 153,153,153,153, 153,153,153,153,
  153,153,153,153, 153,153,153,153, 153,153,153,153, 153,153,153,153,
  153,118,114,115, 131,118,118,119, 120,121,122,118, 118,118,118,118,

  128,129,130,131, 132,133,134,135, 136,137,138,139, 140,141,142,143,
  144,145,146,147, 148,149,150,151, 152,68,154,155,  156,157,158,160,
  160,160,160,160, 160,160,160,160, 160,160,160,160, 160,160,160,175,
  153,153,153,153, 153,153,153,153, 153,153,153,153, 153,153,68,153,

  153,153,153,153, 153,153,153,153, 200,201,202,203, 204,205,206,207,
  208,209,210,211, 212,213,214,215, 216,217,218,219, 220,221,222,223,
  224,225,226,227, 228,229,230,231, 232,233,234,235, 236,237,238,239,
  240,241,153,153, 153,153,153,153, 153,153,153,153, 153,153,153,153
};

static unsigned char remap_v4eater[28] =
{
  /* filter crap for v4 */

  128,18,2,0,4,8,16,20,28,37,
  41,45,130,129,131,132,133,134,135,136,
  146,147,175,65,66,64,2,18
};

int cleanup_em_level(unsigned char *src, int length)
{
  int file_version = 0;
  int i;

  if (length >= 2172 &&
      src[2106] == 255 &&
      src[2107] == 54 &&
      src[2108] == 48 &&
      src[2109] == 48)
  {
    /* ---------- this cave has V6 file format ---------- */
    file_version = FILE_VERSION_EM_V6;

    for (i = 0; i < 2048; i++)
      src[i] = remap_v6[src[i]];
    for (i = 2048; i < 2084; i++)
      src[i] = remap_v6[src[i]];
    for (i = 2112; i < 2148; i++)
      src[i] = remap_v6[src[i]];
  }
  else if (length >= 2110 &&
	   src[2106] == 255 &&
	   src[2107] == 53 &&
	   src[2108] == 48 &&
	   src[2109] == 48)
  {
    /* ---------- this cave has V5 file format ---------- */
    file_version = FILE_VERSION_EM_V5;

    for (i = 0; i < 2048; i++)
      src[i] = remap_v5[src[i]];
    for (i = 2048; i < 2084; i++)
      src[i] = remap_v5[src[i]];
    for (i = 2112; i < 2148; i++)
      src[i] = src[i - 64];
  }
#if 0
  else if (length >= 2106)	/* !!! TEST ONLY: SHOW BROKEN LEVELS !!! */
#else
  else if (length >= 2106 &&
	   src[1983] == 116)
#endif
  {
    /* ---------- this cave has V4 file format ---------- */
    file_version = FILE_VERSION_EM_V4;

    for (i = 0; i < 2048; i++)
      src[i] = remap_v4[src[i]];
    for (i = 2048; i < 2084; i++)
      src[i] = remap_v4eater[src[i] >= 28 ? 0 : src[i]];
    for (i = 2112; i < 2148; i++) src[i] = src[i - 64];
  }
  else if (length >= 2106 &&
	   src[0] == 241 &&	/* <-- Emerald Mine I levels */
	   src[1983] == 27)
  {
    unsigned char j = 94;

    /* ---------- this cave has V3 file format ---------- */
    file_version = FILE_VERSION_EM_V3;

    for (i = 0; i < 2106; i++)
      src[i] = (src[i] ^ (j += 7)) - 0x11;
    src[1] = 131;
    for (i = 0; i < 2048; i++)
      src[i] = remap_v4[src[i]];
    for (i = 2048; i < 2084; i++)
      src[i] = remap_v4eater[src[i] >= 28 ? 0 : src[i]];
    for (i = 2112; i < 2148; i++)
      src[i] = src[i - 64];
  }
#if 1
  else if (length >= 2106 &&
	   src[0] == 245 &&	/* <-- Emerald Mine II levels */
	   src[1983] == 27)
  {
    unsigned char j = 94;

    /* ---------- this cave has V3 file format ---------- */
    file_version = FILE_VERSION_EM_V3;

    for (i = 0; i < 2106; i++)
      src[i] = (src[i] ^ (j += 7)) - 0x11;
    src[1] = 131;
    for (i = 0; i < 2048; i++)
      src[i] = remap_v4[src[i]];
    for (i = 2048; i < 2084; i++)
      src[i] = remap_v4eater[src[i] >= 28 ? 0 : src[i]];
    for (i = 2112; i < 2148; i++)
      src[i] = src[i - 64];

    /* fix copyright sign in Emerald Mine II levels */
    for (i = 0; i < 2048; i++)
      if (src[i] == 241)
	src[i] = 254;		/* replace 'Xdecor_1' with 'Xalpha_copyr' */
  }
#endif
  else
  {
    /* ---------- this cave has unknown file format ---------- */

#if 1
    printf("::: %d, %d\n", src[0], src[1983]);
#endif

    return 0;
  }

  if (file_version < FILE_VERSION_EM_V6)
  {
    /* id */
    src[2106] = 255;
    src[2107] = 54;
    src[2108] = 48;
    src[2109] = 48;

    /* time */
    i = src[2094] * 10;
    src[2110] = i >> 8;
    src[2111] = i;

    for (i = 2148; i < 2172; i++)
      src[i] = 0;

    /* ball data */
    src[2159] = 128;
  }

  /* ---------- at this stage, the cave data always has V6 format ---------- */

  /* fix wheel */
  for (i = 0; i < 2048; i++)
    if (src[i] == 40)
      break;
  for (i++; i < 2048; i++)
    if (src[i] == 40)
      src[i] = 147;

#if 0
  /* fix acid */
  for (i = 64; i < 2048; i++)
    if (src[i] == 63)		/* replace element above 'Xacid_s' ... */
      src[i - 64] = 101;	/* ... with 'Xacid_1' */

#else

  /* fix acid */
  for (i = 64; i < 2048; i++)
  {
    if (src[i] == 63)		/* 'Xacid_s' (acid pool, bottom middle) */
    {
      if (file_version == FILE_VERSION_EM_V4 &&
	  i < 2048 - 64 && src[i + 64] == 63)
	src[i - 64] = 255;	/* replace element above with 'Xfake_acid_1' */
      else
	src[i - 64] = 101;	/* replace element above with 'Xacid_1' */
    }
  }
#endif

  /* fix acid in eater 1 */
  for (i = 2051; i < 2057; i++)
    if (src[i] == 63)
      src[i - 3] = 101;

  /* fix acid in eater 2 */
  for (i = 2060; i < 2066; i++)
    if (src[i] == 63)
      src[i - 3] = 101;

  /* fix acid in eater 3 */
  for (i = 2069; i < 2075; i++)
    if (src[i] == 63)
      src[i - 3] = 101;

  /* fix acid in eater 4 */
  for (i = 2078; i < 2084; i++)
    if (src[i] == 63)
      src[i - 3] = 101;

  /* fix acid in eater 5 */
  for (i = 2115; i < 2121; i++)
    if (src[i] == 63)
      src[i - 3] = 101;

  /* fix acid in eater 6 */
  for (i = 2124; i < 2130; i++)
    if (src[i] == 63)
      src[i - 3] = 101;

  /* fix acid in eater 7 */
  for (i = 2133; i < 2139; i++)
    if (src[i] == 63)
      src[i - 3] = 101;

  /* fix acid in eater 8 */
  for (i = 2142; i < 2148; i++)
    if (src[i] == 63)
      src[i - 3] = 101;

  /* old style time */
  src[2094] = 0;

  /* player 1 pos */
  src[2096] &= 7;
  src[src[2096] << 8 | src[2097]] = 128;

  /* player 2 pos */
  src[2098] &= 7;
  src[src[2098] << 8 | src[2099]] = 128;

  /* amoeba speed */
  if ((src[2100] << 8 | src[2101]) > 9999)
  {
    src[2100] = 39;
    src[2101] = 15;
  }

  /* time wonderwall */
  if ((src[2102] << 8 | src[2103]) > 9999)
  {
    src[2102] = 39;
    src[2103] = 15;
  }

  /* time */
  if ((src[2110] << 8 | src[2111]) > 9999)
  {
    src[2110] = 39;
    src[2111] = 15;
  }

  /* wind direction */
  i = src[2149];
  i &= 15;
  i &= -i;
  src[2149] = i;

  /* time lenses */
  if ((src[2154] << 8 | src[2155]) > 9999)
  {
    src[2154] = 39;
    src[2155] = 15;
  }

  /* time magnify */
  if ((src[2156] << 8 | src[2157]) > 9999)
  {
    src[2156] = 39;
    src[2157] = 15;
  }

  /* ball object */
  src[2158] = 0;
  src[2159] = remap_v6[src[2159]];

  /* ball pause */
  if ((src[2160] << 8 | src[2161]) > 9999)
  {
    src[2160] = 39;
    src[2161] = 15;
  }

  /* ball data */
  src[2162] &= 129;
  if (src[2162] & 1)
    src[2163] = 0;

  /* android move pause */
  if ((src[2164] << 8 | src[2165]) > 9999)
  {
    src[2164] = 39;
    src[2165] = 15;
  }

  /* android clone pause */
  if ((src[2166] << 8 | src[2167]) > 9999)
  {
    src[2166] = 39;
    src[2167] = 15;
  }

  /* android data */
  src[2168] &= 31;

  /* size of v6 cave */
  length = 2172;

#if 1
  if (options.debug)
    printf("::: EM level file version: %d\n", file_version);
#endif

  return file_version;
}

/* 2000-07-30T00:26:00Z
 *
 * Read emerald mine caves version 6
 *
 * v4 and v5 emerald mine caves are converted to v6 (which completely supports
 * older versions)
 * 
 * converting to the internal format loses /significant/ information which can
 * break lots of caves.
 * 
 * major incompatibilities:
 * - borderless caves behave completely differently, the player no longer
 *   "warps" to the other side.
 * - a compile time option for spring can make it behave differently when it
 *   rolls.
 * - a compile time option for rolling objects (stone, nut, spring, bomb) only
 *   in eater.
 * - acid is always deadly even with no base beneath it (this breaks cave 0 in
 *   downunder mine 16)
 *
 * so far all below have not broken any caves:
 *
 * - active wheel inside an eater will not function, eater explosions will not
 *   change settings.
 * - initial collect objects (emerald, diamond, dynamite) don't exist.
 * - initial rolling objects will be moved manually and made into sitting
 *   objects.
 * - drips always appear from dots.
 * - more than one thing can fall into acid at the same time.
 * - acid explodes when the player walks into it, rather than splashing.
 * - simultaneous explosions may be in a slightly different order.
 * - quicksand states have been reduced.
 * - acid base is effectively an indestructable wall now which can affect eater
 *   explosions.
 * - android can clone forever with a clone pause of 0 (emeralds, diamonds,
 *   nuts, stones, bombs, springs).
 *
 * 2001-03-12T02:46:55Z
 * - rolling stuff is now allowed in the cave, i didn't like making this
 *   decision.
 * - if BAD_ROLL is not defined, initial rolling objects are moved by hand.
 * - initial collect objects break some cave in elvis mine 5.
 * - different timing for wonderwall break some cave in exception mine 2.
 * - i think i'm pretty locked into always using the bad roll. *sigh*
 * - rolling spring is now turned into regular spring. it appears the emc
 *   editor only uses the force code for initially moving spring. i will
 *   follow this in my editor.
 */

static unsigned short remap_emerald[256] =
{
  Xstone,		Xstone,		Xdiamond,	Xdiamond,
  Xalien,		Xalien,		Xblank,		Xblank,
  Xtank_n,		Xtank_e,	Xtank_s,	Xtank_w,
  Xtank_gon,		Xtank_goe,	Xtank_gos,	Xtank_gow,

  Xbomb,		Xbomb,		Xemerald,	Xemerald,
  Xbug_n,		Xbug_e,		Xbug_s,		Xbug_w,
  Xbug_gon,		Xbug_goe,	Xbug_gos,	Xbug_gow,
  Xdrip_eat,		Xdrip_eat,	Xdrip_eat,	Xdrip_eat,

  Xstone,		Xbomb,		Xdiamond,	Xemerald,
  Xwonderwall,		Xnut,		Xnut,		Xnut,
  Xwheel,		Xeater_n,	Xeater_s,	Xeater_w,
  Xeater_e,		Xsand_stone,	Xblank,		Xblank,

  Xblank,		Xsand,		Xsand,		Xsand,
  Xsand_stone,		Xsand_stone,	Xsand_stone,	Xsand,
  Xstone,		Xgrow_ew,	Xgrow_ns,	Xdynamite_1,
  Xdynamite_2,		Xdynamite_3,	Xdynamite_4,	Xacid_s,

  Xexit_1,		Xexit_2,	Xexit_3,	Xballoon,
  Xplant,		Xspring,	Xspring,	Xspring,
  Xspring,		Xball_1,	Xball_2,	Xandroid,
  Xblank,		Xandroid,	Xandroid,	Xandroid,

  Xandroid,		Xandroid,	Xandroid,	Xandroid,
  Xandroid,		Xblank,		Xblank,		Xblank,
  Xblank,		Xblank,		Xblank,		Xblank,
  Xblank,		Xblank,		Xblank,		Xblank,

#ifdef BAD_ROLL

  Xblank,		Xblank,		Xblank,		Xspring_force_w,
  Xspring_force_e,	Xacid_1,	Xacid_2,	Xacid_3,
  Xacid_4,		Xacid_5,	Xacid_6,	Xacid_7,
  Xacid_8,		Xblank,		Xblank,		Xblank,

  Xblank,		Xblank,		Xnut_force_w,	Xnut_force_e,
  Xsteel_1,		Xblank,		Xblank,		Xbomb_force_w,
  Xbomb_force_e,	Xstone_force_w,	Xstone_force_e,	Xblank,
  Xblank,		Xblank,		Xblank,		Xblank,

#else

  Xblank,		Xblank,		Xblank,		Xspring,
  Xspring,		Xacid_1,	Xacid_2,	Xacid_3,
  Xacid_4,		Xacid_5,	Xacid_6,	Xacid_7,
  Xacid_8,		Xblank,		Xblank,		Xblank,

  Xblank,		Xblank,		Xnut,		Xnut,
  Xsteel_1,		Xblank,		Xblank,		Xbomb,
  Xbomb,		Xstone,		Xstone,		Xblank,
  Xblank,		Xblank,		Xblank,		Xblank,

#endif

  Xblank,		Xround_wall_1,	Xgrass,		Xsteel_1,
  Xwall_1,		Xkey_1,		Xkey_2,		Xkey_3,
  Xkey_4,		Xdoor_1,	Xdoor_2,	Xdoor_3,
  Xdoor_4,		Xdripper,	Xfake_door_1,	Xfake_door_2,

  Xfake_door_3,		Xfake_door_4,	Xwonderwall,	Xwheel,
  Xsand,		Xacid_nw,	Xacid_ne,	Xacid_sw,
  Xacid_se,		Xfake_blank,	Xamoeba_1,	Xamoeba_2,
  Xamoeba_3,		Xamoeba_4,	Xexit,		Xalpha_arrow_w,

  Xfake_grass,		Xlenses,	Xmagnify,	Xfake_blank,
  Xfake_grass,		Xswitch,	Xswitch,	Xblank,
  Xdecor_8,		Xdecor_9,	Xdecor_10,	Xdecor_5,
  Xalpha_comma,		Xalpha_quote,	Xalpha_minus,	Xdynamite,

  Xsteel_3,		Xdecor_6,	Xdecor_7,	Xsteel_2,
  Xround_wall_2,	Xdecor_2,	Xdecor_4,	Xdecor_3,
  Xwind_nesw,		Xwind_e,	Xwind_s,	Xwind_w,
  Xwind_n,		Xdirt,		Xplant,		Xkey_5,

  Xkey_6,		Xkey_7,		Xkey_8,		Xdoor_5,
  Xdoor_6,		Xdoor_7,	Xdoor_8,	Xbumper,
  Xalpha_a,		Xalpha_b,	Xalpha_c,	Xalpha_d,
  Xalpha_e,		Xalpha_f,	Xalpha_g,	Xalpha_h,

  Xalpha_i,		Xalpha_j,	Xalpha_k,	Xalpha_l,
  Xalpha_m,		Xalpha_n,	Xalpha_o,	Xalpha_p,
  Xalpha_q,		Xalpha_r,	Xalpha_s,	Xalpha_t,
  Xalpha_u,		Xalpha_v,	Xalpha_w,	Xalpha_x,

  Xalpha_y,		Xalpha_z,	Xalpha_0,	Xalpha_1,
  Xalpha_2,		Xalpha_3,	Xalpha_4,	Xalpha_5,
  Xalpha_6,		Xalpha_7,	Xalpha_8,	Xalpha_9,
  Xalpha_perio,		Xalpha_excla,	Xalpha_colon,	Xalpha_quest,

  Xalpha_arrow_e,	Xdecor_1,	Xfake_door_5,	Xfake_door_6,
  Xfake_door_7,		Xfake_door_8,	Xblank,		Xblank,
  Xblank,		Xblank,		Xblank,		Xblank,
#if 0
  Xblank,		Xblank,		Xblank,		Xblank,
#else
  /* special elements added to solve compatibility problems */
  Xblank,		Xblank,		Xalpha_copyr,	Xfake_acid_1
#endif
};

void convert_em_level(unsigned char *src, int file_version)
{
  static int eater_offset[8] =
  {
    0x800, 0x809, 0x812, 0x81B, 0x840, 0x849, 0x852, 0x85B
  };
  int i, x, y, temp;

#if 1
  lev.time_seconds = src[0x83E] << 8 | src[0x83F];
  if (lev.time_seconds > 9999)
    lev.time_seconds = 9999;
#else
  temp = ((src[0x83E] << 8 | src[0x83F]) * 25 + 3) / 4;
  if (temp == 0 || temp > 9999)
    temp = 9999;
  lev.time_initial = temp;
#endif

  lev.required_initial = src[0x82F];

  for (i = 0; i < 2; i++)
  {
    temp = src[0x830 + i * 2] << 8 | src[0x831 + i * 2];
    ply[i].x_initial = (temp & 63) + 1;
    ply[i].y_initial = (temp >> 6 & 31) + 1;
  }

  temp = (src[0x834] << 8 | src[0x835]) * 28;
  if (temp > 9999)
    temp = 9999;
  lev.amoeba_time = temp;

  lev.android_move_time = src[0x874] << 8 | src[0x875];
  lev.android_clone_time = src[0x876] << 8 | src[0x877];

  lev.ball_random = src[0x872] & 1 ? 1 : 0;
  lev.ball_state_initial = src[0x872] & 128 ? 1 : 0;
  lev.ball_time = src[0x870] << 8 | src[0x871];

  lev.emerald_score = src[0x824];
  lev.diamond_score = src[0x825];
  lev.alien_score = src[0x826];
  lev.tank_score = src[0x827];
  lev.bug_score = src[0x828];
  lev.eater_score = src[0x829];
  lev.nut_score = src[0x82A];
  lev.dynamite_score = src[0x82B];
  lev.key_score = src[0x82C];
  lev.exit_score = src[0x82D] * 8 / 5;
  lev.lenses_score = src[0x867];
  lev.magnify_score = src[0x868];
  lev.slurp_score = src[0x869];

  lev.lenses_time = src[0x86A] << 8 | src[0x86B];
  lev.magnify_time = src[0x86C] << 8 | src[0x86D];
  lev.wheel_time = src[0x838] << 8 | src[0x839];

  lev.wind_cnt_initial = src[0x865] & 15 ? lev.wind_time : 0;
  temp = src[0x865];
  lev.wind_direction_initial = (temp & 8 ? 0 :
				temp & 1 ? 1 :
				temp & 2 ? 2 :
				temp & 4 ? 3 : 0);

  lev.wonderwall_time_initial = src[0x836] << 8 | src[0x837];

  for (i = 0; i < 8; i++)
    for (x = 0; x < 9; x++)
      lev.eater_array[i][x] = remap_emerald[src[eater_offset[i] + x]];

  temp = remap_emerald[src[0x86F]];
  for (y = 0; y < 8; y++)
  {
    if (src[0x872] & 1)
    {
      for (x = 0; x < 8; x++)
	lev.ball_array[y][x] = temp;
    }
    else
    {
      lev.ball_array[y][1] = (src[0x873] & 1)  ? temp : Xblank; /* north */
      lev.ball_array[y][6] = (src[0x873] & 2)  ? temp : Xblank; /* south */
      lev.ball_array[y][3] = (src[0x873] & 4)  ? temp : Xblank; /* west */
      lev.ball_array[y][4] = (src[0x873] & 8)  ? temp : Xblank; /* east */
      lev.ball_array[y][7] = (src[0x873] & 16) ? temp : Xblank; /* southeast */
      lev.ball_array[y][5] = (src[0x873] & 32) ? temp : Xblank; /* southwest */
      lev.ball_array[y][2] = (src[0x873] & 64) ? temp : Xblank; /* northeast */
      lev.ball_array[y][0] = (src[0x873] & 128)? temp : Xblank; /* northwest */
    }
  }

  temp = src[0x878] << 8 | src[0x879];

  if (temp & 1)
  {
    lev.android_array[Xemerald]		= Xemerald;
    lev.android_array[Xemerald_pause]	= Xemerald;
    lev.android_array[Xemerald_fall]	= Xemerald;
    lev.android_array[Yemerald_sB]	= Xemerald;
    lev.android_array[Yemerald_eB]	= Xemerald;
    lev.android_array[Yemerald_wB]	= Xemerald;
  }

  if (temp & 2)
  {
    lev.android_array[Xdiamond]		= Xdiamond;
    lev.android_array[Xdiamond_pause]	= Xdiamond;
    lev.android_array[Xdiamond_fall]	= Xdiamond;
    lev.android_array[Ydiamond_sB]	= Xdiamond;
    lev.android_array[Ydiamond_eB]	= Xdiamond;
    lev.android_array[Ydiamond_wB]	= Xdiamond;
  }

  if (temp & 4)
  {
    lev.android_array[Xstone]		= Xstone;
    lev.android_array[Xstone_pause]	= Xstone;
    lev.android_array[Xstone_fall]	= Xstone;
    lev.android_array[Ystone_sB]	= Xstone;
    lev.android_array[Ystone_eB]	= Xstone;
    lev.android_array[Ystone_wB]	= Xstone;
  }

  if (temp & 8)
  {
    lev.android_array[Xbomb]		= Xbomb;
    lev.android_array[Xbomb_pause]	= Xbomb;
    lev.android_array[Xbomb_fall]	= Xbomb;
    lev.android_array[Ybomb_sB]		= Xbomb;
    lev.android_array[Ybomb_eB]		= Xbomb;
    lev.android_array[Ybomb_wB]		= Xbomb;
  }

  if (temp & 16)
  {
    lev.android_array[Xnut]		= Xnut;
    lev.android_array[Xnut_pause]	= Xnut;
    lev.android_array[Xnut_fall]	= Xnut;
    lev.android_array[Ynut_sB]		= Xnut;
    lev.android_array[Ynut_eB]		= Xnut;
    lev.android_array[Ynut_wB]		= Xnut;
  }

  if (temp & 32)
  {
    lev.android_array[Xtank_n]		= Xtank_n;
    lev.android_array[Xtank_gon]	= Xtank_n;
    lev.android_array[Ytank_nB]		= Xtank_n;
    lev.android_array[Ytank_n_e]	= Xtank_n;
    lev.android_array[Ytank_n_w]	= Xtank_n;

    lev.android_array[Xtank_e]		= Xtank_e;
    lev.android_array[Xtank_goe]	= Xtank_e;
    lev.android_array[Ytank_eB]		= Xtank_e;
    lev.android_array[Ytank_e_s]	= Xtank_e;
    lev.android_array[Ytank_e_n]	= Xtank_e;

    lev.android_array[Xtank_s]		= Xtank_s;
    lev.android_array[Xtank_gos]	= Xtank_s;
    lev.android_array[Ytank_sB]		= Xtank_s;
    lev.android_array[Ytank_s_w]	= Xtank_s;
    lev.android_array[Ytank_s_e]	= Xtank_s;

    lev.android_array[Xtank_w]		= Xtank_w;
    lev.android_array[Xtank_gow]	= Xtank_w;
    lev.android_array[Ytank_wB]		= Xtank_w;
    lev.android_array[Ytank_w_n]	= Xtank_w;
    lev.android_array[Ytank_w_s]	= Xtank_w;
  }

  if (temp & 64)
  {
    lev.android_array[Xeater_n]		= Xeater_n;
    lev.android_array[Yeater_nB]	= Xeater_n;

    lev.android_array[Xeater_e]		= Xeater_e;
    lev.android_array[Yeater_eB]	= Xeater_e;

    lev.android_array[Xeater_s]		= Xeater_s;
    lev.android_array[Yeater_sB]	= Xeater_s;

    lev.android_array[Xeater_w]		= Xeater_w;
    lev.android_array[Yeater_wB]	= Xeater_w;
  }

  if (temp & 128)
  {
    lev.android_array[Xbug_n]		= Xbug_gon;
    lev.android_array[Xbug_gon]		= Xbug_gon;
    lev.android_array[Ybug_nB]		= Xbug_gon;
    lev.android_array[Ybug_n_e]		= Xbug_gon;
    lev.android_array[Ybug_n_w]		= Xbug_gon;

    lev.android_array[Xbug_e]		= Xbug_goe;
    lev.android_array[Xbug_goe]		= Xbug_goe;
    lev.android_array[Ybug_eB]		= Xbug_goe;
    lev.android_array[Ybug_e_s]		= Xbug_goe;
    lev.android_array[Ybug_e_n]		= Xbug_goe;

    lev.android_array[Xbug_s]		= Xbug_gos;
    lev.android_array[Xbug_gos]		= Xbug_gos;
    lev.android_array[Ybug_sB]		= Xbug_gos;
    lev.android_array[Ybug_s_w]		= Xbug_gos;
    lev.android_array[Ybug_s_e]		= Xbug_gos;

    lev.android_array[Xbug_w]		= Xbug_gow;
    lev.android_array[Xbug_gow]		= Xbug_gow;
    lev.android_array[Ybug_wB]		= Xbug_gow;
    lev.android_array[Ybug_w_n]		= Xbug_gow;
    lev.android_array[Ybug_w_s]		= Xbug_gow;
  }

  if (temp & 256)
  {
    lev.android_array[Xalien]		= Xalien;
    lev.android_array[Xalien_pause]	= Xalien;
    lev.android_array[Yalien_nB]	= Xalien;
    lev.android_array[Yalien_eB]	= Xalien;
    lev.android_array[Yalien_sB]	= Xalien;
    lev.android_array[Yalien_wB]	= Xalien;
  }

  if (temp & 512)
  {
    lev.android_array[Xspring]		= Xspring;
    lev.android_array[Xspring_pause]	= Xspring;
    lev.android_array[Xspring_e]	= Xspring;
    lev.android_array[Yspring_eB]	= Xspring;
    lev.android_array[Yspring_kill_eB]	= Xspring;
    lev.android_array[Xspring_w]	= Xspring;
    lev.android_array[Yspring_wB]	= Xspring;
    lev.android_array[Yspring_kill_wB]	= Xspring;
    lev.android_array[Xspring_fall]	= Xspring;
    lev.android_array[Yspring_sB]	= Xspring;
  }

  if (temp & 1024)
  {
    lev.android_array[Yballoon_nB]	= Xballoon;
    lev.android_array[Yballoon_eB]	= Xballoon;
    lev.android_array[Yballoon_sB]	= Xballoon;
    lev.android_array[Yballoon_wB]	= Xballoon;
    lev.android_array[Xballoon]		= Xballoon;
  }

  if (temp & 2048)
  {
    lev.android_array[Xdripper]		= Xdrip_eat;
    lev.android_array[XdripperB]	= Xdrip_eat;
    lev.android_array[Xamoeba_1]	= Xdrip_eat;
    lev.android_array[Xamoeba_2]	= Xdrip_eat;
    lev.android_array[Xamoeba_3]	= Xdrip_eat;
    lev.android_array[Xamoeba_4]	= Xdrip_eat;
    lev.android_array[Xamoeba_5]	= Xdrip_eat;
    lev.android_array[Xamoeba_6]	= Xdrip_eat;
    lev.android_array[Xamoeba_7]	= Xdrip_eat;
    lev.android_array[Xamoeba_8]	= Xdrip_eat;
  }

  if (temp & 4096)
  {
    lev.android_array[Xdynamite]	= Xdynamite;
  }

  for (temp = 1; temp < 2047; temp++)
  {
    switch (src[temp])
    {
      case 0x24:				/* wonderwall */
	lev.wonderwall_state_initial = 1;
	lev.wonderwall_time_initial = 9999;
	break;

      case 0x28:				/* wheel */
	lev.wheel_x_initial = temp & 63;
	lev.wheel_y_initial = temp >> 6;
	lev.wheel_cnt_initial = lev.wheel_time;
	break;

#ifndef BAD_ROLL
      case 0x63:				/* spring roll left */
	src[temp - 1] = 0x45;
	src[temp] = 0x80;
	break;

      case 0x64:				/* spring roll right */
	src[temp + 1] = 0x45;
	src[temp] = 0x80;
	break;

      case 0x72:				/* nut roll left */
	src[temp - 1] = 0x25;
	src[temp] = 0x80;
	break;

      case 0x73:				/* nut roll right */
	src[temp + 1] = 0x25;
	src[temp] = 0x80;
	break;

      case 0x77:				/* bomb roll left */
	src[temp - 1] = 0x10;
	src[temp] = 0x80;
	break;

      case 0x78:				/* bomb roll right */
	src[temp + 1] = 0x10;
	src[temp] = 0x80;
	break;

      case 0x79:				/* stone roll left */
	src[temp - 1] = 0x00;
	src[temp] = 0x80;
	break;

      case 0x7A:				/* stone roll right */
	src[temp + 1] = 0x00;
	src[temp] = 0x80;
	break;
#endif

      case 0xA3:				/* fake blank */
	lev.lenses_cnt_initial = 9999;
	break;

      case 0xA4:				/* fake grass */
	lev.magnify_cnt_initial = 9999;
	break;
    }
  }

  /* first fill the complete playfield with the default border element */
  for (y = 0; y < HEIGHT; y++)
    for (x = 0; x < WIDTH; x++)
      native_em_level.cave[x][y] = ZBORDER;

  /* then copy the real level contents from level file into the playfield */
  temp = 0;
  for (y = 0; y < lev.height; y++)
    for (x = 0; x < lev.width; x++)
      native_em_level.cave[x + 1][y + 1] = remap_emerald[src[temp++]];

  /* at last, set the two players at their positions in the playfield */
  /* (native EM[C] levels always have exactly two players in a level) */
#if 1
  for (i = 0; i < 2; i++)
    native_em_level.cave[ply[i].x_initial][ply[i].y_initial] = Zplayer;
#else
  for (i = 0; i < 2; i++)
    if (ply[i].alive_initial)
      native_em_level.cave[ply[i].x_initial][ply[i].y_initial] = Zplayer;
#endif

  native_em_level.file_version = file_version;
}

void prepare_em_level(void)
{
  int i, x, y;
  int players_left;
  int num_tape_players;

  /* reset all runtime variables to their initial values */

  for (y = 0; y < HEIGHT; y++)
    for (x = 0; x < WIDTH; x++)
      Cave[y][x] = native_em_level.cave[x][y];

  for (y = 0; y < HEIGHT; y++)
    for (x = 0; x < WIDTH; x++)
      Next[y][x] = Cave[y][x];

  for (y = 0; y < HEIGHT; y++)
    for (x = 0; x < WIDTH; x++)
      Draw[y][x] = Cave[y][x];

#if 1
  lev.time_initial = lev.time_seconds;
#else
  lev.time_initial = (lev.time_seconds * 50 + 7) / 8;
#endif
  lev.time = lev.time_initial;

  lev.required = lev.required_initial;
  lev.score = 0;

  lev.android_move_cnt  = lev.android_move_time;
  lev.android_clone_cnt = lev.android_clone_time;

  lev.ball_pos = 0;
  lev.ball_state = lev.ball_state_initial;
  lev.ball_cnt = lev.ball_time;

  lev.eater_pos = 0;
  lev.shine_cnt = 0;

  lev.lenses_cnt = lev.lenses_cnt_initial;
  lev.magnify_cnt = lev.magnify_cnt_initial;

  lev.wheel_cnt = lev.wheel_cnt_initial;
  lev.wheel_x   = lev.wheel_x_initial;
  lev.wheel_y   = lev.wheel_y_initial;

  lev.wind_direction = lev.wind_direction_initial;
  lev.wind_cnt       = lev.wind_cnt_initial;

  lev.wonderwall_state = lev.wonderwall_state_initial;
  lev.wonderwall_time  = lev.wonderwall_time_initial;

  lev.killed_out_of_time = FALSE;

  /* determine number of players in this level */
  lev.home_initial = 0;

  for (i = 0; i < MAX_PLAYERS; i++)
  {
    ply[i].exists = 0;
    ply[i].alive_initial = FALSE;

    if (ply[i].x_initial > 0 && ply[i].y_initial > 0)
    {
      ply[i].exists = 1;

      lev.home_initial++;
    }
  }

  num_tape_players = getNumActivePlayers_EM();

  if (num_tape_players != -1)
    lev.home_initial = MIN(lev.home_initial, num_tape_players);
  else if (!setup.team_mode)
    lev.home_initial = MIN(lev.home_initial, 1);

  lev.home = lev.home_initial;
  players_left = lev.home_initial;

  for (i = 0; i < MAX_PLAYERS; i++)
  {
    if (ply[i].exists)
    {
      if (players_left)
      {
	ply[i].alive_initial = TRUE;
	players_left--;
      }
      else
      {
	int x = ply[i].x_initial;
	int y = ply[i].y_initial;

	native_em_level.cave[x][y] = Xblank;

	Cave[y][x] = Next[y][x] = Draw[y][x] = Xblank;
      }
    }
  }

  for (i = 0; i < MAX_PLAYERS; i++)
  {
    ply[i].num = i;
    ply[i].alive = ply[i].alive_initial;
    ply[i].dynamite = 0;
    ply[i].dynamite_cnt = 0;
    ply[i].keys = 0;
    ply[i].anim = 0;
    ply[i].oldx = ply[i].x = ply[i].x_initial;
    ply[i].oldy = ply[i].y = ply[i].y_initial;
    ply[i].last_move_dir = MV_NONE;
    ply[i].joy_n = ply[i].joy_e = ply[i].joy_s = ply[i].joy_w = 0;
    ply[i].joy_snap  = ply[i].joy_drop = 0;
    ply[i].joy_stick = ply[i].joy_spin = 0;

#if 0
    printf("player %d: x/y == %d/%d, alive == %d\n",
	   i, ply[i].x_initial, ply[i].y_initial, ply[i].alive);
#endif
  }

  game_em.any_player_moving = FALSE;
  game_em.last_moving_player = 0;	/* default: first player */

  for (i = 0; i < MAX_PLAYERS; i++)
    game_em.last_player_direction[i] = MV_NONE;
}
