changed handling of chain explosions in EM engine
authorHolger Schemel <info@artsoft.org>
Tue, 18 Feb 2020 14:24:47 +0000 (15:24 +0100)
committerHolger Schemel <info@artsoft.org>
Tue, 19 May 2020 16:19:57 +0000 (18:19 +0200)
So far, chain explosions in the native EM game engine were not handled
like in the original Kingsoft or EMC player on the Amiga, which can be
tested with a burning dynamite surrounded by eight bugs, which explode
to only one diamond (and lots of emeralds) instead of four diamonds.

This was changed now (while keeping the old behaviour for old tapes).

src/game.c
src/game_em/convert.c
src/game_em/emerald.h
src/game_em/export.h
src/game_em/logic.c
src/tools.c

index 00c7b5e5a0befbc5821aa6305b18e993768833b9..888e1ebf0af64304339a0e2e48c41c2fa74c83a5 100644 (file)
@@ -2906,12 +2906,17 @@ static void InitGameEngine(void)
   game.use_block_last_field_bug =
     (game.engine_version < VERSION_IDENT(3,1,1,0));
 
+  /* various special flags and settings for native Emerald Mine game engine */
+
   game_em.use_single_button =
     (game.engine_version > VERSION_IDENT(4,0,0,2));
 
   game_em.use_snap_key_bug =
     (game.engine_version < VERSION_IDENT(4,0,1,0));
 
+  game_em.use_old_explosions =
+    (game.engine_version < VERSION_IDENT(4,1,4,2));
+
   // --------------------------------------------------------------------------
 
   // set maximal allowed number of custom element changes per game frame
index 509437c7a40db680e35c75bf79772c3498ec3849..00768b5b96a54aa3b87797426136a8a1dcc8350f 100644 (file)
@@ -182,6 +182,7 @@ void prepare_em_level(void)
   //
   // - game_em.use_single_button (default: TRUE)
   // - game_em.use_snap_key_bug (default: FALSE)
+  // - game_em.use_old_explosions (default: FALSE)
 
   game_em.level_solved = FALSE;
   game_em.game_over = FALSE;
index 3c79825e90a858482c42cac15d04342911603161..d8d8c8b8ec0ce3d56396bfd902db5797b9afbb92 100644 (file)
@@ -77,7 +77,9 @@ enum
   Ztank,               /* internal tank/alien/bomb explosion */
   Zeater,              /* internal eater explosion */
   Zdynamite,           /* internal dynamite explosion */
+  Zboom,               /* explosion */
 
+  Xchain,              /* chain explosion; transition to Zboom */
   Xboom_bug,           /* bug explosion; transition to Zbug */
   Xboom_tank,          /* tank/alien/bomb explosion; transition to Ztank */
   Xboom_android,       /* android explosion; transition to Xboom_2 */
index 66dd13347f4e3a9c3318d51858bdd48baddc3e5f..a79a14866f545c3880544dd011375a087e27147f 100644 (file)
@@ -36,14 +36,16 @@ struct GameInfo_EM
   boolean any_player_moving;
   boolean any_player_snapping;
 
-  boolean use_single_button;
-  boolean use_snap_key_bug;
-
   int last_moving_player;
   int last_player_direction[MAX_PLAYERS];
 
   struct LOGIC *lev;
   struct PLAYER *ply[MAX_PLAYERS];
+
+  // flags to handle bugs in and changes between different engine versions
+  boolean use_single_button;
+  boolean use_snap_key_bug;
+  boolean use_old_explosions;
 };
 
 struct LevelInfo_EM
index fc6cbb30ce8af579d45984f7058994eb6d1c739c..7774c1dba4490e04b987d51e91ac05307943a038 100644 (file)
@@ -115,7 +115,8 @@ static void Lboom_generic(int x, int y, int element, int element_middle)
 
 static void Lboom_bug(int x, int y)
 {
-  next[x][y] = Zbug;
+  if (game_em.use_old_explosions)
+    next[x][y] = Zbug;
 
   Lboom_generic(x, y, Xemerald, Xdiamond);
 
@@ -126,7 +127,8 @@ static void Lboom_bug(int x, int y)
 
 static void Lboom_tank(int x, int y)
 {
-  next[x][y] = Ztank;
+  if (game_em.use_old_explosions)
+    next[x][y] = Ztank;
 
   Lboom_generic(x, y, Xblank, Xblank);
 
@@ -137,7 +139,8 @@ static void Lboom_tank(int x, int y)
 
 static void Lboom_eater(int x, int y)
 {
-  next[x][y] = Zeater;
+  if (game_em.use_old_explosions)
+    next[x][y] = Zeater;
 
   boom[x-1][y-1] = lev.eater_array[lev.eater_pos][0];
   boom[x][y-1]   = lev.eater_array[lev.eater_pos][1];
@@ -156,6 +159,63 @@ static void Lboom_eater(int x, int y)
 #endif
 }
 
+static void Lboom_bug_old(int x, int y)
+{
+  if (!game_em.use_old_explosions)
+    return;
+
+  Lboom_bug(x, y);
+}
+
+static void Lboom_tank_old(int x, int y)
+{
+  if (!game_em.use_old_explosions)
+    return;
+
+  Lboom_tank(x, y);
+}
+
+static void Lboom_eater_old(int x, int y)
+{
+  if (!game_em.use_old_explosions)
+    return;
+
+  Lboom_eater(x, y);
+}
+
+static void Lboom_bug_new(int x, int y, boolean chain_explosion)
+{
+  if (game_em.use_old_explosions)
+    return;
+
+  if (chain_explosion)
+    cave[x][y] = Xchain;
+
+  Lboom_bug(x, y);
+}
+
+static void Lboom_tank_new(int x, int y, boolean chain_explosion)
+{
+  if (game_em.use_old_explosions)
+    return;
+
+  if (chain_explosion)
+    cave[x][y] = Xchain;
+
+  Lboom_tank(x, y);
+}
+
+static void Lboom_eater_new(int x, int y, boolean chain_explosion)
+{
+  if (game_em.use_old_explosions)
+    return;
+
+  if (chain_explosion)
+    cave[x][y] = Xchain;
+
+  Lboom_eater(x, y);
+}
+
 static boolean player_killed(struct PLAYER *ply)
 {
   int x = ply->x;
@@ -293,6 +353,7 @@ static void kill_player(struct PLAYER *ply)
     case Xbug_2_s:
     case Xbug_2_w:
       cave[x][y-1] = Xboom_bug;
+      Lboom_bug_new(x, y-1, TRUE);
       break;
 
     case Xtank_1_n:
@@ -304,6 +365,7 @@ static void kill_player(struct PLAYER *ply)
     case Xtank_2_s:
     case Xtank_2_w:
       cave[x][y-1] = Xboom_tank;
+      Lboom_tank_new(x, y-1, TRUE);
       break;
   }
 
@@ -318,6 +380,7 @@ static void kill_player(struct PLAYER *ply)
     case Xbug_2_s:
     case Xbug_2_w:
       cave[x+1][y] = Xboom_bug;
+      Lboom_bug_new(x+1, y, TRUE);
       break;
 
     case Xtank_1_n:
@@ -329,6 +392,7 @@ static void kill_player(struct PLAYER *ply)
     case Xtank_2_s:
     case Xtank_2_w:
       cave[x+1][y] = Xboom_tank;
+      Lboom_tank_new(x+1, y, TRUE);
       break;
   }
 
@@ -343,6 +407,7 @@ static void kill_player(struct PLAYER *ply)
     case Xbug_2_s:
     case Xbug_2_w:
       cave[x][y+1] = Xboom_bug;
+      Lboom_bug_new(x, y+1, TRUE);
       break;
 
     case Xtank_1_n:
@@ -354,6 +419,7 @@ static void kill_player(struct PLAYER *ply)
     case Xtank_2_s:
     case Xtank_2_w:
       cave[x][y+1] = Xboom_tank;
+      Lboom_tank_new(x, y+1, TRUE);
       break;
   }
 
@@ -368,6 +434,7 @@ static void kill_player(struct PLAYER *ply)
     case Xbug_2_s:
     case Xbug_2_w:
       cave[x-1][y] = Xboom_bug;
+      Lboom_bug_new(x-1, y, TRUE);
       break;
 
     case Xtank_1_n:
@@ -379,6 +446,7 @@ static void kill_player(struct PLAYER *ply)
     case Xtank_2_s:
     case Xtank_2_w:
       cave[x-1][y] = Xboom_tank;
+      Lboom_tank_new(x-1, y, TRUE);
       break;
   }
 
@@ -2802,6 +2870,7 @@ static void Lbug_1_n(int x, int y)
       is_amoeba[cave[x][y+1]] ||
       is_amoeba[cave[x-1][y]])
   {
+    next[x][y] = Zboom;
     Lboom_bug(x, y);
 
     return;
@@ -2849,6 +2918,7 @@ static void Lbug_2_n(int x, int y)
       is_amoeba[cave[x][y+1]] ||
       is_amoeba[cave[x-1][y]])
   {
+    next[x][y] = Zboom;
     Lboom_bug(x, y);
 
     return;
@@ -2914,6 +2984,7 @@ static void Lbug_1_e(int x, int y)
       is_amoeba[cave[x][y+1]] ||
       is_amoeba[cave[x-1][y]])
   {
+    next[x][y] = Zboom;
     Lboom_bug(x, y);
 
     return;
@@ -2961,6 +3032,7 @@ static void Lbug_2_e(int x, int y)
       is_amoeba[cave[x][y+1]] ||
       is_amoeba[cave[x-1][y]])
   {
+    next[x][y] = Zboom;
     Lboom_bug(x, y);
 
     return;
@@ -3026,6 +3098,7 @@ static void Lbug_1_s(int x, int y)
       is_amoeba[cave[x][y+1]] ||
       is_amoeba[cave[x-1][y]])
   {
+    next[x][y] = Zboom;
     Lboom_bug(x, y);
 
     return;
@@ -3073,6 +3146,7 @@ static void Lbug_2_s(int x, int y)
       is_amoeba[cave[x][y+1]] ||
       is_amoeba[cave[x-1][y]])
   {
+    next[x][y] = Zboom;
     Lboom_bug(x, y);
 
     return;
@@ -3138,6 +3212,7 @@ static void Lbug_1_w(int x, int y)
       is_amoeba[cave[x][y+1]] ||
       is_amoeba[cave[x-1][y]])
   {
+    next[x][y] = Zboom;
     Lboom_bug(x, y);
 
     return;
@@ -3185,6 +3260,7 @@ static void Lbug_2_w(int x, int y)
       is_amoeba[cave[x][y+1]] ||
       is_amoeba[cave[x-1][y]])
   {
+    next[x][y] = Zboom;
     Lboom_bug(x, y);
 
     return;
@@ -3250,6 +3326,7 @@ static void Ltank_1_n(int x, int y)
       is_amoeba[cave[x][y+1]] ||
       is_amoeba[cave[x-1][y]])
   {
+    next[x][y] = Zboom;
     Lboom_tank(x, y);
 
     return;
@@ -3297,6 +3374,7 @@ static void Ltank_2_n(int x, int y)
       is_amoeba[cave[x][y+1]] ||
       is_amoeba[cave[x-1][y]])
   {
+    next[x][y] = Zboom;
     Lboom_tank(x, y);
 
     return;
@@ -3362,6 +3440,7 @@ static void Ltank_1_e(int x, int y)
       is_amoeba[cave[x][y+1]] ||
       is_amoeba[cave[x-1][y]])
   {
+    next[x][y] = Zboom;
     Lboom_tank(x, y);
 
     return;
@@ -3409,6 +3488,7 @@ static void Ltank_2_e(int x, int y)
       is_amoeba[cave[x][y+1]] ||
       is_amoeba[cave[x-1][y]])
   {
+    next[x][y] = Zboom;
     Lboom_tank(x, y);
 
     return;
@@ -3474,6 +3554,7 @@ static void Ltank_1_s(int x, int y)
       is_amoeba[cave[x][y+1]] ||
       is_amoeba[cave[x-1][y]])
   {
+    next[x][y] = Zboom;
     Lboom_tank(x, y);
 
     return;
@@ -3521,6 +3602,7 @@ static void Ltank_2_s(int x, int y)
       is_amoeba[cave[x][y+1]] ||
       is_amoeba[cave[x-1][y]])
   {
+    next[x][y] = Zboom;
     Lboom_tank(x, y);
 
     return;
@@ -3586,6 +3668,7 @@ static void Ltank_1_w(int x, int y)
       is_amoeba[cave[x][y+1]] ||
       is_amoeba[cave[x-1][y]])
   {
+    next[x][y] = Zboom;
     Lboom_tank(x, y);
 
     return;
@@ -3633,6 +3716,7 @@ static void Ltank_2_w(int x, int y)
       is_amoeba[cave[x][y+1]] ||
       is_amoeba[cave[x-1][y]])
   {
+    next[x][y] = Zboom;
     Lboom_tank(x, y);
 
     return;
@@ -4393,16 +4477,20 @@ static void Lstone_fall(int x, int y)
     case Xeater_s:
     case Xeater_w:
       cave[x][y] = Ystone_sB;
+      next[x][y] = Xblank;
       cave[x][y+1] = Yeater_stone;
-      Lboom_eater(x, y+1);
+      next[x][y+1] = Zeater;
+      Lboom_eater_old(x, y+1);
       score += lev.eater_score;
       return;
 
     case Xalien:
     case Xalien_pause:
       cave[x][y] = Ystone_sB;
+      next[x][y] = Xblank;
       cave[x][y+1] = Yalien_stone;
-      Lboom_tank(x, y+1);
+      next[x][y+1] = Ztank;
+      Lboom_tank_old(x, y+1);
       score += lev.alien_score;
       return;
 
@@ -4415,8 +4503,10 @@ static void Lstone_fall(int x, int y)
     case Xbug_2_s:
     case Xbug_2_w:
       cave[x][y] = Ystone_sB;
+      next[x][y] = Xblank;
       cave[x][y+1] = Ybug_stone;
-      Lboom_bug(x, y+1);
+      next[x][y+1] = Zbug;
+      Lboom_bug_old(x, y+1);
       score += lev.bug_score;
       return;
 
@@ -4429,8 +4519,10 @@ static void Lstone_fall(int x, int y)
     case Xtank_2_s:
     case Xtank_2_w:
       cave[x][y] = Ystone_sB;
+      next[x][y] = Xblank;
       cave[x][y+1] = Ytank_stone;
-      Lboom_tank(x, y+1);
+      next[x][y+1] = Ztank;
+      Lboom_tank_old(x, y+1);
       score += lev.tank_score;
       return;
 
@@ -4506,8 +4598,11 @@ static void Lstone_fall(int x, int y)
 
     case Xbomb:
     case Xbomb_pause:
+      cave[x][y] = Xstone;
+      next[x][y] = Xstone;
       cave[x][y+1] = Ybomb_blank;
-      Lboom_tank(x, y+1);
+      next[x][y+1] = Ztank;
+      Lboom_tank_old(x, y+1);
       return;
 
     case Xnut:
@@ -4815,7 +4910,8 @@ static void Lbomb_fall(int x, int y)
 
     default:
       cave[x][y] = Ybomb_blank;
-      Lboom_tank(x, y);
+      next[x][y] = Ztank;
+      Lboom_tank_old(x, y);
       return;
   }
 }
@@ -5509,16 +5605,20 @@ static void Lspring_fall(int x, int y)
     case Xeater_s:
     case Xeater_w:
       cave[x][y] = Yspring_sB;
+      next[x][y] = Xblank;
       cave[x][y+1] = Yeater_spring;
-      Lboom_eater(x, y+1);
+      next[x][y+1] = Zeater;
+      Lboom_eater_old(x, y+1);
       score += lev.eater_score;
       return;
 
     case Xalien:
     case Xalien_pause:
       cave[x][y] = Yspring_sB;
+      next[x][y] = Xblank;
       cave[x][y+1] = Yalien_spring;
-      Lboom_tank(x, y+1);
+      next[x][y+1] = Ztank;
+      Lboom_tank_old(x, y+1);
       score += lev.alien_score;
       return;
 
@@ -5531,8 +5631,10 @@ static void Lspring_fall(int x, int y)
     case Xbug_2_s:
     case Xbug_2_w:
       cave[x][y] = Yspring_sB;
+      next[x][y] = Xblank;
       cave[x][y+1] = Ybug_spring;
-      Lboom_bug(x, y+1);
+      next[x][y+1] = Zbug;
+      Lboom_bug_old(x, y+1);
       score += lev.bug_score;
       return;
 
@@ -5545,15 +5647,20 @@ static void Lspring_fall(int x, int y)
     case Xtank_2_s:
     case Xtank_2_w:
       cave[x][y] = Yspring_sB;
+      next[x][y] = Xblank;
       cave[x][y+1] = Ytank_spring;
-      Lboom_tank(x, y+1);
+      next[x][y+1] = Ztank;
+      Lboom_tank_old(x, y+1);
       score += lev.tank_score;
       return;
 
     case Xbomb:
     case Xbomb_pause:
+      cave[x][y] = Xspring;
+      next[x][y] = Xspring;
       cave[x][y+1] = Ybomb_blank;
-      Lboom_tank(x, y+1);
+      next[x][y+1] = Ztank;
+      Lboom_tank_old(x, y+1);
       return;
 
     default:
@@ -5576,6 +5683,8 @@ static void Lpush_emerald_e(int x, int y)
     case Ztank:
     case Zeater:
     case Zdynamite:
+    case Zboom:
+    case Xchain:
     case Xboom_bug:
     case Xboom_tank:
     case Xboom_android:
@@ -5616,6 +5725,8 @@ static void Lpush_emerald_w(int x, int y)
     case Ztank:
     case Zeater:
     case Zdynamite:
+    case Zboom:
+    case Xchain:
     case Xboom_bug:
     case Xboom_tank:
     case Xboom_android:
@@ -5656,6 +5767,8 @@ static void Lpush_diamond_e(int x, int y)
     case Ztank:
     case Zeater:
     case Zdynamite:
+    case Zboom:
+    case Xchain:
     case Xboom_bug:
     case Xboom_tank:
     case Xboom_android:
@@ -5696,6 +5809,8 @@ static void Lpush_diamond_w(int x, int y)
     case Ztank:
     case Zeater:
     case Zdynamite:
+    case Zboom:
+    case Xchain:
     case Xboom_bug:
     case Xboom_tank:
     case Xboom_android:
@@ -5736,6 +5851,8 @@ static void Lpush_stone_e(int x, int y)
     case Ztank:
     case Zeater:
     case Zdynamite:
+    case Zboom:
+    case Xchain:
     case Xboom_bug:
     case Xboom_tank:
     case Xboom_android:
@@ -5776,6 +5893,8 @@ static void Lpush_stone_w(int x, int y)
     case Ztank:
     case Zeater:
     case Zdynamite:
+    case Zboom:
+    case Xchain:
     case Xboom_bug:
     case Xboom_tank:
     case Xboom_android:
@@ -5816,6 +5935,8 @@ static void Lpush_bomb_e(int x, int y)
     case Ztank:
     case Zeater:
     case Zdynamite:
+    case Zboom:
+    case Xchain:
     case Xboom_bug:
     case Xboom_tank:
     case Xboom_android:
@@ -5856,6 +5977,8 @@ static void Lpush_bomb_w(int x, int y)
     case Ztank:
     case Zeater:
     case Zdynamite:
+    case Zboom:
+    case Xchain:
     case Xboom_bug:
     case Xboom_tank:
     case Xboom_android:
@@ -5896,6 +6019,8 @@ static void Lpush_nut_e(int x, int y)
     case Ztank:
     case Zeater:
     case Zdynamite:
+    case Zboom:
+    case Xchain:
     case Xboom_bug:
     case Xboom_tank:
     case Xboom_android:
@@ -5936,6 +6061,8 @@ static void Lpush_nut_w(int x, int y)
     case Ztank:
     case Zeater:
     case Zdynamite:
+    case Zboom:
+    case Xchain:
     case Xboom_bug:
     case Xboom_tank:
     case Xboom_android:
@@ -5976,6 +6103,8 @@ static void Lpush_spring_e(int x, int y)
     case Ztank:
     case Zeater:
     case Zdynamite:
+    case Zboom:
+    case Xchain:
     case Xboom_bug:
     case Xboom_tank:
     case Xboom_android:
@@ -6016,6 +6145,8 @@ static void Lpush_spring_w(int x, int y)
     case Ztank:
     case Zeater:
     case Zdynamite:
+    case Zboom:
+    case Xchain:
     case Xboom_bug:
     case Xboom_tank:
     case Xboom_android:
@@ -6815,6 +6946,8 @@ static void Lboom_one(int x, int y, boolean by_dynamite)
     case Ztank:
     case Zeater:
     case Zdynamite:
+    case Zboom:
+    case Xchain:
     case Xboom_bug:
     case Xboom_tank:
     case Xboom_android:
@@ -6877,12 +7010,14 @@ static void Lboom_one(int x, int y, boolean by_dynamite)
     case Xbug_2_s:
     case Xbug_2_w:
       cave[x][y] = Xboom_bug;
+      Lboom_bug_new(x, y, TRUE);
       return;
 
     case Xbomb:
     case Xbomb_pause:
     case Xbomb_fall:
       cave[x][y] = Xboom_tank;
+      Lboom_tank_new(x, y, TRUE);
       return;
 
     default:
@@ -6910,20 +7045,27 @@ static void Lexplode(int x, int y)
   switch (cave[x][y])
   {
     case Zbug:
+      Lboom_bug_new(x, y, FALSE);
       Lboom_nine(x, y, FALSE);
       break;
 
     case Ztank:
+      Lboom_tank_new(x, y, FALSE);
       Lboom_nine(x, y, FALSE);
       break;
 
     case Zeater:
+      Lboom_eater_new(x, y, FALSE);
       Lboom_nine(x, y, FALSE);
       break;
 
     case Zdynamite:
       Lboom_nine(x, y, TRUE);
       break;
+
+    case Zboom:
+      Lboom_nine(x, y, FALSE);
+      break;
   }
 }
 
@@ -6952,6 +7094,11 @@ static void Lboom_android(int x, int y)
   Lboom_1(x, y);
 }
 
+static void Lchain(int x, int y)
+{
+  next[x][y] = Zboom;
+}
+
 static void handle_tile(int x, int y)
 {
   switch (cave[x][y])
@@ -7111,6 +7258,7 @@ static void handle_tile(int x, int y)
 
     case Xpause:               Lpause(x, y);                   break;
 
+    case Xchain:               Lchain(x, y);                   break;
     case Xboom_bug:            Lboom_bug(x, y);                break;
     case Xboom_tank:           Lboom_tank(x, y);               break;
     case Xboom_android:                Lboom_android(x, y);            break;
index 366303b22e49d5236b65e5ebe2b04186a6cd8f8e..83620631c3ea9a8873936122d7b7a1b087f7c6bd 100644 (file)
@@ -5763,7 +5763,15 @@ em_object_mapping_list[] =
     Zdynamite,                         FALSE,  FALSE,
     EL_EMPTY,                          -1, -1
   },
+  {
+    Zboom,                             FALSE,  FALSE,
+    EL_EMPTY,                          -1, -1
+  },
 
+  {
+    Xchain,                            FALSE,  FALSE,
+    EL_DEFAULT,                                ACTION_EXPLODING, -1
+  },
   {
     Xboom_bug,                         FALSE,  FALSE,
     EL_BUG,                            ACTION_EXPLODING, -1