added support for "player is pushing" graphics for BD engine
authorHolger Schemel <info@artsoft.org>
Sun, 14 Apr 2024 18:38:44 +0000 (20:38 +0200)
committerHolger Schemel <info@artsoft.org>
Sun, 14 Apr 2024 19:06:14 +0000 (21:06 +0200)
src/game_bd/bd_cave.c
src/game_bd/bd_cave.h
src/game_bd/bd_cavedb.c
src/game_bd/bd_caveengine.c
src/game_bd/bd_caveengine.h
src/game_bd/bd_elements.h
src/game_bd/bd_gameplay.c
src/tools.c

index a115cb00111e0266a596c33320086bd6bc687a7d..8cc703a493a7022241d47e4e63467cd7e95fc06d 100644 (file)
@@ -1316,7 +1316,8 @@ void gd_cave_count_diamonds(GdCave *cave)
   if a cell is changed, it is flagged with GD_REDRAW; the flag can be cleared
   by the caller.
 */
-void gd_drawcave_game(const GdCave *cave, int **element_buffer, int **gfx_buffer,
+void gd_drawcave_game(const GdCave *cave,
+                     int **element_buffer, int **last_element_buffer, int **gfx_buffer,
                      boolean bonus_life_flash, int animcycle, boolean hate_invisible_outbox)
 {
   static int player_blinking = 0;
@@ -1539,6 +1540,27 @@ void gd_drawcave_game(const GdCave *cave, int **element_buffer, int **gfx_buffer
       else
        draw = elemdrawing[actual];
 
+      // draw special graphics if player is pushing something
+      if ((cave->last_direction == GD_MV_LEFT || cave->last_direction == GD_MV_RIGHT) &&
+         is_player(cave, x, y) && can_be_pushed_dir(cave, x, y, cave->last_direction))
+      {
+       // special check needed when smooth game element movements selected in setup menu:
+       // last element must either be player (before pushing) or pushable element (while pushing)
+       // (extra check needed to prevent pushing animation when moving towards pushable element)
+       if (!use_bd_smooth_movements() || last_element_buffer[y][x] != O_SPACE)
+       {
+         if (cave->last_direction == GD_MV_LEFT)
+           map = O_PLAYER_PUSH_LEFT;
+         else
+           map = O_PLAYER_PUSH_RIGHT;
+
+         if (cave->last_direction == GD_MV_LEFT)
+           draw = elemdrawing[O_PLAYER_PUSH_LEFT];
+         else
+           draw = elemdrawing[O_PLAYER_PUSH_RIGHT];
+       }
+      }
+
       // if negative, animated.
       if (draw < 0)
        draw = -draw + animcycle;
index c76923a9f75980681728083dc5c3f426b11ab095..faa90069f65a790d395039b8b787049e74223c1e 100644 (file)
@@ -82,7 +82,7 @@ void gd_struct_set_defaults_from_array(void *str, const GdStructDescriptor *prop
 
 // these define the number of the cells in the png file
 #define GD_NUM_OF_CELLS_X      8
-#define GD_NUM_OF_CELLS_Y      47
+#define GD_NUM_OF_CELLS_Y      51
 
 // +80: placeholder for cells which are rendered by the game;
 // for example diamond + arrow = falling diamond
@@ -697,7 +697,8 @@ GdScheduling gd_scheduling_from_string(const char *str);
 // game playing helpers
 #define GD_REDRAW (1 << 10)
 
-void gd_drawcave_game(const GdCave *cave, int **element_buffer, int **gfx_buffer,
+void gd_drawcave_game(const GdCave *cave,
+                     int **element_buffer, int **last_element_buffer, int **gfx_buffer,
                      boolean bonus_life_flash, int animcycle, boolean hate_invisible_outbox);
 
 // function to copy a GdString
index 88e83d6ec4e65eb7b72b6444552ed3f9318301b0..ff9df20552936eba610ef7360dfa204882612f59 100644 (file)
@@ -377,6 +377,8 @@ GdElements gd_elements[] =
   { O_PLAYER_TAP, NULL, P_PLAYER, NULL, 0, 216, -216, -216 },
   { O_PLAYER_BLINK, NULL, P_PLAYER, NULL, 0, 208, -208, -208 },
   { O_PLAYER_TAP_BLINK, NULL, P_PLAYER, NULL, 0, 224, -224, -224 },
+  { O_PLAYER_PUSH_LEFT, N_("Player, pushing left"), P_PLAYER, NULL, 0, 392, -392, -392 },
+  { O_PLAYER_PUSH_RIGHT, N_("Player, pushing right"), P_PLAYER, NULL, 0, 400, -400, -400 },
   { O_CREATURE_SWITCH_ON, NULL, 0, NULL, 0, 19, 19, 19 },
   { O_EXPANDING_WALL_SWITCH_HORIZ, NULL, 0, NULL, 0, 40, 40, 40 },
   { O_EXPANDING_WALL_SWITCH_VERT, NULL, 0, NULL, 0, 41, 41, 41 },
index e221ca7784551455c8e7e5d376129f8c31dac05b..e174f916bfc7329a1f83c9d295dc2723b9672a1f 100644 (file)
@@ -449,7 +449,7 @@ static inline boolean rotates_ccw (const GdCave *cave, const int x, const int y)
 }
 
 // returns true if the element is a player
-static inline boolean is_player(const GdCave *cave, const int x, const int y)
+boolean is_player(const GdCave *cave, const int x, const int y)
 {
   return (gd_elements[get(cave, x, y) & O_MASK].properties & P_PLAYER) != 0;
 }
@@ -467,6 +467,13 @@ static inline boolean can_be_hammered_dir(const GdCave *cave, const int x, const
   return (gd_elements[get_dir(cave, x, y, dir) & O_MASK].properties & P_CAN_BE_HAMMERED) != 0;
 }
 
+// returns true if the element can be pushed
+boolean can_be_pushed_dir(const GdCave *cave, const int x, const int y,
+                         const GdDirection dir)
+{
+  return (gd_elements[get_dir(cave, x, y, dir) & O_MASK].properties & P_PUSHABLE) != 0;
+}
+
 // returns true if the element is explodable and explodes to space, for example the player
 static inline boolean is_first_stage_of_explosion(const GdCave *cave, const int x, const int y)
 {
index 0c1a67cfe2a71d240a26872a977a349d1956c042..b4c44f5b104e6d073e7b8cf72238c33b4024573f 100644 (file)
@@ -21,6 +21,8 @@
 
 
 // the game itself
+boolean is_player(const GdCave *cave, const int x, const int y);
+boolean can_be_pushed_dir(const GdCave *cave, const int x, const int y, const GdDirection dir);
 GdDirection gd_direction_from_keypress(boolean up, boolean down, boolean left, boolean right);
 void gd_cave_iterate(GdCave *cave, GdDirection player_move, boolean player_fire, boolean suicide);
 void set_initial_cave_speed(GdCave *cave);
index de04d23aa6de5d875beb012412633e570a8af5a2..34945ec73b6e295a0c15646209bb785b40f6ca9f 100644 (file)
@@ -282,6 +282,8 @@ typedef enum _element
   O_PLAYER_TAP,
   O_PLAYER_BLINK,
   O_PLAYER_TAP_BLINK,
+  O_PLAYER_PUSH_LEFT,
+  O_PLAYER_PUSH_RIGHT,
   O_CREATURE_SWITCH_ON,
   O_EXPANDING_WALL_SWITCH_HORIZ,
   O_EXPANDING_WALL_SWITCH_VERT,
index b287f085be9a68b4705c925654bdd7a327e88cfd..a981c81bcf8c4037d9625b00ae89f55d81c2ce88 100644 (file)
@@ -571,7 +571,7 @@ static GdGameState gd_game_main_int(GdGame *game, boolean allow_iterate, boolean
   // always render the cave to the gfx buffer;
   // however it may do nothing if animcycle was not changed.
   if (game->element_buffer && game->gfx_buffer)
-    gd_drawcave_game(game->cave, game->element_buffer, game->gfx_buffer,
+    gd_drawcave_game(game->cave, game->element_buffer, game->last_element_buffer, game->gfx_buffer,
                     game->bonus_life_flash != 0, game->animcycle, gd_no_invisible_outbox);
 
   game->state_counter = counter_next;
index 1fe6fccc6306529554ed1f797cee6f8c8cd8373e..7734259098d5cb2023b42e14fb5cbcb0919a81c1 100644 (file)
@@ -7493,6 +7493,14 @@ bd_object_mapping_list[] =
     O_PLAYER_TAP_BLINK,                                FALSE,
     EL_BD_PLAYER,                              ACTION_BORING_3, -1
   },
+  {
+    O_PLAYER_PUSH_LEFT,                                FALSE,
+    EL_BD_PLAYER,                              ACTION_PUSHING, MV_BIT_LEFT
+  },
+  {
+    O_PLAYER_PUSH_RIGHT,                       FALSE,
+    EL_BD_PLAYER,                              ACTION_PUSHING, MV_BIT_RIGHT
+  },
   {
     O_CREATURE_SWITCH_ON,                      FALSE,
     EL_BD_CREATURE_SWITCH_ACTIVE,              -1, -1