added new steel slope game element for MM game engine
authorHolger Schemel <info@artsoft.org>
Sat, 6 May 2023 12:34:58 +0000 (14:34 +0200)
committerHolger Schemel <info@artsoft.org>
Wed, 17 May 2023 06:27:03 +0000 (08:27 +0200)
docs/elements/df_slope.txt [new file with mode: 0644]
graphics/gfx_classic/RocksDF.png
src/conf_gfx.c
src/editor.c
src/game_mm/export.h
src/game_mm/mm_game.c
src/game_mm/mm_main.h
src/game_mm/mm_tools.c
src/main.c
src/main.h

diff --git a/docs/elements/df_slope.txt b/docs/elements/df_slope.txt
new file mode 100644 (file)
index 0000000..ac49f18
--- /dev/null
@@ -0,0 +1 @@
+Steel slopes reflect the laser beam similar to steel walls.
index 3d881babd8129d136d44cd45867a9f0713726203..9bf2b6122f5194ab90e2f6218de7712fc995371a 100644 (file)
Binary files a/graphics/gfx_classic/RocksDF.png and b/graphics/gfx_classic/RocksDF.png differ
index 67fc180735f169d3126d98458508b3c4d3d583c8..be3f35770ca116843436e562b4b12f94157acecb 100644 (file)
@@ -5852,6 +5852,23 @@ struct ConfigInfo image_config[] =
   { "df_mirror_fixed_16.ypos",                 "10"                    },
   { "df_mirror_fixed_16.frames",               "1"                     },
 
+  { "df_slope_1",                              "RocksDF.png"           },
+  { "df_slope_1.xpos",                         "0"                     },
+  { "df_slope_1.ypos",                         "11"                    },
+  { "df_slope_1.frames",                       "1"                     },
+  { "df_slope_2",                              "RocksDF.png"           },
+  { "df_slope_2.xpos",                         "1"                     },
+  { "df_slope_2.ypos",                         "11"                    },
+  { "df_slope_2.frames",                       "1"                     },
+  { "df_slope_3",                              "RocksDF.png"           },
+  { "df_slope_3.xpos",                         "2"                     },
+  { "df_slope_3.ypos",                         "11"                    },
+  { "df_slope_3.frames",                       "1"                     },
+  { "df_slope_4",                              "RocksDF.png"           },
+  { "df_slope_4.xpos",                         "3"                     },
+  { "df_slope_4.ypos",                         "11"                    },
+  { "df_slope_4.frames",                       "1"                     },
+
   // (these are only defined as elements to support ".PANEL" definitions)
   { "graphic_1",                               UNDEFINED_FILENAME      },
   { "graphic_2",                               UNDEFINED_FILENAME      },
index 7c9020702bf6c9aa3d99ca61f41b597a45aa983d..d4e2bc8e8015cde39b646a1587ed700c69fd5639 100644 (file)
@@ -4713,7 +4713,12 @@ static int editor_el_deflektor[] =
   EL_DF_STEEL_WALL,
   EL_DF_WOODEN_WALL,
   EL_DF_REFRACTOR,
-  EL_DF_MINE
+  EL_DF_MINE,
+
+  EL_DF_SLOPE_1,
+  EL_DF_SLOPE_2,
+  EL_DF_SLOPE_3,
+  EL_DF_SLOPE_4
 };
 static int *editor_hl_deflektor_ptr = editor_hl_deflektor;
 static int *editor_el_deflektor_ptr = editor_el_deflektor;
@@ -11702,6 +11707,12 @@ static void SetElementIntelliDraw(int x, int y, int dx, int dy, int new_element,
        EL_DF_RECEIVER_DOWN,
        EL_DF_RECEIVER_LEFT
       },
+      {
+       EL_DF_SLOPE_1,
+       EL_DF_SLOPE_4,
+       EL_DF_SLOPE_3,
+       EL_DF_SLOPE_2
+      },
 
       {
        -1,
index 184ce216cbbba739aac087e1e672cb05a4c44109..b555511bd80b03181cdba1abe55b8a3f015ece04 100644 (file)
@@ -43,7 +43,7 @@
 #define EL_MM_END_2_NATIVE             430
 
 #define EL_MM_START_3_NATIVE           431
-#define EL_MM_END_3_NATIVE             446
+#define EL_MM_END_3_NATIVE             450
 
 #define EL_MM_RUNTIME_START_NATIVE     500
 #define EL_MM_RUNTIME_END_NATIVE       504
index a5b34f290936e49ac503786a01760362e785a201..204ddf63a95daef1328ee1d399f8a304fd4348ee 100644 (file)
@@ -139,10 +139,14 @@ static DelayCounter overload_delay = { 0 };
 #define MM_MASK_GRID_2         5
 #define MM_MASK_GRID_3         6
 #define MM_MASK_GRID_4         7
-#define MM_MASK_RECTANGLE      8
-#define MM_MASK_CIRCLE         9
+#define MM_MASK_SLOPE_1                8
+#define MM_MASK_SLOPE_2                9
+#define MM_MASK_SLOPE_3                10
+#define MM_MASK_SLOPE_4                11
+#define MM_MASK_RECTANGLE      12
+#define MM_MASK_CIRCLE         13
 
-#define NUM_MM_MASKS           10
+#define NUM_MM_MASKS           14
 
 // element masks for scanning pixels of MM elements
 static const char mm_masks[NUM_MM_MASKS][16][16 + 1] =
@@ -291,6 +295,78 @@ static const char mm_masks[NUM_MM_MASKS][16][16 + 1] =
     "    XXX  XXXX   ",
     "     XX  XXXXX  ",
   },
+  {
+    "               X",
+    "              XX",
+    "             XXX",
+    "            XXXX",
+    "           XXXXX",
+    "          XXXXXX",
+    "         XXXXXXX",
+    "        XXXXXXXX",
+    "       XXXXXXXXX",
+    "      XXXXXXXXXX",
+    "     XXXXXXXXXXX",
+    "    XXXXXXXXXXXX",
+    "   XXXXXXXXXXXXX",
+    "  XXXXXXXXXXXXXX",
+    " XXXXXXXXXXXXXXX",
+    "XXXXXXXXXXXXXXXX",
+  },
+  {
+    "X               ",
+    "XX              ",
+    "XXX             ",
+    "XXXX            ",
+    "XXXXX           ",
+    "XXXXXX          ",
+    "XXXXXXX         ",
+    "XXXXXXXX        ",
+    "XXXXXXXXX       ",
+    "XXXXXXXXXX      ",
+    "XXXXXXXXXXX     ",
+    "XXXXXXXXXXXX    ",
+    "XXXXXXXXXXXXX   ",
+    "XXXXXXXXXXXXXX  ",
+    "XXXXXXXXXXXXXXX ",
+    "XXXXXXXXXXXXXXXX",
+  },
+  {
+    "XXXXXXXXXXXXXXXX",
+    "XXXXXXXXXXXXXXX ",
+    "XXXXXXXXXXXXXX  ",
+    "XXXXXXXXXXXXX   ",
+    "XXXXXXXXXXXX    ",
+    "XXXXXXXXXXX     ",
+    "XXXXXXXXXX      ",
+    "XXXXXXXXX       ",
+    "XXXXXXXX        ",
+    "XXXXXXX         ",
+    "XXXXXX          ",
+    "XXXXX           ",
+    "XXXX            ",
+    "XXX             ",
+    "XX              ",
+    "X               ",
+  },
+  {
+    "XXXXXXXXXXXXXXXX",
+    " XXXXXXXXXXXXXXX",
+    "  XXXXXXXXXXXXXX",
+    "   XXXXXXXXXXXXX",
+    "    XXXXXXXXXXXX",
+    "     XXXXXXXXXXX",
+    "      XXXXXXXXXX",
+    "       XXXXXXXXX",
+    "        XXXXXXXX",
+    "         XXXXXXX",
+    "          XXXXXX",
+    "           XXXXX",
+    "            XXXX",
+    "             XXX",
+    "              XX",
+    "               X",
+  },
   {
     "XXXXXXXXXXXXXXXX",
     "XXXXXXXXXXXXXXXX",
@@ -338,6 +414,8 @@ static int get_element_angle(int element)
       IS_LASER(element) ||
       IS_RECEIVER(element))
     return 4 * element_phase;
+  else if (IS_DF_SLOPE(element))
+    return 4 + (element_phase % 2) * 8;
   else
     return element_phase;
 }
@@ -887,6 +965,8 @@ static int getMaskFromElement(int element)
     return MM_MASK_GRID_1 + get_element_phase(element);
   else if (IS_DF_GRID(element))
     return MM_MASK_RECTANGLE;
+  else if (IS_DF_SLOPE(element))
+    return MM_MASK_SLOPE_1 + get_element_phase(element);
   else if (IS_RECTANGLE(element))
     return MM_MASK_RECTANGLE;
   else
@@ -1121,10 +1201,14 @@ static void ScanLaser(void)
       break;
     }
 
+    boolean diagonally_adjacent_hit = FALSE;
+
     // handle special case of laser hitting two diagonally adjacent elements
     // (with or without a third corner element behind these two elements)
     if ((diag_1 || diag_2) && cross_x && cross_y)
     {
+      diagonally_adjacent_hit = TRUE;
+
       // compare the two diagonally adjacent elements
       int xoffset = 2;
       int yoffset = 2 * (diag_1 ? -1 : +1);
@@ -1240,6 +1324,29 @@ static void ScanLaser(void)
          break;
       }
     }
+    else if (IS_DF_SLOPE(element))
+    {
+      if (diagonally_adjacent_hit)
+      {
+       laser.overloaded = TRUE;
+
+       break;
+      }
+
+      if (hit_mask == HIT_MASK_LEFT ||
+         hit_mask == HIT_MASK_RIGHT ||
+         hit_mask == HIT_MASK_TOP ||
+         hit_mask == HIT_MASK_BOTTOM)
+      {
+       if (HitReflectingWalls(element, hit_mask))
+         break;
+      }
+      else
+      {
+       if (HitElement(element, hit_mask))
+         break;
+      }
+    }
     else
     {
       if (HitElement(element, hit_mask))
@@ -1594,8 +1701,30 @@ void DrawLaser_MM(void)
 
 static boolean HitElement(int element, int hit_mask)
 {
-  if (HitOnlyAnEdge(hit_mask))
-    return FALSE;
+  if (IS_DF_SLOPE(element))
+  {
+    int mirrored_angle = get_mirrored_angle(laser.current_angle,
+                                           get_element_angle(element));
+    int opposite_angle = get_opposite_angle(laser.current_angle);
+
+    // check if laser is reflected by slope by 180°
+    if (mirrored_angle == opposite_angle)
+    {
+      LX += XS;
+      LY += YS;
+
+      AddDamagedField(LX / TILEX, LY / TILEY);
+
+      laser.overloaded = TRUE;
+
+      return TRUE;
+    }
+  }
+  else
+  {
+    if (HitOnlyAnEdge(hit_mask))
+      return FALSE;
+  }
 
   if (IS_MOVING(ELX, ELY) || IS_BLOCKED(ELX, ELY))
     element = MovingOrBlocked2Element_MM(ELX, ELY);
@@ -1615,8 +1744,11 @@ static boolean HitElement(int element, int hit_mask)
 
   AddDamagedField(ELX, ELY);
 
+  boolean through_center = ((ELX * TILEX + 14 - LX) * YS ==
+                           (ELY * TILEY + 14 - LY) * XS);
+
   // this is more precise: check if laser would go through the center
-  if ((ELX * TILEX + 14 - LX) * YS != (ELY * TILEY + 14 - LY) * XS)
+  if (!IS_DF_SLOPE(element) && !through_center)
   {
     int skip_count = 0;
 
@@ -1687,10 +1819,28 @@ static boolean HitElement(int element, int hit_mask)
     return TRUE;
   }
 
-  if (!IS_BEAMER(element) &&
-      !IS_FIBRE_OPTIC(element) &&
-      !IS_GRID_WOOD(element) &&
-      element != EL_FUEL_EMPTY)
+  if (IS_DF_SLOPE(element) && !through_center)
+  {
+    int correction = 2;
+
+    if (hit_mask == HIT_MASK_ALL)
+    {
+      // laser already inside slope -- go back half step
+      LX -= XS / 2;
+      LY -= YS / 2;
+
+      correction = 1;
+    }
+
+    AddLaserEdge(LX, LY);
+
+    LX -= (ABS(XS) < ABS(YS) ? correction * SIGN(XS) : 0);
+    LY -= (ABS(YS) < ABS(XS) ? correction * SIGN(YS) : 0);
+  }
+  else if (!IS_BEAMER(element) &&
+          !IS_FIBRE_OPTIC(element) &&
+          !IS_GRID_WOOD(element) &&
+          element != EL_FUEL_EMPTY)
   {
 #if 0
     if ((ELX * TILEX + 14 - LX) * YS == (ELY * TILEY + 14 - LY) * XS)
@@ -1712,6 +1862,7 @@ static boolean HitElement(int element, int hit_mask)
       IS_DF_MIRROR(element) ||
       IS_DF_MIRROR_AUTO(element) ||
       IS_DF_MIRROR_FIXED(element) ||
+      IS_DF_SLOPE(element) ||
       element == EL_PRISM ||
       element == EL_REFRACTOR)
   {
@@ -1731,7 +1882,8 @@ static boolean HitElement(int element, int hit_mask)
        IS_MIRROR_FIXED(element) ||
        IS_DF_MIRROR(element) ||
        IS_DF_MIRROR_AUTO(element) ||
-       IS_DF_MIRROR_FIXED(element))
+       IS_DF_MIRROR_FIXED(element) ||
+       IS_DF_SLOPE(element))
       laser.current_angle = get_mirrored_angle(laser.current_angle,
                                               get_element_angle(element));
 
@@ -1766,6 +1918,68 @@ static boolean HitElement(int element, int hit_mask)
       (get_opposite_angle(laser.current_angle) ==
        laser.damage[laser.num_damages - 1].angle ? TRUE : FALSE);
 
+    if (IS_DF_SLOPE(element))
+    {
+      // handle special cases for slope element
+
+      if (IS_45_ANGLE(laser.current_angle))
+      {
+       int elx, ely;
+
+       elx = getLevelFromLaserX(LX);
+       ely = getLevelFromLaserY(LY);
+
+       if (IN_LEV_FIELD(elx, ely))
+       {
+         int element_next = Tile[elx][ely];
+
+         // check if slope is followed by slope with opposite orientation
+         if (IS_DF_SLOPE(element_next) && ABS(element - element_next) == 2)
+           laser.overloaded = TRUE;
+       }
+
+       int nr = element - EL_DF_SLOPE_START;
+       int dx = (nr == 0 ? (XS > 0 ? TILEX - 1 : -1) :
+                 nr == 1 ? (XS > 0 ? TILEX     :  1) :
+                 nr == 2 ? (XS > 0 ? TILEX     :  1) :
+                 nr == 3 ? (XS > 0 ? TILEX - 1 : -1) : 0);
+       int dy = (nr == 0 ? (YS > 0 ? TILEY - 1 : -1) :
+                 nr == 1 ? (YS > 0 ? TILEY - 1 : -1) :
+                 nr == 2 ? (YS > 0 ? TILEY     :  0) :
+                 nr == 3 ? (YS > 0 ? TILEY     :  0) : 0);
+
+       int px = ELX * TILEX + dx;
+       int py = ELY * TILEY + dy;
+
+       dx = px % TILEX;
+       dy = py % TILEY;
+
+       elx = getLevelFromLaserX(px);
+       ely = getLevelFromLaserY(py);
+
+       if (IN_LEV_FIELD(elx, ely))
+       {
+         int element_side = Tile[elx][ely];
+
+         // check if end of slope is blocked by other element
+         if (IS_WALL(element_side) || IS_WALL_CHANGING(element_side))
+         {
+           int pos = dy / MINI_TILEY * 2 + dx / MINI_TILEX;
+
+           if (element & (1 << pos))
+             laser.overloaded = TRUE;
+         }
+         else
+         {
+           int pos = getMaskFromElement(element_side);
+
+           if (mm_masks[pos][dx / 2][dx / 2] == 'X')
+             laser.overloaded = TRUE;
+         }
+       }
+      }
+    }
+
     return (laser.overloaded ? TRUE : FALSE);
   }
 
index b9dd47a80befeace95c44257975565f718c0f201..684647ce12ea77ca52aff8fc88a27288e7fb452f 100644 (file)
                                 (e) <= EL_DF_MIRROR_AUTO_END)
 #define IS_DF_MIRROR_FIXED(e)  ((e) >= EL_DF_MIRROR_FIXED_START &&     \
                                 (e) <= EL_DF_MIRROR_FIXED_END)
+#define IS_DF_SLOPE(e)         ((e) >= EL_DF_SLOPE_START &&            \
+                                (e) <= EL_DF_SLOPE_END)
 #define IS_LASER(e)            ((e) >= EL_LASER_START &&               \
                                 (e) <= EL_LASER_END)
 #define IS_RECEIVER(e)         ((e) >= EL_RECEIVER_START &&            \
@@ -606,7 +608,14 @@ extern int         num_element_info;
 #define EL_DF_MIRROR_FIXED_15  (EL_DF_MIRROR_FIXED_START + 15)
 #define EL_DF_MIRROR_FIXED_END EL_DF_MIRROR_FIXED_15
 
-#define EL_MM_END_2            446
+#define EL_DF_SLOPE_START       447
+#define EL_DF_SLOPE_00         (EL_DF_SLOPE_START + 0)
+#define EL_DF_SLOPE_01         (EL_DF_SLOPE_START + 1)
+#define EL_DF_SLOPE_02         (EL_DF_SLOPE_START + 2)
+#define EL_DF_SLOPE_03         (EL_DF_SLOPE_START + 3)
+#define EL_DF_SLOPE_END                EL_DF_SLOPE_03
+
+#define EL_MM_END_2            450
 #define EL_MM_END              EL_MM_END_2
 
 // "real" (and therefore drawable) runtime elements
@@ -714,6 +723,7 @@ extern int          num_element_info;
 #define ANG_RAY_270            12
 #define IS_22_5_ANGLE(angle)   ((angle) % 2)
 #define IS_90_ANGLE(angle)     (!((angle) % 4))
+#define IS_45_ANGLE(angle)     (!(((angle) + 2) % 4))
 #define IS_HORIZ_ANGLE(angle)  (!((angle) % 8))
 #define IS_VERT_ANGLE(angle)   (!(((angle) + 4) % 8))
 
index aa9c2a5d0aab5cbdeed125d1961bdd6b7d417cc7..6aeadd315726deeddbcd3f6776d78ab00be46d21 100644 (file)
@@ -1149,6 +1149,8 @@ int get_base_element(int element)
     return EL_DF_MIRROR_AUTO_START;
   else if (IS_DF_MIRROR_FIXED(element))
     return EL_DF_MIRROR_FIXED_START;
+  else if (IS_DF_SLOPE(element))
+    return EL_DF_SLOPE_START;
   else if (IS_PACMAN(element))
     return EL_PACMAN_START;
   else if (IS_GRID_STEEL(element))
@@ -1207,7 +1209,8 @@ int get_num_elements(int element)
           IS_RECEIVER(element) ||
           IS_PACMAN(element) ||
           IS_GRID_STEEL(element) ||
-          IS_GRID_WOOD(element))
+          IS_GRID_WOOD(element) ||
+          IS_DF_SLOPE(element))
     return 4;
   else
     return 1;
@@ -1278,6 +1281,13 @@ static int getFlippedTileExt_MM(int element, int mode)
          (mode != MM_FLIP_XY && element_phase > 1))
        element_phase ^= 1;
     }
+    else if (IS_DF_SLOPE(element))
+    {
+      element_phase = (mode == MM_FLIP_X  ? 5 - element_phase :
+                      mode == MM_FLIP_Y  ? 3 - element_phase :
+                      mode == MM_FLIP_XY ? 4 - element_phase :
+                      element_phase);
+    }
     else
     {
       int num_elements_flip = num_elements;
index 04576fe0648d20bfc5184af02fea7bbe2da9ed0e..bb8e1f0d7b5cbdec63e273b9ff0eb1424d6530f9 100644 (file)
@@ -6440,6 +6440,26 @@ struct ElementNameInfo element_name_info[MAX_NUM_ELEMENTS + 1] =
     "df_mirror_fixed",
     "fixed mirror (DF style) (168.75\xb0)"
   },
+  {
+    "df_slope_1",
+    "df_slope",
+    "slope (DF style) (45\xb0)"
+  },
+  {
+    "df_slope_2",
+    "df_slope",
+    "slope (DF style) (135\xb0)"
+  },
+  {
+    "df_slope_3",
+    "df_slope",
+    "slope (DF style) (225\xb0)"
+  },
+  {
+    "df_slope_4",
+    "df_slope",
+    "slope (DF style) (315\xb0)"
+  },
 
   // --------------------------------------------------------------------------
   // "real" (and therefore drawable) runtime elements
index 48752bd0ea54c1d6ee40e74b44741a10a7a82458..f021fd743794edec53298d7a7e9372b5ca4b8104 100644 (file)
 #define EL_DF_MIRROR_FIXED_16          (EL_DF_MIRROR_FIXED_START + 15)
 #define EL_DF_MIRROR_FIXED_END         EL_DF_MIRROR_FIXED_16
 
-#define EL_MM_END_3                    EL_DF_MIRROR_FIXED_END
-#define EL_DF_END_2                    EL_DF_MIRROR_FIXED_END
+#define EL_DF_SLOPE_START              1249
+#define EL_DF_SLOPE_1                  (EL_DF_SLOPE_START + 0)
+#define EL_DF_SLOPE_2                  (EL_DF_SLOPE_START + 1)
+#define EL_DF_SLOPE_3                  (EL_DF_SLOPE_START + 2)
+#define EL_DF_SLOPE_4                  (EL_DF_SLOPE_START + 3)
+#define EL_DF_SLOPE_END                        EL_DF_SLOPE_4
 
-#define NUM_FILE_ELEMENTS              1249
+#define EL_MM_END_3                    EL_DF_SLOPE_END
+#define EL_DF_END_2                    EL_DF_SLOPE_END
+
+#define NUM_FILE_ELEMENTS              1253
 
 
 // "real" (and therefore drawable) runtime elements