rnd-20060207-1-src
authorHolger Schemel <info@artsoft.org>
Tue, 7 Feb 2006 00:30:12 +0000 (01:30 +0100)
committerHolger Schemel <info@artsoft.org>
Sat, 30 Aug 2014 08:50:39 +0000 (10:50 +0200)
* improved screen redraw for EMC graphics engine (faster and smoother)
* when not scrolling, do not redraw the whole playfield if not needed
* added multi-player mode for EMC game engine (with up to four players)

18 files changed:
ChangeLog
src/conftime.h
src/files.c
src/game.c
src/game_em/cave.c
src/game_em/convert.c
src/game_em/game_em.h
src/game_em/global.h
src/game_em/graphics.c
src/game_em/input.c
src/game_em/level.h
src/game_em/main_em.h
src/game_em/synchro_1.c
src/game_em/synchro_2.c
src/game_em/tab_generate.c
src/main.c
src/screens.c
src/tools.c

index 253e6ec8ead2865e3e60850be9fff4b117cd2ab3..66f05732effd9c7cdb85f71b7ad3639483689a10 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,10 @@
+2006-02-06
+       * improved screen redraw for EMC graphics engine (faster and smoother)
+       * when not scrolling, do not redraw the whole playfield if not needed
+
+2006-02-03
+       * added multi-player mode for EMC game engine (with up to four players)
+
 2006-01-28
        * added android (can clone elements) from EMC engine to R'n'D engine
 
index 9b40c697bfde0be874694385e824bd43232222bd..3a96329a7a9ac26c70adb078dae67561fe9d3ed3 100644 (file)
@@ -1 +1 @@
-#define COMPILE_DATE_STRING "[2006-02-03 19:01]"
+#define COMPILE_DATE_STRING "[2006-02-07 01:20]"
index 6b395bf0cd7e8c1eed3b49a382ef5c1ab8e88d11..4ff5c649111b360048c5c64e7f93413a91bec749 100644 (file)
@@ -2389,10 +2389,17 @@ void CopyNativeLevel_RND_to_EM(struct LevelInfo *level)
   };
   struct LevelInfo_EM *level_em = level->native_em_level;
   struct LEVEL *lev = level_em->lev;
-  struct PLAYER *ply1 = level_em->ply1;
-  struct PLAYER *ply2 = level_em->ply2;
+  struct PLAYER **ply = level_em->ply;
   int i, j, x, y;
 
+#if 0
+  printf("::: A\n");
+  for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
+    for (j = 0; j < 8; j++)
+      printf("::: ball %d, %d: %d\n", i, j,
+            level->ball_content[i].e[ball_xy[j][0]][ball_xy[j][1]]);
+#endif
+
   lev->width  = MIN(level->fieldx, EM_MAX_CAVE_WIDTH);
   lev->height = MIN(level->fieldy, EM_MAX_CAVE_HEIGHT);
 
@@ -2445,6 +2452,13 @@ void CopyNativeLevel_RND_to_EM(struct LevelInfo *level)
        map_element_RND_to_EM(level->
                              ball_content[i].e[ball_xy[j][0]][ball_xy[j][1]]);
 
+#if 0
+  for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
+    for (j = 0; j < 8; j++)
+      printf("::: ball %d, %d: %d\n", i, j,
+            level->ball_content[i].e[ball_xy[j][0]][ball_xy[j][1]]);
+#endif
+
   map_android_clone_elements_RND_to_EM(level);
 
 #if 0
@@ -2468,15 +2482,42 @@ void CopyNativeLevel_RND_to_EM(struct LevelInfo *level)
     level_em->cave[x + 1][y + 1] = new_element;
   }
 
+#if 1
+
+  for (i = 0; i < MAX_PLAYERS; i++)
+  {
+    ply[i]->x_initial = 0;
+    ply[i]->y_initial = 0;
+  }
+
+#else
+
   ply1->x_initial = 0;
   ply1->y_initial = 0;
 
   ply2->x_initial = 0;
   ply2->y_initial = 0;
 
+#endif
+
   /* initialize player positions and delete players from the playfield */
   for (y = 0; y < lev->height; y++) for (x = 0; x < lev->width; x++)
   {
+
+#if 1
+
+    if (ELEM_IS_PLAYER(level->field[x][y]))
+    {
+      int player_nr = GET_PLAYER_NR(level->field[x][y]);
+
+      ply[player_nr]->x_initial = x + 1;
+      ply[player_nr]->y_initial = y + 1;
+
+      level_em->cave[x + 1][y + 1] = map_element_RND_to_EM(EL_EMPTY);
+    }
+
+#else
+
 #if 1
     /* !!! CURRENTLY ONLY SUPPORT FOR ONE PLAYER !!! */
     if (ELEM_IS_PLAYER(level->field[x][y]))
@@ -2500,6 +2541,9 @@ void CopyNativeLevel_RND_to_EM(struct LevelInfo *level)
       level_em->cave[x + 1][y + 1] = map_element_RND_to_EM(EL_EMPTY);
     }
 #endif
+
+#endif
+
   }
 }
 
@@ -2518,8 +2562,7 @@ void CopyNativeLevel_EM_to_RND(struct LevelInfo *level)
   };
   struct LevelInfo_EM *level_em = level->native_em_level;
   struct LEVEL *lev = level_em->lev;
-  struct PLAYER *ply1 = level_em->ply1;
-  struct PLAYER *ply2 = level_em->ply2;
+  struct PLAYER **ply = level_em->ply;
   int i, j, x, y;
 
   level->fieldx = MIN(lev->width,  MAX_LEV_FIELDX);
@@ -2570,11 +2613,27 @@ void CopyNativeLevel_EM_to_RND(struct LevelInfo *level)
   level->wind_direction_initial =
     map_direction_EM_to_RND(lev->wind_direction_initial);
 
+#if 0
+  printf("::: foo\n");
+  for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
+    for (j = 0; j < 8; j++)
+      printf("::: ball %d, %d: %d\n", i, j,
+            level->ball_content[i].e[ball_xy[j][0]][ball_xy[j][1]]);
+#endif
+
   for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
     for (j = 0; j < 8; j++)
       level->ball_content[i].e[ball_xy[j][0]][ball_xy[j][1]] =
        map_element_EM_to_RND(lev->ball_array[i][j]);
 
+#if 0
+  printf("::: bar\n");
+  for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
+    for (j = 0; j < 8; j++)
+      printf("::: ball %d, %d: %d\n", i, j,
+            level->ball_content[i].e[ball_xy[j][0]][ball_xy[j][1]]);
+#endif
+
   map_android_clone_elements_EM_to_RND(level);
 
 #if 0
@@ -2593,13 +2652,50 @@ void CopyNativeLevel_EM_to_RND(struct LevelInfo *level)
     level->field[x][y] = new_element;
   }
 
+#if 0
+  printf("::: bar 0\n");
+  for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
+    for (j = 0; j < 8; j++)
+      printf("::: ball %d, %d: %d\n", i, j,
+            level->ball_content[i].e[ball_xy[j][0]][ball_xy[j][1]]);
+#endif
+
+#if 1
+
+  for (i = 0; i < MAX_PLAYERS; i++)
+  {
+    /* in case of all players set to the same field, use the first player */
+    int nr = MAX_PLAYERS - i - 1;
+    int jx = ply[nr]->x_initial - 1;
+    int jy = ply[nr]->y_initial - 1;
+
+#if 0
+    printf("::: player %d: %d, %d\n", nr, jx, jy);
+#endif
+
+    if (jx != -1 && jy != -1)
+      level->field[jx][jy] = EL_PLAYER_1 + nr;
+  }
+
+#else
+
   /* in case of both players set to the same field, use the first player */
   level->field[ply2->x_initial - 1][ply2->y_initial - 1] = EL_PLAYER_2;
   level->field[ply1->x_initial - 1][ply1->y_initial - 1] = EL_PLAYER_1;
 
+#endif
+
 #if 0
   printf("::: native Emerald Mine file version: %d\n", level_em->file_version);
 #endif
+
+#if 0
+  printf("::: bar 2\n");
+  for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
+    for (j = 0; j < 8; j++)
+      printf("::: ball %d, %d: %d\n", i, j,
+            level->ball_content[i].e[ball_xy[j][0]][ball_xy[j][1]]);
+#endif
 }
 
 static void LoadLevelFromFileInfo_EM(struct LevelInfo *level,
@@ -2617,6 +2713,30 @@ void CopyNativeLevel_RND_to_Native(struct LevelInfo *level)
 
 void CopyNativeLevel_Native_to_RND(struct LevelInfo *level)
 {
+
+#if 0
+  {
+    static int ball_xy[8][2] =
+      {
+       { 0, 0 },
+       { 1, 0 },
+       { 2, 0 },
+       { 0, 1 },
+       { 2, 1 },
+       { 0, 2 },
+       { 1, 2 },
+       { 2, 2 },
+      };
+    int i, j;
+
+    printf("::: A6\n");
+    for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
+      for (j = 0; j < 8; j++)
+       printf("::: ball %d, %d: %d\n", i, j,
+              level->ball_content[i].e[ball_xy[j][0]][ball_xy[j][1]]);
+  }
+#endif
+
   if (level->game_engine_type == GAME_ENGINE_TYPE_EM)
     CopyNativeLevel_EM_to_RND(level);
 }
index 5d3e9844a4aee204ca3a48ec6bb534e2c5023c5d..a18c80bdd1b8d0793488ec55b1d87aa943cdd52b 100644 (file)
@@ -293,6 +293,8 @@ static void TestIfElementSmashesCustomElement(int, int, int);
 #endif
 
 static void HandleElementChange(int, int, int);
+static void ExecuteCustomElementAction(int, int, int, int);
+static boolean ChangeElement(int, int, int, int);
 
 static boolean CheckTriggeredElementChangeExt(int, int, int, int, int,int,int);
 #define CheckTriggeredElementChange(x, y, e, ev)                       \
@@ -2814,14 +2816,33 @@ static void ResetRandomAnimationValue(int x, int y)
 
 static void ResetGfxAnimation(int x, int y)
 {
+#if 0
+  int element, graphic;
+#endif
+
   GfxFrame[x][y] = 0;
   GfxAction[x][y] = ACTION_DEFAULT;
   GfxDir[x][y] = MovDir[x][y];
+
+#if 0
+  element = Feld[x][y];
+  graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
+
+  if (graphic_info[graphic].anim_global_sync)
+    GfxFrame[x][y] = FrameCounter;
+  else if (ANIM_MODE(graphic) == ANIM_CE_VALUE)
+    GfxFrame[x][y] = CustomValue[x][y];
+  else if (ANIM_MODE(graphic) == ANIM_CE_SCORE)
+    GfxFrame[x][y] = element_info[element].collect_score;
+#endif
 }
 
 void InitMovingField(int x, int y, int direction)
 {
   int element = Feld[x][y];
+#if 0
+  int graphic;
+#endif
   int dx = (direction == MV_LEFT ? -1 : direction == MV_RIGHT ? +1 : 0);
   int dy = (direction == MV_UP   ? -1 : direction == MV_DOWN  ? +1 : 0);
   int newx = x + dx;
@@ -2835,6 +2856,17 @@ void InitMovingField(int x, int y, int direction)
   GfxAction[x][y] = (direction == MV_DOWN && CAN_FALL(element) ?
                     ACTION_FALLING : ACTION_MOVING);
 
+#if 0
+  graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
+
+  if (graphic_info[graphic].anim_global_sync)
+    GfxFrame[x][y] = FrameCounter;
+  else if (ANIM_MODE(graphic) == ANIM_CE_VALUE)
+    GfxFrame[x][y] = CustomValue[x][y];
+  else if (ANIM_MODE(graphic) == ANIM_CE_SCORE)
+    GfxFrame[x][y] = element_info[element].collect_score;
+#endif
+
   /* this is needed for CEs with property "can move" / "not moving" */
 
   if (getElementMoveStepsize(x, y) != 0)       /* moving or being moved */
@@ -5262,6 +5294,9 @@ inline static void TurnRoundExt(int x, int y)
 static void TurnRound(int x, int y)
 {
   int direction = MovDir[x][y];
+#if 1
+  int element, graphic;
+#endif
 
   TurnRoundExt(x, y);
 
@@ -5272,6 +5307,18 @@ static void TurnRound(int x, int y)
 
   if (MovDelay[x][y])
     GfxAction[x][y] = ACTION_TURNING_FROM_LEFT + MV_DIR_TO_BIT(direction);
+
+#if 1
+  element = Feld[x][y];
+  graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
+
+  if (graphic_info[graphic].anim_global_sync)
+    GfxFrame[x][y] = FrameCounter;
+  else if (ANIM_MODE(graphic) == ANIM_CE_VALUE)
+    GfxFrame[x][y] = CustomValue[x][y];
+  else if (ANIM_MODE(graphic) == ANIM_CE_SCORE)
+    GfxFrame[x][y] = element_info[element].collect_score;
+#endif
 }
 
 static boolean JustBeingPushed(int x, int y)
@@ -6449,6 +6496,28 @@ void ContinueMoving(int x, int y)
 
   TestIfElementTouchesCustomElement(x, y);     /* empty or new element */
 
+#if 0
+  if (ChangePage[newx][newy] != -1)            /* delayed change */
+  {
+    int page = ChangePage[newx][newy];
+    struct ElementChangeInfo *change = &ei->change_page[page];
+
+    ChangePage[newx][newy] = -1;
+
+    if (change->can_change)
+    {
+      if (ChangeElement(newx, newy, element, page))
+      {
+        if (change->post_change_function)
+          change->post_change_function(newx, newy);
+      }
+    }
+
+    if (change->has_action)
+      ExecuteCustomElementAction(newx, newy, element, page);
+  }
+#endif
+
   TestIfElementHitsCustomElement(newx, newy, direction);
   TestIfPlayerTouchesCustomElement(newx, newy);
   TestIfElementTouchesCustomElement(newx, newy);
@@ -7790,6 +7859,10 @@ static void ExecuteCustomElementAction(int x, int y, int element, int page)
 
        CheckElementChange(x, y, element, EL_UNDEFINED, CE_VALUE_GETS_ZERO);
        CheckTriggeredElementChange(x, y, element, CE_VALUE_GETS_ZERO_OF_X);
+
+#if 0
+       printf("::: RESULT: %d, %d\n", Feld[x][y], ChangePage[x][y]);
+#endif
       }
 #endif
 
@@ -8339,8 +8412,20 @@ static boolean CheckElementChangeExt(int x, int y,
     element = Feld[x][y];
   }
 
-  if (Feld[x][y] != element)   /* check if element has already changed */
+#if 0
+  /* check if element has already changed */
+  if (Feld[x][y] != element)
     return FALSE;
+#else
+  /* check if element has already changed or is about to change after moving */
+  if ((game.engine_version < VERSION_IDENT(3,2,0,7) &&
+       Feld[x][y] != element) ||
+
+      (game.engine_version >= VERSION_IDENT(3,2,0,7) &&
+       (ChangeCount[x][y] >= game.max_num_changes_per_frame ||
+       ChangePage[x][y] != -1)))
+    return FALSE;
+#endif
 
   for (p = 0; p < element_info[element].num_change_pages; p++)
   {
index 08c28ec22de4ccd631f2c0d0d85f5fd70b1d3230..47f7315eaeab5358bce2c7c8651748e91e2627ec 100644 (file)
@@ -17,17 +17,17 @@ void setLevelInfoToDefaults_EM(void)
   native_em_level.file_version = FILE_VERSION_EM_ACTUAL;
 
   native_em_level.lev = &lev;
-  native_em_level.ply1 = &ply1;
-  native_em_level.ply2 = &ply2;
+  for (i = 0; i < MAX_PLAYERS; i++)
+    native_em_level.ply[i] = &ply[i];
 
   lev.width = 64;
   lev.height = 32;
 
-  ply1.x_initial = 0;
-  ply1.y_initial = 0;
-
-  ply2.x_initial = 0;
-  ply2.y_initial = 0;
+  for (i = 0; i < MAX_PLAYERS; i++)
+  {
+    ply[i].x_initial = 0;
+    ply[i].y_initial = 0;
+  }
 
   lev.lenses_cnt_initial = 0;
   lev.magnify_cnt_initial = 0;
@@ -47,10 +47,25 @@ void setLevelInfoToDefaults_EM(void)
   for (i = 0; i < TILE_MAX; i++)
     lev.android_array[i] = Xblank;
 
-  lev.home_initial = 2;                /* initial number of players in this level */
+#if 1
+  /* initial 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;
+  }
+#else
+  /* initial number of players in this level */
+  lev.home_initial = (setup.team_mode ? 2 : 1);
 
-  ply1.alive_initial = (lev.home_initial >= 1);
-  ply2.alive_initial = (lev.home_initial >= 2);
+  for (i = 0; i < MAX_PLAYERS; i++)
+  {
+    ply[i].exists = 0;
+    ply[i].alive_initial = (lev.home_initial > i ? TRUE : FALSE);
+  }
+#endif
 }
 
 
index 3c714c6e26dab749f7f5a09e3c758fda9aaffd2e..7b3b036aa1c7b9ad6daf4abf3d975aedb962037b 100644 (file)
@@ -563,12 +563,12 @@ void convert_em_level(unsigned char *src, int file_version)
 
   lev.required_initial = src[0x82F];
 
-  temp = src[0x830] << 8 | src[0x831];
-  ply1.x_initial = (temp & 63) + 1;
-  ply1.y_initial = (temp >> 6 & 31) + 1;
-  temp = src[0x832] << 8 | src[0x833];
-  ply2.x_initial = (temp & 63) + 1;
-  ply2.y_initial = (temp >> 6 & 31) + 1;
+  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)
@@ -886,17 +886,23 @@ void convert_em_level(unsigned char *src, int file_version)
       native_em_level.cave[x + 1][y + 1] = remap_emerald[src[temp++]];
 
   /* at last, set the two players at their positions in the playfield */
-  if (ply1.alive_initial)
-    native_em_level.cave[ply1.x_initial][ply1.y_initial] = Zplayer;
-  if (ply2.alive_initial)
-    native_em_level.cave[ply2.x_initial][ply2.y_initial] = Zplayer;
+  /* (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)
 {
-  unsigned int x, y;
+  unsigned int i, x, y;
+  int players_left;
 
   /* reset all runtime variables to their initial values */
 
@@ -945,33 +951,64 @@ void prepare_em_level(void)
   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++;
+    }
+  }
+
+  if (!setup.team_mode)
+    lev.home_initial = MIN(lev.home_initial, 1);
+
   lev.home = lev.home_initial;
+  players_left = lev.home_initial;
 
-  lev.killed_out_of_time = FALSE;
+  for (i = 0; i < MAX_PLAYERS; i++)
+  {
+    if (ply[i].exists)
+    {
+      if (players_left)
+      {
+       ply[i].alive_initial = TRUE;
+       players_left--;
+      }
+      else
+      {
+       native_em_level.cave[ply[i].x_initial][ply[i].y_initial] = 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;
 
-  ply1.num = 0;
-  ply1.alive = ply1.alive_initial;
-  ply1.dynamite = 0;
-  ply1.dynamite_cnt = 0;
-  ply1.keys = 0;
-  ply1.anim = 0;
-  ply1.oldx = ply1.x = ply1.x_initial;
-  ply1.oldy = ply1.y = ply1.y_initial;
-  ply1.last_move_dir = MV_NONE;
-  ply1.joy_n = ply1.joy_e = ply1.joy_s = ply1.joy_w = 0;
-  ply1.joy_snap = ply1.joy_drop = 0;
-  ply1.joy_stick = ply1.joy_spin = 0;
-
-  ply2.num = 1;
-  ply2.alive = ply2.alive_initial;
-  ply2.dynamite = 0;
-  ply2.dynamite_cnt = 0;
-  ply2.keys = 0;
-  ply2.anim = 0;
-  ply2.oldx = ply2.x = ply2.x_initial;
-  ply2.oldy = ply2.y = ply2.y_initial;
-  ply2.last_move_dir = MV_NONE;
-  ply2.joy_n = ply2.joy_e = ply2.joy_s = ply2.joy_w = 0;
-  ply2.joy_snap = ply1.joy_drop = 0;
-  ply2.joy_stick = ply2.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
+  }
 }
index 2ca711b448cc529175c0a41a4c63f5cac5a94a28..d6a962c14223fb5724660b0b4079dbecbd37de55 100644 (file)
@@ -26,7 +26,7 @@
 extern struct GlobalInfo_EM global_em_info;
 extern struct LevelInfo_EM native_em_level;
 extern struct GraphicInfo_EM graphic_info_em_object[TILE_MAX][8];
-extern struct GraphicInfo_EM graphic_info_em_player[2][SPR_MAX][8];
+extern struct GraphicInfo_EM graphic_info_em_player[MAX_PLAYERS][SPR_MAX][8];
 
 extern void em_open_all();
 extern void em_close_all();
index 1a6e77ada027f16d3a4aeb211b26a1a965960702..e60f96291f439c82bcea327dcfb69da82ce1b2f1 100644 (file)
@@ -25,7 +25,7 @@ int open_all(void);
 void close_all(void);
 
 #if 1
-void readjoy(byte, int);
+void readjoy(byte, struct PLAYER *);
 #else
 void readjoy(byte);
 #endif
index 06f974a2e935777387583b68373e7897e55b2ff6..cc746c0c399fd44da79edc8d44e5bc458ce7b453 100644 (file)
@@ -16,6 +16,8 @@ unsigned int screen_y;
 static unsigned int screentiles[MAX_BUF_YSIZE][MAX_BUF_XSIZE];
 static unsigned int crumbled_state[MAX_BUF_YSIZE][MAX_BUF_XSIZE];
 
+static boolean redraw[MAX_BUF_XSIZE][MAX_BUF_YSIZE];
+
 
 /* copy the entire screen to the window at the scroll position
  *
@@ -69,7 +71,54 @@ void BlitScreenToBitmap_EM(Bitmap *target_bitmap)
 
 void blitscreen(void)
 {
+#if 1
+
+  static boolean scrolling_last = FALSE;
+  unsigned int left = screen_x / TILEX;
+  unsigned int top  = screen_y / TILEY;
+  boolean scrolling = (screen_x % TILEX != 0 || screen_y % TILEY != 0);
+  int x, y;
+
+  SyncDisplay();
+
+  if (redraw_tiles > REDRAWTILES_THRESHOLD || scrolling || scrolling_last)
+  {
+    /* blit all (up to four) parts of the scroll buffer to the backbuffer */
+    BlitScreenToBitmap_EM(backbuffer);
+
+    /* blit the completely updated backbuffer to the window (in one blit) */
+    BlitBitmap(backbuffer, window, SX, SY, SXSIZE, SYSIZE, SX, SY);
+  }
+  else
+  {
+    for (x = 0; x < SCR_FIELDX; x++)
+    {
+      for (y = 0; y < SCR_FIELDY; y++)
+      {
+       int xx = (left + x) % MAX_BUF_XSIZE;
+       int yy = (top  + y) % MAX_BUF_YSIZE;
+
+       if (redraw[xx][yy])
+         BlitBitmap(screenBitmap, window,
+                    xx * TILEX, yy * TILEY, TILEX, TILEY,
+                    SX + x * TILEX, SY + y * TILEY);
+      }
+    }
+  }
+
+  for (x = 0; x < MAX_BUF_XSIZE; x++)
+    for (y = 0; y < MAX_BUF_YSIZE; y++)
+      redraw[x][y] = FALSE;
+  redraw_tiles = 0;
+
+  scrolling_last = scrolling;
+
+#else
+
+  /* blit all (up to four) parts of the scroll buffer to the window */
   BlitScreenToBitmap_EM(window);
+
+#endif
 }
 
 static void DrawLevelField_EM(int x, int y, int sx, int sy,
@@ -225,7 +274,7 @@ static void animscreen(void)
 {
   unsigned int x, y, i;
   unsigned int left = screen_x / TILEX;
-  unsigned int top = screen_y / TILEY;
+  unsigned int top  = screen_y / TILEY;
   static int xy[4][2] =
   {
     { 0, -1 },
@@ -273,6 +322,9 @@ static void animscreen(void)
 
        screentiles[sy][sx] = obj;
        crumbled_state[sy][sx] = crm;
+
+       redraw[sx][sy] = TRUE;
+       redraw_tiles++;
       }
     }
   }
@@ -365,6 +417,8 @@ static void blitplayer(struct PLAYER *ply)
 void game_initscreen(void)
 {
   unsigned int x,y;
+  int dynamite_state = ply[0].dynamite;                /* !!! ONLY PLAYER 1 !!! */
+  int all_keys_state = ply[0].keys | ply[1].keys | ply[2].keys | ply[3].keys;
 
   frame = 6;
   screen_x = 0;
@@ -380,8 +434,8 @@ void game_initscreen(void)
   }
 
 #if 1
-  DrawAllGameValues(lev.required, ply1.dynamite, lev.score,
-                   lev.time, ply1.keys | ply2.keys);
+  DrawAllGameValues(lev.required, dynamite_state, lev.score,
+                   lev.time, all_keys_state);
 #else
   DrawAllGameValues(lev.required, ply1.dynamite, lev.score,
                    DISPLAY_TIME(lev.time + 4), ply1.keys | ply2.keys);
@@ -390,11 +444,12 @@ void game_initscreen(void)
 
 void RedrawPlayfield_EM()
 {
-  unsigned int x,y;
+  unsigned int i, x, y;
 
-  x = (frame * ply1.oldx + (8 - frame) * ply1.x) * TILEX / 8
+  /* !!! FIX THIS (CENTERED TO PLAYER 1) !!! */
+  x = (frame * ply[0].oldx + (8 - frame) * ply[0].x) * TILEX / 8
     + ((SCR_FIELDX - 1) * TILEX) / 2;
-  y = (frame * ply1.oldy + (8 - frame) * ply1.y) * TILEY / 8
+  y = (frame * ply[0].oldy + (8 - frame) * ply[0].y) * TILEY / 8
     + ((SCR_FIELDY - 1) * TILEY) / 2;
 
   if (x > lev.width * TILEX)
@@ -411,8 +466,10 @@ void RedrawPlayfield_EM()
   screen_y = y - (SCR_FIELDY - 1) * TILEY;
 
   animscreen();
-  blitplayer(&ply1);
-  blitplayer(&ply2);
+
+  for (i = 0; i < MAX_PLAYERS; i++)
+    blitplayer(&ply[i]);
+
   blitscreen();
 
   FlushDisplay();
@@ -425,9 +482,12 @@ void game_animscreen(void)
 
 void DrawGameDoorValues_EM()
 {
+  int dynamite_state = ply[0].dynamite;                /* !!! ONLY PLAYER 1 !!! */
+  int all_keys_state = ply[0].keys | ply[1].keys | ply[2].keys | ply[3].keys;
+
 #if 1
-  DrawAllGameValues(lev.required, ply1.dynamite, lev.score,
-                   lev.time, ply1.keys | ply2.keys);
+  DrawAllGameValues(lev.required, dynamite_state, lev.score,
+                   lev.time, all_keys_state);
 #else
   DrawAllGameValues(lev.required, ply1.dynamite, lev.score,
                    DISPLAY_TIME(lev.time), ply1.keys | ply2.keys);
index b2a644c79b04ea6ad8d455b461783912e470a3ea..ae3e1d554d0f93c50fa5f3a1bea9a84848817ffc 100644 (file)
@@ -10,9 +10,8 @@
 
 unsigned long RandomEM;
 
-struct PLAYER ply1;
-struct PLAYER ply2;
 struct LEVEL lev;
+struct PLAYER ply[MAX_PLAYERS];
 
 unsigned short **Boom;
 unsigned short **Cave;
@@ -92,8 +91,8 @@ void GameActions_EM(byte action[MAX_PLAYERS])
 
   frame = (frame - 1) & 7;
 
-  for (i = 0; i < 2; i++)
-    readjoy(action[i], i);
+  for (i = 0; i < MAX_PLAYERS; i++)
+    readjoy(action[i], &ply[i]);
 
   UpdateEngineValues(screen_x / TILEX, screen_y / TILEY);
 
@@ -190,7 +189,7 @@ void GameActions_EM(byte action)
 
 #if 1
 
-void readjoy(byte action, int player_nr)
+void readjoy(byte action, struct PLAYER *ply)
 {
   unsigned int north = 0, east = 0, south = 0, west = 0;
   unsigned int snap = 0, drop = 0;
@@ -213,29 +212,15 @@ void readjoy(byte action, int player_nr)
   if (action & JOY_BUTTON_2)
     drop = 1;
 
-  if (player_nr == 0)
-  {
-    ply1.joy_snap = snap;
-    ply1.joy_drop = drop;
-    if (ply1.joy_stick || (north | east | south | west))
-    {
-      ply1.joy_n = north;
-      ply1.joy_e = east;
-      ply1.joy_s = south;
-      ply1.joy_w = west;
-    }
-  }
-  else
+  ply->joy_snap = snap;
+  ply->joy_drop = drop;
+
+  if (ply->joy_stick || (north | east | south | west))
   {
-    ply2.joy_snap = snap;
-    ply2.joy_drop = drop;
-    if (ply2.joy_stick || (north | east | south | west))
-    {
-      ply2.joy_n = north;
-      ply2.joy_e = east;
-      ply2.joy_s = south;
-      ply2.joy_w = west;
-    }
+    ply->joy_n = north;
+    ply->joy_e = east;
+    ply->joy_s = south;
+    ply->joy_w = west;
   }
 }
 
index 46ba9e4038825e8d5a49750a74bbf92fbf7b881b..9fb51dd9260a3851e40045a22c276c0b1944a22c 100644 (file)
@@ -7,97 +7,14 @@
 #define WIDTH          EM_MAX_CAVE_WIDTH
 #define HEIGHT         EM_MAX_CAVE_HEIGHT
 
-#if 0
-
-struct LEVEL
-{
-  unsigned int home;     /* number of players that have to go home */
-                         /* 0 == all players home */
-
-  unsigned int width;    /* world width */
-  unsigned int height;   /* world height */
-  unsigned int time;     /* time remaining */
-  unsigned int required; /* emeralds needed */
-  unsigned int score;    /* score */
-
-  /* fill in all below /every/ time you read a level */
-  unsigned int alien_score;           /* alien popped by stone/spring score */
-  unsigned int amoeba_time;           /* amoeba speed */
-  unsigned int android_move_cnt;      /* android move time counter */
-  unsigned int android_move_time;     /* android move reset time */
-  unsigned int android_clone_cnt;     /* android clone time counter */
-  unsigned int android_clone_time;    /* android clone reset time */
-  unsigned int ball_cnt;              /* ball time counter */
-  unsigned int ball_pos;              /* ball array pos counter */
-  unsigned int ball_random;           /* ball is random flag */
-  unsigned int ball_state;            /* ball currently on flag */
-  unsigned int ball_time;             /* ball reset time */
-  unsigned int bug_score;             /* bug popped by stone/spring score */
-  unsigned int diamond_score;         /* diamond collect score */
-  unsigned int dynamite_score;        /* dynamite collect scoer*/
-  unsigned int eater_pos;             /* eater array pos */
-  unsigned int eater_score;           /* eater popped by stone/spring score */
-  unsigned int emerald_score;         /* emerald collect score */
-  unsigned int exit_score;            /* exit score */
-  unsigned int key_score;             /* key collect score */
-  unsigned int lenses_cnt;            /* lenses time counter */
-  unsigned int lenses_score;          /* lenses collect score */
-  unsigned int lenses_time;           /* lenses reset time */
-  unsigned int magnify_cnt;           /* magnify time counter */
-  unsigned int magnify_score;         /* magnify collect score */
-  unsigned int magnify_time;          /* magnify reset time */
-  unsigned int nut_score;             /* nut crack score */
-  unsigned int shine_cnt;             /* shine counter for emerald/diamond */
-  unsigned int slurp_score;           /* slurp alien score */
-  unsigned int tank_score;            /* tank popped by stone/spring */
-  unsigned int wheel_cnt;             /* wheel time counter */
-  unsigned int wheel_x;               /* wheel x pos */
-  unsigned int wheel_y;               /* wheel y pos */
-  unsigned int wheel_time;            /* wheel reset time */
-  unsigned int wind_cnt;              /* wind time counter */
-  unsigned int wind_direction;        /* wind direction */
-  unsigned int wind_time;             /* wind reset time */
-  unsigned int wonderwall_state;      /* wonderwall currently on flag */
-  unsigned int wonderwall_time;       /* wonderwall time */
-  unsigned short eater_array[8][9];   /* eater data */
-  unsigned short ball_array[8][8];    /* ball data */
-  unsigned short android_array[TILE_MAX]; /* android clone table */
-};
-
-struct PLAYER
-{
-  unsigned int num;
-  unsigned int alive;
-  unsigned int dynamite;
-  unsigned int dynamite_cnt;
-  unsigned int keys;
-  unsigned int anim;
-  unsigned int x;
-  unsigned int y;
-  unsigned int oldx;
-  unsigned int oldy;
-
-  unsigned joy_n:1;
-  unsigned joy_e:1;
-  unsigned joy_s:1;
-  unsigned joy_w:1;
-  unsigned joy_snap:1;
-  unsigned joy_drop:1;
-  unsigned joy_stick:1;
-  unsigned joy_spin:1;
-};
-
-#endif
-
 extern unsigned long RandomEM;
 
-extern struct PLAYER ply1;
-extern struct PLAYER ply2;
 extern struct LEVEL lev;
+extern struct PLAYER ply[MAX_PLAYERS];
 
 extern struct LevelInfo_EM native_em_level;
 extern struct GraphicInfo_EM graphic_info_em_object[TILE_MAX][8];
-extern struct GraphicInfo_EM graphic_info_em_player[2][SPR_MAX][8];
+extern struct GraphicInfo_EM graphic_info_em_player[MAX_PLAYERS][SPR_MAX][8];
 
 extern unsigned short **Boom;
 extern unsigned short **Cave;
index 5da62d3b8f5afb3e889a397b94ed39eb9d22be5e..88f673f9979f3014a645969ad85a457944af85ea 100644 (file)
@@ -599,6 +599,7 @@ struct LEVEL
 struct PLAYER
 {
   unsigned int num;
+  unsigned int exists;
   unsigned int alive_initial;
   unsigned int alive;
 
@@ -651,7 +652,7 @@ struct LevelInfo_EM
   unsigned short cave[EM_MAX_CAVE_WIDTH][EM_MAX_CAVE_HEIGHT];
 
   struct LEVEL *lev;
-  struct PLAYER *ply1, *ply2;
+  struct PLAYER *ply[MAX_PLAYERS];
 };
 
 struct GraphicInfo_EM
index 124751d0ad312087bbf805251937df00481ef4eb..0b3710e1c55394f9f1e80ff109f01f513b737308 100644 (file)
@@ -18,7 +18,24 @@ static boolean player_killed(struct PLAYER *);
 
 void synchro_1(void)
 {
- /* must test for death and actually kill separately */
+#if 1
+
+  int start_check_nr;
+  int i;
+
+  /* must test for death and actually kill separately */
+
+  for (i = 0; i < MAX_PLAYERS; i++)
+  {
+    boolean ply_kill = player_killed(&ply[i]);
+
+    if (ply[i].alive && ply_kill)
+      kill_player(&ply[i]);
+  }
+
+#else
+
+  /* must test for death and actually kill separately */
   boolean ply1_kill = player_killed(&ply1);
   boolean ply2_kill = player_killed(&ply2);
 
@@ -27,10 +44,51 @@ void synchro_1(void)
   if (ply2.alive && ply2_kill)
     kill_player(&ply2);
 
+#endif
+
 #if 0
   ply1.alive = 1; /* debugging */
 #endif
 
+#if 1
+
+  for (i = 0; i < MAX_PLAYERS; i++)
+  {
+    ply[i].oldx = ply[i].x;
+    ply[i].oldy = ply[i].y;
+    ply[i].anim = SPR_still;
+  }
+
+  start_check_nr = (RandomEM & 128 ? 0 : 1) * 2 + (RandomEM & 256 ? 0 : 1);
+
+  for (i = 0; i < MAX_PLAYERS; i++)
+  {
+    int check_nr = (start_check_nr + i) % MAX_PLAYERS;
+
+    if (ply[check_nr].alive)
+      check_player(&ply[check_nr]);
+  }
+
+  for (i = 0; i < MAX_PLAYERS; i++)
+  {
+    if (!ply[i].alive)
+      continue;
+
+    if (Cave[ply[i].oldy][ply[i].oldx] == Zplayer)
+    {
+      Cave[ply[i].oldy][ply[i].oldx] = Xblank;
+      Next[ply[i].oldy][ply[i].oldx] = Xblank;
+    }
+
+    if (Cave[ply[i].y][ply[i].x] == Xblank)
+    {
+      Cave[ply[i].y][ply[i].x] = Zplayer;
+      Next[ply[i].y][ply[i].x] = Zplayer;
+    }
+  }
+
+#else
+
   ply1.oldx = ply1.x;
   ply1.oldy = ply1.y;
   ply1.anim = SPR_still;
@@ -78,6 +136,8 @@ void synchro_1(void)
       Next[ply2.y][ply2.x] = Zplayer;
     }
   }
+
+#endif
 }
 
 static boolean player_killed(struct PLAYER *ply)
@@ -85,6 +145,10 @@ static boolean player_killed(struct PLAYER *ply)
   register unsigned int x = ply->x;
   register unsigned int y = ply->y;
 
+#if 0
+  printf("::: %d: %d, %d\n", ply->num, x, y);
+#endif
+
   if (!ply->alive)
     return FALSE;
 
index 119d86a5832c1fd7d229d0e5b96057388937fce5..5079b7c253d7b31a8339f97aaf0b1b67bb99d46c 100644 (file)
 
 #define RANDOM (random = random << 31 | random >> 1)
 
+static void set_nearest_player_xy(int x, int y, int *dx, int *dy)
+{
+  int distance, distance_shortest = EM_MAX_CAVE_WIDTH + EM_MAX_CAVE_HEIGHT;
+  int i;
+
+  /* default values if no players are alive anymore */
+  *dx = 0;
+  *dy = 0;
+
+  for (i = 0; i < MAX_PLAYERS; i++)
+  {
+    if (!ply[i].alive)
+      continue;
+
+    distance = ABS(ply[i].x - x) + ABS(ply[i].y - y);
+
+    if (distance < distance_shortest)
+    {
+      *dx = ply[i].x;
+      *dy = ply[i].y;
+
+      distance_shortest = distance;
+    }
+  }
+}
+
 void synchro_2(void)
 {
   register unsigned int x = 0;
@@ -1879,6 +1905,12 @@ void synchro_2(void)
            Cave[y+1][x+1] == Zplayer)
          goto android_still;
 
+#if 1
+
+       set_nearest_player_xy(x, y, &dx, &dy);
+
+#else
+
        if (ply1.alive && ply2.alive)
        {
          if ((ply1.x > x ? ply1.x - x : x - ply1.x) +
@@ -1911,6 +1943,8 @@ void synchro_2(void)
          dy = 0;
        }
 
+#endif
+
        Next[y][x] = Xblank;    /* assume we will move */
        temp = ((x < dx) + 1 - (x > dx)) + ((y < dy) + 1 - (y > dy)) * 3;
 
@@ -3205,6 +3239,21 @@ void synchro_2(void)
     /* --------------------------------------------------------------------- */
 
     case Xalien:
+
+#if 1
+
+      if (lev.wheel_cnt)
+      {
+       dx = lev.wheel_x;
+       dy = lev.wheel_y;
+      }
+      else
+      {
+       set_nearest_player_xy(x, y, &dx, &dy);
+      }
+
+#else
+
       if (lev.wheel_cnt)
       {
        dx = lev.wheel_x;
@@ -3242,6 +3291,8 @@ void synchro_2(void)
        dy = 0;
       }
 
+#endif
+
       if (RANDOM & 1)
       {
        if (y > dy)
@@ -4888,8 +4939,8 @@ void synchro_2(void)
 
  done:
 
-  if (ply1.alive || ply2.alive)
-    lev.score += score; /* only get a score if someone is alive */
+  if (ply[0].alive || ply[1].alive || ply[2].alive || ply[3].alive)
+    lev.score += score;                /* only add a score if someone is alive */
 
   RandomEM = random;
 
index 75c47b3795afc0345af4817394b0130b9e051ab8..2828ecd32b672ba3d7ab4f6eef9e83a180343d50 100644 (file)
@@ -4435,7 +4435,7 @@ unsigned short map_ttl[128];
 struct GraphicInfo_EM graphic_info_em_object[TILE_MAX][8];
 
 /* map player number, frames and action to graphic info */
-struct GraphicInfo_EM graphic_info_em_player[2][SPR_MAX][8];
+struct GraphicInfo_EM graphic_info_em_player[MAX_PLAYERS][SPR_MAX][8];
 
 void create_tab(int *invert, unsigned char *array)
 {
@@ -4641,14 +4641,14 @@ void create_spr_graphics_info_em()
 {
   int i, j, k;
 
-  for (i = 0; i < 2; i++)
+  for (i = 0; i < MAX_PLAYERS; i++)
   {
     for (j = 0; j < SPR_MAX; j++)
     {
       for (k = 0; k < 8; k++)
       {
        struct GraphicInfo_EM *g = &graphic_info_em_player[i][j][k];
-       int spr = map_spr[i][k][j];
+       int spr = map_spr[i % 2][k][j];
 
        g->bitmap = sprBitmap;
        g->src_x = (spr / 8) * TILEX;
index 591b96ab5bdd348c7d921fb4f4423971355e1dc9..bc9a1e8bdace8fae9e8b0084769ca51e4e07d231 100644 (file)
@@ -290,60 +290,63 @@ struct ElementNameInfo element_name_info[MAX_NUM_ELEMENTS + 1] =
   {
     "key_1",
     "key",
-    "red key"
+    "key 1"
   },
   {
     "key_2",
     "key",
-    "yellow key"
+    "key 2"
   },
   {
     "key_3",
     "key",
-    "green key"
+    "key 3"
   },
   {
     "key_4",
     "key",
-    "blue key"
+    "key 4"
   },
   {
     "gate_1",
     "gate",
-    "red door"
+    "door 1"
   },
   {
     "gate_2",
     "gate",
-    "yellow door"
+    "door 2"
   },
   {
     "gate_3",
     "gate",
-    "green door"
+    "door 3"
   },
   {
     "gate_4",
     "gate",
-    "blue door"
+    "door 4"
   },
   {
     "gate_1_gray",
     "gate",
-    "gray door (opened by red key)"
+    "gray door (opened by key 1)"
   },
   {
     "gate_2_gray",
     "gate",
-    "gray door (opened by yellow key)"},
+    "gray door (opened by key 2)"
+  },
   {
     "gate_3_gray",
     "gate",
-    "gray door (opened by green key)"},
+    "gray door (opened by key 3)"
+  },
   {
     "gate_4_gray",
     "gate",
-    "gray door (opened by blue key)"},
+    "gray door (opened by key 4)"
+  },
   {
     "dynamite",
     "dynamite",
@@ -524,22 +527,22 @@ struct ElementNameInfo element_name_info[MAX_NUM_ELEMENTS + 1] =
   {
     "player_1",
     "player",
-    "yellow player"
+    "player 1"
   },
   {
     "player_2",
     "player",
-    "red player"
+    "player 2"
   },
   {
     "player_3",
     "player",
-    "green player"
+    "player 3"
   },
   {
     "player_4",
     "player",
-    "blue player"
+    "player 4"
   },
   {
     "bug.right",
@@ -1136,22 +1139,22 @@ struct ElementNameInfo element_name_info[MAX_NUM_ELEMENTS + 1] =
   {
     "em_gate_1",
     "gate",
-    "red door (EM style)"
+    "door 1 (EM style)"
   },
   {
     "em_gate_2",
     "gate",
-    "yellow door (EM style)"
+    "door 2 (EM style)"
   },
   {
     "em_gate_3",
     "gate",
-    "green door (EM style)"
+    "door 3 (EM style)"
   },
   {
     "em_gate_4",
     "gate",
-    "blue door (EM style)"
+    "door 4 (EM style)"
   },
   {
     "em_key_2_file_obsolete",
@@ -1371,22 +1374,22 @@ struct ElementNameInfo element_name_info[MAX_NUM_ELEMENTS + 1] =
   {
     "em_gate_1_gray",
     "gate",
-    "gray door (EM style, red key)"
+    "gray door (EM style, key 1)"
   },
   {
     "em_gate_2_gray",
     "gate",
-    "gray door (EM style, yellow key)"
+    "gray door (EM style, key 2)"
   },
   {
     "em_gate_3_gray",
     "gate",
-    "gray door (EM style, green key)"
+    "gray door (EM style, key 3)"
   },
   {
     "em_gate_4_gray",
     "gate",
-    "gray door (EM style, blue key)"
+    "gray door (EM style, key 4)"
   },
   {
     "unused_254",
@@ -1476,122 +1479,122 @@ struct ElementNameInfo element_name_info[MAX_NUM_ELEMENTS + 1] =
   {
     "conveyor_belt_1_left",
     "conveyor_belt",
-    "red conveyor belt (left)"
+    "conveyor belt 1 (left)"
   },
   {
     "conveyor_belt_1_middle",
     "conveyor_belt",
-    "red conveyor belt (middle)"
+    "conveyor belt 1 (middle)"
   },
   {
     "conveyor_belt_1_right",
     "conveyor_belt",
-    "red conveyor belt (right)"
+    "conveyor belt 1 (right)"
   },
   {
     "conveyor_belt_1_switch_left",
     "conveyor_belt_switch",
-    "switch for red conveyor belt (left)"
+    "switch for conveyor belt 1 (left)"
   },
   {
     "conveyor_belt_1_switch_middle",
     "conveyor_belt_switch",
-    "switch for red conveyor belt (middle)"
+    "switch for conveyor belt 1 (middle)"
   },
   {
     "conveyor_belt_1_switch_right",
     "conveyor_belt_switch",
-    "switch for red conveyor belt (right)"
+    "switch for conveyor belt 1 (right)"
   },
   {
     "conveyor_belt_2_left",
     "conveyor_belt",
-    "yellow conveyor belt (left)"
+    "conveyor belt 2 (left)"
   },
   {
     "conveyor_belt_2_middle",
     "conveyor_belt",
-    "yellow conveyor belt (middle)"
+    "conveyor belt 2 (middle)"
   },
   {
     "conveyor_belt_2_right",
     "conveyor_belt",
-    "yellow conveyor belt (right)"
+    "conveyor belt 2 (right)"
   },
   {
     "conveyor_belt_2_switch_left",
     "conveyor_belt_switch",
-    "switch for yellow conveyor belt (left)"
+    "switch for conveyor belt 2 (left)"
   },
   {
     "conveyor_belt_2_switch_middle",
     "conveyor_belt_switch",
-    "switch for yellow conveyor belt (middle)"
+    "switch for conveyor belt 2 (middle)"
   },
   {
     "conveyor_belt_2_switch_right",
     "conveyor_belt_switch",
-    "switch for yellow conveyor belt (right)"
+    "switch for conveyor belt 2 (right)"
   },
   {
     "conveyor_belt_3_left",
     "conveyor_belt",
-    "green conveyor belt (left)"
+    "conveyor belt 3 (left)"
   },
   {
     "conveyor_belt_3_middle",
     "conveyor_belt",
-    "green conveyor belt (middle)"
+    "conveyor belt 3 (middle)"
   },
   {
     "conveyor_belt_3_right",
     "conveyor_belt",
-    "green conveyor belt (right)"
+    "conveyor belt 3 (right)"
   },
   {
     "conveyor_belt_3_switch_left",
     "conveyor_belt_switch",
-    "switch for green conveyor belt (left)"
+    "switch for conveyor belt 3 (left)"
   },
   {
     "conveyor_belt_3_switch_middle",
     "conveyor_belt_switch",
-    "switch for green conveyor belt (middle)"
+    "switch for conveyor belt 3 (middle)"
   },
   {
     "conveyor_belt_3_switch_right",
     "conveyor_belt_switch",
-    "switch for green conveyor belt (right)"
+    "switch for conveyor belt 3 (right)"
   },
   {
     "conveyor_belt_4_left",
     "conveyor_belt",
-    "blue conveyor belt (left)"
+    "conveyor belt 4 (left)"
   },
   {
     "conveyor_belt_4_middle",
     "conveyor_belt",
-    "blue conveyor belt (middle)"
+    "conveyor belt 4 (middle)"
   },
   {
     "conveyor_belt_4_right",
     "conveyor_belt",
-    "blue conveyor belt (right)"
+    "conveyor belt 4 (right)"
   },
   {
     "conveyor_belt_4_switch_left",
     "conveyor_belt_switch",
-    "switch for blue conveyor belt (left)"
+    "switch for conveyor belt 4 (left)"
   },
   {
     "conveyor_belt_4_switch_middle",
     "conveyor_belt_switch",
-    "switch for blue conveyor belt (middle)"
+    "switch for conveyor belt 4 (middle)"
   },
   {
     "conveyor_belt_4_switch_right",
     "conveyor_belt_switch",
-    "switch for blue conveyor belt (right)"
+    "switch for conveyor belt 4 (right)"
   },
   {
     "landmine",
@@ -3201,22 +3204,22 @@ struct ElementNameInfo element_name_info[MAX_NUM_ELEMENTS + 1] =
   {
     "em_key_1",
     "key",
-    "red key (EM style)"
+    "key 1 (EM style)"
     },
   {
     "em_key_2",
     "key",
-    "yellow key (EM style)"
+    "key 2 (EM style)"
     },
   {
     "em_key_3",
     "key",
-    "green key (EM style)"
+    "key 3 (EM style)"
   },
   {
     "em_key_4",
     "key",
-    "blue key (EM style)"
+    "key 4 (EM style)"
   },
   {
     "envelope_1",
index c7382d07776c28afce6541d4000f12c99e030dae..999e933ea408dc2e322386f679ce2b33f7eb40a9 100644 (file)
@@ -3091,8 +3091,10 @@ void HandleGameActions()
        return;
     }
 
-    if (level.native_em_level->ply1->alive == 0 &&
-       level.native_em_level->ply2->alive == 0)        /* all dead */
+    if (level.native_em_level->ply[0]->alive == 0 &&
+       level.native_em_level->ply[1]->alive == 0 &&
+       level.native_em_level->ply[2]->alive == 0 &&
+       level.native_em_level->ply[3]->alive == 0)      /* all dead */
       AllPlayersGone = TRUE;
 
     if (AllPlayersGone && !TAPE_IS_STOPPED(tape))
index 90d10c55e278d5faab7c69d3f2355360fcdf9690..4711961d04144b313957294b5e84ec4d215b90d7 100644 (file)
@@ -4737,6 +4737,110 @@ em_player_mapping_list[] =
     SPR_still,                         1,
     EL_PLAYER_2,                       ACTION_DEFAULT, -1,
   },
+  {
+    SPR_walk + 0,                      2,
+    EL_PLAYER_3,                       ACTION_MOVING, MV_BIT_UP,
+  },
+  {
+    SPR_walk + 1,                      2,
+    EL_PLAYER_3,                       ACTION_MOVING, MV_BIT_RIGHT,
+  },
+  {
+    SPR_walk + 2,                      2,
+    EL_PLAYER_3,                       ACTION_MOVING, MV_BIT_DOWN,
+  },
+  {
+    SPR_walk + 3,                      2,
+    EL_PLAYER_3,                       ACTION_MOVING, MV_BIT_LEFT,
+  },
+  {
+    SPR_push + 0,                      2,
+    EL_PLAYER_3,                       ACTION_PUSHING, MV_BIT_UP,
+  },
+  {
+    SPR_push + 1,                      2,
+    EL_PLAYER_3,                       ACTION_PUSHING, MV_BIT_RIGHT,
+  },
+  {
+    SPR_push + 2,                      2,
+    EL_PLAYER_3,                       ACTION_PUSHING, MV_BIT_DOWN,
+  },
+  {
+    SPR_push + 3,                      2,
+    EL_PLAYER_3,                       ACTION_PUSHING, MV_BIT_LEFT,
+  },
+  {
+    SPR_spray + 0,                     2,
+    EL_PLAYER_3,                       ACTION_SNAPPING, MV_BIT_UP,
+  },
+  {
+    SPR_spray + 1,                     2,
+    EL_PLAYER_3,                       ACTION_SNAPPING, MV_BIT_RIGHT,
+  },
+  {
+    SPR_spray + 2,                     2,
+    EL_PLAYER_3,                       ACTION_SNAPPING, MV_BIT_DOWN,
+  },
+  {
+    SPR_spray + 3,                     2,
+    EL_PLAYER_3,                       ACTION_SNAPPING, MV_BIT_LEFT,
+  },
+  {
+    SPR_walk + 0,                      3,
+    EL_PLAYER_4,                       ACTION_MOVING, MV_BIT_UP,
+  },
+  {
+    SPR_walk + 1,                      3,
+    EL_PLAYER_4,                       ACTION_MOVING, MV_BIT_RIGHT,
+  },
+  {
+    SPR_walk + 2,                      3,
+    EL_PLAYER_4,                       ACTION_MOVING, MV_BIT_DOWN,
+  },
+  {
+    SPR_walk + 3,                      3,
+    EL_PLAYER_4,                       ACTION_MOVING, MV_BIT_LEFT,
+  },
+  {
+    SPR_push + 0,                      3,
+    EL_PLAYER_4,                       ACTION_PUSHING, MV_BIT_UP,
+  },
+  {
+    SPR_push + 1,                      3,
+    EL_PLAYER_4,                       ACTION_PUSHING, MV_BIT_RIGHT,
+  },
+  {
+    SPR_push + 2,                      3,
+    EL_PLAYER_4,                       ACTION_PUSHING, MV_BIT_DOWN,
+  },
+  {
+    SPR_push + 3,                      3,
+    EL_PLAYER_4,                       ACTION_PUSHING, MV_BIT_LEFT,
+  },
+  {
+    SPR_spray + 0,                     3,
+    EL_PLAYER_4,                       ACTION_SNAPPING, MV_BIT_UP,
+  },
+  {
+    SPR_spray + 1,                     3,
+    EL_PLAYER_4,                       ACTION_SNAPPING, MV_BIT_RIGHT,
+  },
+  {
+    SPR_spray + 2,                     3,
+    EL_PLAYER_4,                       ACTION_SNAPPING, MV_BIT_DOWN,
+  },
+  {
+    SPR_spray + 3,                     3,
+    EL_PLAYER_4,                       ACTION_SNAPPING, MV_BIT_LEFT,
+  },
+  {
+    SPR_still,                         2,
+    EL_PLAYER_3,                       ACTION_DEFAULT, -1,
+  },
+  {
+    SPR_still,                         3,
+    EL_PLAYER_4,                       ACTION_DEFAULT, -1,
+  },
 
   {
     -1,                                        -1,
@@ -5655,7 +5759,7 @@ unsigned int InitRND(long seed)
 void InitGraphicInfo_EM(void)
 {
   struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
-  struct Mapping_EM_to_RND_player player_mapping[2][SPR_MAX];
+  struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
   int i, j, p;
 
 #if DEBUG_EM_GFX
@@ -5677,7 +5781,7 @@ void InitGraphicInfo_EM(void)
   }
 
   /* always start with reliable default values */
-  for (p = 0; p < 2; p++)
+  for (p = 0; p < MAX_PLAYERS; p++)
   {
     for (i = 0; i < SPR_MAX; i++)
     {
@@ -6021,6 +6125,15 @@ void InitGraphicInfo_EM(void)
        g_em->height = TILEY - cy * step;
       }
 
+#if 1
+      /* create unique graphic identifier to decide if tile must be redrawn */
+      /* bit 31 - 16 (16 bit): EM style graphic
+        bit 15 - 12 ( 4 bit): EM style frame
+        bit 11 -  6 ( 6 bit): graphic width
+        bit  5 -  0 ( 6 bit): graphic height */
+      g_em->unique_identifier =
+       (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
+#else
       /* create unique graphic identifier to decide if tile must be redrawn */
       /* bit 31 - 16 (16 bit): EM style element
         bit 15 - 12 ( 4 bit): EM style frame
@@ -6028,6 +6141,13 @@ void InitGraphicInfo_EM(void)
         bit  5 -  0 ( 6 bit): graphic height */
       g_em->unique_identifier =
        (i << 16) | (j << 12) | (g_em->width << 6) | g_em->height;
+#endif
+
+#if 0
+      if (effective_element == EL_ROCK)
+       printf("::: EL_ROCK(%d, %d): %d, %d => %d\n",
+              effective_action, j, graphic, frame, g_em->unique_identifier);
+#endif
 
 #if DEBUG_EM_GFX
 
@@ -6129,7 +6249,7 @@ void InitGraphicInfo_EM(void)
     }
   }
 
-  for (p = 0; p < 2; p++)
+  for (p = 0; p < MAX_PLAYERS; p++)
   {
     for (i = 0; i < SPR_MAX; i++)
     {