added full compatibility for wrap-around levels in EM engine
authorHolger Schemel <info@artsoft.org>
Fri, 25 Sep 2020 00:08:46 +0000 (02:08 +0200)
committerHolger Schemel <info@artsoft.org>
Fri, 25 Sep 2020 00:25:50 +0000 (02:25 +0200)
The previous support for wrap-around levels in the EM game engine was
some sort of "idealized" implementation that lets the player wrap
around by moving horizontally on the same vertical level position
forever (which results in truely infinite wrap-around levels).

This may be nice and perfect, but has the disadvantage that the
original Emerald Mine Club engine did not work that way, making
existing EMC levels unplayable and/or unsolvable. (Examples are
level 80 of "Ruppelmine 3" or level 34 of "The Exception 2".)

Instead, the original game engine caused the player to step one
vertical position up or down when leaving the playfield at the left
or right border, which is required by the mentioned example levels.

This correction adds a flag that is set by default to use the original
behaviour.

src/game_em/cave.c
src/game_em/cave.h
src/game_em/convert.c
src/game_em/emerald.h
src/game_em/graphics.c
src/game_em/logic.c

index e33bdd580fa4511410981f514c8fe2b83f92156f..40b2dc6f90e6e6f9af864ed3a1c4c525aa180137 100644 (file)
@@ -64,6 +64,7 @@ void setLevelInfoToDefaults_EM(void)
   cav.testmode         = FALSE;
   cav.teamwork         = FALSE;
   cav.infinite         = TRUE;
+  cav.infinite_true    = FALSE;        // default: use original EMC behaviour
 
   cav.ball_random      = FALSE;
   cav.ball_active      = FALSE;
index 2b6ccef8ee05cae33ca4d80c3492cd8cadfacbfd..c1f47fff504aa94ece30469f058aba449b2f20c1 100644 (file)
@@ -258,6 +258,7 @@ struct CAVE
   boolean testmode;            /* flag for test mode */
   boolean teamwork;            /* flag for two player mode */
   boolean infinite;            /* flag for infinitely wide cave */
+  boolean infinite_true;       /* flag for truely infinitely wide cave */
 
   boolean ball_random;         /* flag if ball is random */
   boolean ball_active;         /* flag if ball is already active */
index 59c9a81e2d95ded94a1071865a7172f19aa76573..4c34fd16c7044d8a8b00ccca4fa1c10a8f3b0cd1 100644 (file)
@@ -278,21 +278,24 @@ void prepare_em_level(void)
   lev.bottom = lev.top + lev.height;
 
   lev.infinite = game_em.use_wrap_around;
+  lev.infinite_true = cav.infinite_true;
 
   if (lev.infinite)
   {
     /* add linked cave buffer columns for wrap-around movement */
     for (x = 0; x < lev.left; x++)
     {
-      lev.cavecol[x] = lev.cavecol[lev.width + x];
-      lev.nextcol[x] = lev.nextcol[lev.width + x];
-      lev.drawcol[x] = lev.drawcol[lev.width + x];
-      lev.boomcol[x] = lev.boomcol[lev.width + x];
-
-      lev.cavecol[lev.right + x] = lev.cavecol[lev.left + x];
-      lev.nextcol[lev.right + x] = lev.nextcol[lev.left + x];
-      lev.drawcol[lev.right + x] = lev.drawcol[lev.left + x];
-      lev.boomcol[lev.right + x] = lev.boomcol[lev.left + x];
+      int offset = (lev.infinite_true ? 0 : 1);
+
+      lev.cavecol[x] = &lev.cavecol[lev.width + x][-offset];
+      lev.nextcol[x] = &lev.nextcol[lev.width + x][-offset];
+      lev.drawcol[x] = &lev.drawcol[lev.width + x][-offset];
+      lev.boomcol[x] = &lev.boomcol[lev.width + x][-offset];
+
+      lev.cavecol[lev.right + x] = &lev.cavecol[lev.left + x][offset];
+      lev.nextcol[lev.right + x] = &lev.nextcol[lev.left + x][offset];
+      lev.drawcol[lev.right + x] = &lev.drawcol[lev.left + x][offset];
+      lev.boomcol[lev.right + x] = &lev.boomcol[lev.left + x][offset];
     }
   }
 
index 5a4ab2e64a8a984377dbcb07e85fe5f6038a3cde..e641de6e560342753bf6370a7512e896f0c8dbc4 100644 (file)
@@ -711,6 +711,7 @@ struct LOGIC
 
   boolean testmode;            /* test mode */
   boolean infinite;            /* flag for infinitely wide cave */
+  boolean infinite_true;       /* flag for truely infinitely wide cave */
   boolean killed_out_of_time;  /* kill player due to time out */
 
   int exit_x, exit_y;          /* kludge for playing player exit sound */
index 19000a7de764047c836a1e6b2e943ccab698cf8a..7f303a2a6510b78fda2ae33728a6037669e5cf6d 100644 (file)
@@ -446,6 +446,14 @@ static void blitplayer(int nr)
     ply[nr].x = (ply[nr].x < lev.left ? lev.right - 1 : lev.left);
     ply[nr].prev_x = ply[nr].x - dx;
 
+    if (!lev.infinite_true)
+    {
+      int dy = ply[nr].y - ply[nr].prev_y;
+
+      ply[nr].y += (ply[nr].x == lev.left ? 1 : -1);
+      ply[nr].prev_y = ply[nr].y - dy;
+    }
+
     /* draw player entering playfield from the opposite side */
     blitplayer_ext(nr);
 
@@ -666,8 +674,11 @@ void RedrawPlayfield_EM(boolean force_redraw)
 
     if (draw_new_player_location_wrap)
     {
-      // when wrapping around (horizontally), keep vertical player position
-      screen_yy = screen_y;
+      if (lev.infinite_true)
+      {
+       // when wrapping around (horizontally), keep vertical player position
+       screen_yy = screen_y;
+      }
 
       // scrolling for wrapping should be faster than for switching players
       wait_delay_value /= 4;
index ba823a0ca86b20e6855ad35ba49d80862e5b36e6..5055be5a11ca930b75d19ddb7f9d42270177d90b 100644 (file)
@@ -7413,6 +7413,9 @@ static void logic_players(void)
     {
       ply[i].x = (ply[i].x < lev.left ? lev.right - 1 : lev.left);
 
+      if (!lev.infinite_true)
+       ply[i].y += (ply[i].x == lev.left ? 1 : -1);
+
       game.centered_player_nr_next = i;
       game.set_centered_player = TRUE;
       game.set_centered_player_wrap = TRUE;