From 5eec6f3a02cb8a6171a37a209aae3e3665aff514 Mon Sep 17 00:00:00 2001 From: Holger Schemel Date: Fri, 25 Sep 2020 02:08:46 +0200 Subject: [PATCH] added full compatibility for wrap-around levels in EM engine 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 | 1 + src/game_em/cave.h | 1 + src/game_em/convert.c | 21 ++++++++++++--------- src/game_em/emerald.h | 1 + src/game_em/graphics.c | 15 +++++++++++++-- src/game_em/logic.c | 3 +++ 6 files changed, 31 insertions(+), 11 deletions(-) diff --git a/src/game_em/cave.c b/src/game_em/cave.c index e33bdd58..40b2dc6f 100644 --- a/src/game_em/cave.c +++ b/src/game_em/cave.c @@ -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; diff --git a/src/game_em/cave.h b/src/game_em/cave.h index 2b6ccef8..c1f47fff 100644 --- a/src/game_em/cave.h +++ b/src/game_em/cave.h @@ -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 */ diff --git a/src/game_em/convert.c b/src/game_em/convert.c index 59c9a81e..4c34fd16 100644 --- a/src/game_em/convert.c +++ b/src/game_em/convert.c @@ -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]; } } diff --git a/src/game_em/emerald.h b/src/game_em/emerald.h index 5a4ab2e6..e641de6e 100644 --- a/src/game_em/emerald.h +++ b/src/game_em/emerald.h @@ -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 */ diff --git a/src/game_em/graphics.c b/src/game_em/graphics.c index 19000a7d..7f303a2a 100644 --- a/src/game_em/graphics.c +++ b/src/game_em/graphics.c @@ -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; diff --git a/src/game_em/logic.c b/src/game_em/logic.c index ba823a0c..5055be5a 100644 --- a/src/game_em/logic.c +++ b/src/game_em/logic.c @@ -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; -- 2.34.1