home *** CD-ROM | disk | FTP | other *** search
/ GameStar Special 2004 August / GSSH0804.iso / Geschicklichkeit / RocksnDiamonds / rocksndiamonds.exe / rocksndiamonds-3.1.0 / src / game.c < prev    next >
C/C++ Source or Header  |  2004-06-06  |  320KB  |  12,330 lines

  1. /***********************************************************
  2. * Rocks'n'Diamonds -- McDuffin Strikes Back!               *
  3. *----------------------------------------------------------*
  4. * (c) 1995-2002 Artsoft Entertainment                      *
  5. *               Holger Schemel                             *
  6. *               Detmolder Strasse 189                      *
  7. *               33604 Bielefeld                            *
  8. *               Germany                                    *
  9. *               e-mail: info@artsoft.org                   *
  10. *----------------------------------------------------------*
  11. * game.c                                                   *
  12. ***********************************************************/
  13.  
  14. #include "libgame/libgame.h"
  15.  
  16. #include "game.h"
  17. #include "init.h"
  18. #include "tools.h"
  19. #include "screens.h"
  20. #include "files.h"
  21. #include "tape.h"
  22. #include "network.h"
  23.  
  24. /* this switch controls how rocks move horizontally */
  25. #define OLD_GAME_BEHAVIOUR    FALSE
  26.  
  27. /* EXPERIMENTAL STUFF */
  28. #define USE_NEW_AMOEBA_CODE    FALSE
  29.  
  30. /* for DigField() */
  31. #define DF_NO_PUSH        0
  32. #define DF_DIG            1
  33. #define DF_SNAP            2
  34.  
  35. /* for MovePlayer() */
  36. #define MF_NO_ACTION        0
  37. #define MF_MOVING        1
  38. #define MF_ACTION        2
  39.  
  40. /* for ScrollPlayer() */
  41. #define SCROLL_INIT        0
  42. #define SCROLL_GO_ON        1
  43.  
  44. /* for Explode() */
  45. #define EX_PHASE_START        0
  46. #define EX_TYPE_NONE        0
  47. #define EX_TYPE_NORMAL        (1 << 0)
  48. #define EX_TYPE_CENTER        (1 << 1)
  49. #define EX_TYPE_BORDER        (1 << 2)
  50. #define EX_TYPE_CROSS        (1 << 3)
  51. #define EX_TYPE_SINGLE_TILE    (EX_TYPE_CENTER | EX_TYPE_BORDER)
  52.  
  53. /* special positions in the game control window (relative to control window) */
  54. #define XX_LEVEL        37
  55. #define YY_LEVEL        20
  56. #define XX_EMERALDS        29
  57. #define YY_EMERALDS        54
  58. #define XX_DYNAMITE        29
  59. #define YY_DYNAMITE        89
  60. #define XX_KEYS            18
  61. #define YY_KEYS            123
  62. #define XX_SCORE        15
  63. #define YY_SCORE        159
  64. #define XX_TIME1        29
  65. #define XX_TIME2        30
  66. #define YY_TIME            194
  67.  
  68. /* special positions in the game control window (relative to main window) */
  69. #define DX_LEVEL        (DX + XX_LEVEL)
  70. #define DY_LEVEL        (DY + YY_LEVEL)
  71. #define DX_EMERALDS        (DX + XX_EMERALDS)
  72. #define DY_EMERALDS        (DY + YY_EMERALDS)
  73. #define DX_DYNAMITE        (DX + XX_DYNAMITE)
  74. #define DY_DYNAMITE        (DY + YY_DYNAMITE)
  75. #define DX_KEYS            (DX + XX_KEYS)
  76. #define DY_KEYS            (DY + YY_KEYS)
  77. #define DX_SCORE        (DX + XX_SCORE)
  78. #define DY_SCORE        (DY + YY_SCORE)
  79. #define DX_TIME1        (DX + XX_TIME1)
  80. #define DX_TIME2        (DX + XX_TIME2)
  81. #define DY_TIME            (DY + YY_TIME)
  82.  
  83. /* values for initial player move delay (initial delay counter value) */
  84. #define INITIAL_MOVE_DELAY_OFF    -1
  85. #define INITIAL_MOVE_DELAY_ON    0
  86.  
  87. /* values for player movement speed (which is in fact a delay value) */
  88. #define MOVE_DELAY_NORMAL_SPEED    8
  89. #define MOVE_DELAY_HIGH_SPEED    4
  90.  
  91. #define DOUBLE_MOVE_DELAY(x)    (x = (x <= MOVE_DELAY_HIGH_SPEED ? x * 2 : x))
  92. #define HALVE_MOVE_DELAY(x)    (x = (x >= MOVE_DELAY_HIGH_SPEED ? x / 2 : x))
  93. #define DOUBLE_PLAYER_SPEED(p)    (HALVE_MOVE_DELAY((p)->move_delay_value))
  94. #define HALVE_PLAYER_SPEED(p)    (DOUBLE_MOVE_DELAY((p)->move_delay_value))
  95.  
  96. /* values for other actions */
  97. #define MOVE_STEPSIZE_NORMAL    (TILEX / MOVE_DELAY_NORMAL_SPEED)
  98.  
  99. #define GET_DX_FROM_DIR(d)    ((d) == MV_LEFT ? -1 : (d) == MV_RIGHT ? 1 : 0)
  100. #define GET_DY_FROM_DIR(d)    ((d) == MV_UP   ? -1 : (d) == MV_DOWN  ? 1 : 0)
  101.  
  102. #define    INIT_GFX_RANDOM()    (SimpleRND(1000000))
  103.  
  104. #define GET_NEW_PUSH_DELAY(e)    (   (element_info[e].push_delay_fixed) + \
  105.                  RND(element_info[e].push_delay_random))
  106. #define GET_NEW_DROP_DELAY(e)    (   (element_info[e].drop_delay_fixed) + \
  107.                  RND(element_info[e].drop_delay_random))
  108. #define GET_NEW_MOVE_DELAY(e)    (   (element_info[e].move_delay_fixed) + \
  109.                  RND(element_info[e].move_delay_random))
  110. #define GET_MAX_MOVE_DELAY(e)    (   (element_info[e].move_delay_fixed) + \
  111.                     (element_info[e].move_delay_random))
  112.  
  113. #define GET_TARGET_ELEMENT(e, ch)                    \
  114.     ((e) == EL_TRIGGER_ELEMENT ? (ch)->actual_trigger_element :    \
  115.      (e) == EL_TRIGGER_PLAYER  ? (ch)->actual_trigger_player : (e))
  116.  
  117. #define GET_VALID_PLAYER_ELEMENT(e)                    \
  118.     ((e) >= EL_PLAYER_1 && (e) <= EL_PLAYER_4 ? (e) : EL_PLAYER_1)
  119.  
  120. #define CAN_GROW_INTO(e)                        \
  121.     ((e) == EL_SAND || (IS_DIGGABLE(e) && level.grow_into_diggable))
  122.  
  123. #define ELEMENT_CAN_ENTER_FIELD_BASE_X(x, y, condition)            \
  124.         (IN_LEV_FIELD(x, y) && (IS_FREE(x, y) ||        \
  125.                     (condition)))
  126.  
  127. #define ELEMENT_CAN_ENTER_FIELD_BASE_2(e, x, y, condition)        \
  128.         (IN_LEV_FIELD(x, y) && (IS_FREE(x, y) ||        \
  129.                     (CAN_MOVE_INTO_ACID(e) &&    \
  130.                      Feld[x][y] == EL_ACID) ||    \
  131.                     (condition)))
  132.  
  133. #define ELEMENT_CAN_ENTER_FIELD_BASE_3(e, x, y, condition)        \
  134.         (IN_LEV_FIELD(x, y) && (IS_FREE_OR_PLAYER(x, y) ||    \
  135.                     (CAN_MOVE_INTO_ACID(e) &&    \
  136.                      Feld[x][y] == EL_ACID) ||    \
  137.                     (condition)))
  138.  
  139. #define ELEMENT_CAN_ENTER_FIELD_BASE_4(e, x, y, condition)        \
  140.         (IN_LEV_FIELD(x, y) && (IS_FREE(x, y) ||        \
  141.                     (condition) ||            \
  142.                     (CAN_MOVE_INTO_ACID(e) &&    \
  143.                      Feld[x][y] == EL_ACID) ||    \
  144.                     (DONT_COLLIDE_WITH(e) &&    \
  145.                      IS_PLAYER(x, y) &&        \
  146.                      !PLAYER_ENEMY_PROTECTED(x, y))))
  147.  
  148. #if 0
  149. #define ELEMENT_CAN_ENTER_FIELD_GENERIC(e, x, y, condition)        \
  150.         (IN_LEV_FIELD(x, y) && (IS_FREE(x, y) ||        \
  151.                     (condition) ||            \
  152.                     (DONT_COLLIDE_WITH(e) &&    \
  153.                      IS_PLAYER(x, y) &&        \
  154.                      !PLAYER_ENEMY_PROTECTED(x, y))))
  155. #endif
  156.  
  157. #define ELEMENT_CAN_ENTER_FIELD(e, x, y)                \
  158.     ELEMENT_CAN_ENTER_FIELD_BASE_4(e, x, y, 0)
  159.  
  160. #if 1
  161. #define SATELLITE_CAN_ENTER_FIELD(x, y)                    \
  162.     ELEMENT_CAN_ENTER_FIELD_BASE_2(EL_SATELLITE, x, y, 0)
  163. #else
  164. #define SATELLITE_CAN_ENTER_FIELD(x, y)                    \
  165.     ELEMENT_CAN_ENTER_FIELD_BASE_X(x, y, Feld[x][y] == EL_ACID)
  166. #endif
  167.  
  168. #if 0
  169. #define ENEMY_CAN_ENTER_FIELD(e, x, y) (IN_LEV_FIELD(x, y) && IS_FREE(x, y))
  170. #endif
  171.  
  172. #define ENEMY_CAN_ENTER_FIELD(e, x, y)                    \
  173.     ELEMENT_CAN_ENTER_FIELD_BASE_2(e, x, y, 0)
  174.  
  175. #if 1
  176.  
  177. #define YAMYAM_CAN_ENTER_FIELD(e, x, y)                    \
  178.     ELEMENT_CAN_ENTER_FIELD_BASE_3(e, x, y, Feld[x][y] == EL_DIAMOND)
  179.  
  180. #define DARK_YAMYAM_CAN_ENTER_FIELD(e, x, y)                \
  181.     ELEMENT_CAN_ENTER_FIELD_BASE_3(e, x,y, IS_FOOD_DARK_YAMYAM(Feld[x][y]))
  182.  
  183. #define PACMAN_CAN_ENTER_FIELD(e, x, y)                    \
  184.     ELEMENT_CAN_ENTER_FIELD_BASE_3(e, x, y, IS_AMOEBOID(Feld[x][y]))
  185.  
  186. #define PIG_CAN_ENTER_FIELD(e, x, y)                    \
  187.     ELEMENT_CAN_ENTER_FIELD_BASE_2(e, x, y, IS_FOOD_PIG(Feld[x][y]))
  188.  
  189. #define PENGUIN_CAN_ENTER_FIELD(e, x, y)                \
  190.     ELEMENT_CAN_ENTER_FIELD_BASE_2(e, x, y, (Feld[x][y] == EL_EXIT_OPEN ||\
  191.                          IS_FOOD_PENGUIN(Feld[x][y])))
  192. #define DRAGON_CAN_ENTER_FIELD(e, x, y)                    \
  193.     ELEMENT_CAN_ENTER_FIELD_BASE_2(e, x, y, 0)
  194.  
  195. #define MOLE_CAN_ENTER_FIELD(e, x, y, condition)            \
  196.     ELEMENT_CAN_ENTER_FIELD_BASE_2(e, x, y, (condition))
  197.  
  198. #define SPRING_CAN_ENTER_FIELD(e, x, y)                    \
  199.     ELEMENT_CAN_ENTER_FIELD_BASE_2(e, x, y, 0)
  200.  
  201. #else
  202.  
  203. #define YAMYAM_CAN_ENTER_FIELD(e, x, y)                    \
  204.         (IN_LEV_FIELD(x, y) && (IS_FREE_OR_PLAYER(x, y) ||    \
  205.                     (CAN_MOVE_INTO_ACID(e) &&    \
  206.                      Feld[x][y] == EL_ACID) ||    \
  207.                     Feld[x][y] == EL_DIAMOND))
  208.  
  209. #define DARK_YAMYAM_CAN_ENTER_FIELD(e, x, y)                \
  210.         (IN_LEV_FIELD(x, y) && (IS_FREE_OR_PLAYER(x, y) ||    \
  211.                     (CAN_MOVE_INTO_ACID(e) &&    \
  212.                      Feld[x][y] == EL_ACID) ||    \
  213.                     IS_FOOD_DARK_YAMYAM(Feld[x][y])))
  214.  
  215. #define PACMAN_CAN_ENTER_FIELD(e, x, y)                    \
  216.         (IN_LEV_FIELD(x, y) && (IS_FREE_OR_PLAYER(x, y) ||    \
  217.                     (CAN_MOVE_INTO_ACID(e) &&    \
  218.                      Feld[x][y] == EL_ACID) ||    \
  219.                     IS_AMOEBOID(Feld[x][y])))
  220.  
  221. #define PIG_CAN_ENTER_FIELD(e, x, y)                    \
  222.         (IN_LEV_FIELD(x, y) && (IS_FREE(x, y) ||        \
  223.                     (CAN_MOVE_INTO_ACID(e) &&    \
  224.                      Feld[x][y] == EL_ACID) ||    \
  225.                     IS_FOOD_PIG(Feld[x][y])))
  226.  
  227. #define PENGUIN_CAN_ENTER_FIELD(e, x, y)                \
  228.         (IN_LEV_FIELD(x, y) && (IS_FREE(x, y) ||        \
  229.                     (CAN_MOVE_INTO_ACID(e) &&    \
  230.                      Feld[x][y] == EL_ACID) ||    \
  231.                     IS_FOOD_PENGUIN(Feld[x][y]) ||    \
  232.                     Feld[x][y] == EL_EXIT_OPEN))
  233.  
  234. #define DRAGON_CAN_ENTER_FIELD(e, x, y)                    \
  235.         (IN_LEV_FIELD(x, y) && (IS_FREE(x, y) ||        \
  236.                     (CAN_MOVE_INTO_ACID(e) &&    \
  237.                      Feld[x][y] == EL_ACID)))
  238.  
  239. #define MOLE_CAN_ENTER_FIELD(e, x, y, condition)            \
  240.         (IN_LEV_FIELD(x, y) && (IS_FREE(x, y) ||        \
  241.                     (CAN_MOVE_INTO_ACID(e) &&    \
  242.                      Feld[x][y] == EL_ACID) ||    \
  243.                     (condition)))
  244.  
  245. #define SPRING_CAN_ENTER_FIELD(e, x, y)                    \
  246.         (IN_LEV_FIELD(x, y) && (IS_FREE(x, y) ||        \
  247.                     (CAN_MOVE_INTO_ACID(e) &&    \
  248.                      Feld[x][y] == EL_ACID)))
  249.  
  250. #endif
  251.  
  252. #define GROUP_NR(e)        ((e) - EL_GROUP_START)
  253. #define MOVE_ENTER_EL(e)    (element_info[e].move_enter_element)
  254. #define IS_IN_GROUP(e, nr)    (element_info[e].in_group[nr] == TRUE)
  255. #define IS_IN_GROUP_EL(e, ge)    (IS_IN_GROUP(e, (ge) - EL_GROUP_START))
  256.  
  257. #define IS_EQUAL_OR_IN_GROUP(e, ge)                    \
  258.     (IS_GROUP_ELEMENT(ge) ? IS_IN_GROUP(e, GROUP_NR(ge)) : (e) == (ge))
  259.  
  260. #if 0
  261. #define CE_ENTER_FIELD_COND(e, x, y)                    \
  262.         (!IS_PLAYER(x, y) &&                    \
  263.          (Feld[x][y] == EL_ACID ||                \
  264.           IS_EQUAL_OR_IN_GROUP(Feld[x][y], MOVE_ENTER_EL(e))))
  265. #else
  266. #define CE_ENTER_FIELD_COND(e, x, y)                    \
  267.         (!IS_PLAYER(x, y) &&                    \
  268.          IS_EQUAL_OR_IN_GROUP(Feld[x][y], MOVE_ENTER_EL(e)))
  269. #endif
  270.  
  271. #define CUSTOM_ELEMENT_CAN_ENTER_FIELD(e, x, y)                \
  272.     ELEMENT_CAN_ENTER_FIELD_BASE_4(e, x, y, CE_ENTER_FIELD_COND(e, x, y))
  273.  
  274. #define IN_LEV_FIELD_AND_IS_FREE(x, y)  (IN_LEV_FIELD(x, y) &&  IS_FREE(x, y))
  275. #define IN_LEV_FIELD_AND_NOT_FREE(x, y) (IN_LEV_FIELD(x, y) && !IS_FREE(x, y))
  276.  
  277. #define ACCESS_FROM(e, d)        (element_info[e].access_direction &(d))
  278. #define IS_WALKABLE_FROM(e, d)        (IS_WALKABLE(e)   && ACCESS_FROM(e, d))
  279. #define IS_PASSABLE_FROM(e, d)        (IS_PASSABLE(e)   && ACCESS_FROM(e, d))
  280. #define IS_ACCESSIBLE_FROM(e, d)    (IS_ACCESSIBLE(e) && ACCESS_FROM(e, d))
  281.  
  282. /* game button identifiers */
  283. #define GAME_CTRL_ID_STOP        0
  284. #define GAME_CTRL_ID_PAUSE        1
  285. #define GAME_CTRL_ID_PLAY        2
  286. #define SOUND_CTRL_ID_MUSIC        3
  287. #define SOUND_CTRL_ID_LOOPS        4
  288. #define SOUND_CTRL_ID_SIMPLE        5
  289.  
  290. #define NUM_GAME_BUTTONS        6
  291.  
  292.  
  293. /* forward declaration for internal use */
  294.  
  295. static boolean MovePlayerOneStep(struct PlayerInfo *, int, int, int, int);
  296. static boolean MovePlayer(struct PlayerInfo *, int, int);
  297. static void ScrollPlayer(struct PlayerInfo *, int);
  298. static void ScrollScreen(struct PlayerInfo *, int);
  299.  
  300. int DigField(struct PlayerInfo *, int, int, int, int, int, int, int);
  301.  
  302. static void InitBeltMovement(void);
  303. static void CloseAllOpenTimegates(void);
  304. static void CheckGravityMovement(struct PlayerInfo *);
  305. static void CheckGravityMovementWhenNotMoving(struct PlayerInfo *);
  306. static void KillHeroUnlessEnemyProtected(int, int);
  307. static void KillHeroUnlessExplosionProtected(int, int);
  308.  
  309. static void TestIfPlayerTouchesCustomElement(int, int);
  310. static void TestIfElementTouchesCustomElement(int, int);
  311. static void TestIfElementHitsCustomElement(int, int, int);
  312. #if 0
  313. static void TestIfElementSmashesCustomElement(int, int, int);
  314. #endif
  315.  
  316. static void ChangeElement(int, int, int);
  317.  
  318. static boolean CheckTriggeredElementChangeExt(int, int, int, int, int,int,int);
  319. #define CheckTriggeredElementChange(x, y, e, ev)            \
  320.     CheckTriggeredElementChangeExt(x, y, e, ev, CH_PLAYER_ANY,    \
  321.                        CH_SIDE_ANY, -1)
  322. #define CheckTriggeredElementChangeByPlayer(x, y, e, ev, p, s)        \
  323.     CheckTriggeredElementChangeExt(x, y, e, ev, p, s, -1)
  324. #define CheckTriggeredElementChangeBySide(x, y, e, ev, s)        \
  325.     CheckTriggeredElementChangeExt(x, y, e, ev, CH_PLAYER_ANY, s, -1)
  326. #define CheckTriggeredElementChangeByPage(x, y, e, ev, p)        \
  327.     CheckTriggeredElementChangeExt(x, y, e, ev, CH_PLAYER_ANY,    \
  328.                        CH_SIDE_ANY, p)
  329.  
  330. static boolean CheckElementChangeExt(int, int, int, int, int, int, int, int);
  331. #define CheckElementChange(x, y, e, te, ev)                \
  332.     CheckElementChangeExt(x, y, e, te, ev, CH_PLAYER_ANY, CH_SIDE_ANY, -1)
  333. #define CheckElementChangeByPlayer(x, y, e, ev, p, s)            \
  334.     CheckElementChangeExt(x, y, e, EL_EMPTY, ev, p, s, CH_PAGE_ANY)
  335. #define CheckElementChangeBySide(x, y, e, te, ev, s)            \
  336.     CheckElementChangeExt(x, y, e, te, ev, CH_PLAYER_ANY, s, CH_PAGE_ANY)
  337. #define CheckElementChangeByPage(x, y, e, te, ev, p)            \
  338.     CheckElementChangeExt(x, y, e, te, ev, CH_PLAYER_ANY, CH_SIDE_ANY, p)
  339.  
  340. static void PlayLevelSound(int, int, int);
  341. static void PlayLevelSoundNearest(int, int, int);
  342. static void PlayLevelSoundAction(int, int, int);
  343. static void PlayLevelSoundElementAction(int, int, int, int);
  344. static void PlayLevelSoundElementActionIfLoop(int, int, int, int);
  345. static void PlayLevelSoundActionIfLoop(int, int, int);
  346. static void StopLevelSoundActionIfLoop(int, int, int);
  347. static void PlayLevelMusic();
  348.  
  349. static void MapGameButtons();
  350. static void HandleGameButtons(struct GadgetInfo *);
  351.  
  352. static struct GadgetInfo *game_gadget[NUM_GAME_BUTTONS];
  353.  
  354.  
  355. /* ------------------------------------------------------------------------- */
  356. /* definition of elements that automatically change to other elements after  */
  357. /* a specified time, eventually calling a function when changing             */
  358. /* ------------------------------------------------------------------------- */
  359.  
  360. /* forward declaration for changer functions */
  361. static void InitBuggyBase(int x, int y);
  362. static void WarnBuggyBase(int x, int y);
  363.  
  364. static void InitTrap(int x, int y);
  365. static void ActivateTrap(int x, int y);
  366. static void ChangeActiveTrap(int x, int y);
  367.  
  368. static void InitRobotWheel(int x, int y);
  369. static void RunRobotWheel(int x, int y);
  370. static void StopRobotWheel(int x, int y);
  371.  
  372. static void InitTimegateWheel(int x, int y);
  373. static void RunTimegateWheel(int x, int y);
  374.  
  375. struct ChangingElementInfo
  376. {
  377.   int element;
  378.   int target_element;
  379.   int change_delay;
  380.   void (*pre_change_function)(int x, int y);
  381.   void (*change_function)(int x, int y);
  382.   void (*post_change_function)(int x, int y);
  383. };
  384.  
  385. static struct ChangingElementInfo change_delay_list[] =
  386. {
  387.   {
  388.     EL_NUT_BREAKING,
  389.     EL_EMERALD,
  390.     6,
  391.     NULL,
  392.     NULL,
  393.     NULL
  394.   },
  395.   {
  396.     EL_PEARL_BREAKING,
  397.     EL_EMPTY,
  398.     8,
  399.     NULL,
  400.     NULL,
  401.     NULL
  402.   },
  403.   {
  404.     EL_EXIT_OPENING,
  405.     EL_EXIT_OPEN,
  406.     29,
  407.     NULL,
  408.     NULL,
  409.     NULL
  410.   },
  411.   {
  412.     EL_EXIT_CLOSING,
  413.     EL_EXIT_CLOSED,
  414.     29,
  415.     NULL,
  416.     NULL,
  417.     NULL
  418.   },
  419.   {
  420.     EL_SP_EXIT_OPENING,
  421.     EL_SP_EXIT_OPEN,
  422.     29,
  423.     NULL,
  424.     NULL,
  425.     NULL
  426.   },
  427.   {
  428.     EL_SP_EXIT_CLOSING,
  429.     EL_SP_EXIT_CLOSED,
  430.     29,
  431.     NULL,
  432.     NULL,
  433.     NULL
  434.   },
  435.   {
  436.     EL_SWITCHGATE_OPENING,
  437.     EL_SWITCHGATE_OPEN,
  438.     29,
  439.     NULL,
  440.     NULL,
  441.     NULL
  442.   },
  443.   {
  444.     EL_SWITCHGATE_CLOSING,
  445.     EL_SWITCHGATE_CLOSED,
  446.     29,
  447.     NULL,
  448.     NULL,
  449.     NULL
  450.   },
  451.   {
  452.     EL_TIMEGATE_OPENING,
  453.     EL_TIMEGATE_OPEN,
  454.     29,
  455.     NULL,
  456.     NULL,
  457.     NULL
  458.   },
  459.   {
  460.     EL_TIMEGATE_CLOSING,
  461.     EL_TIMEGATE_CLOSED,
  462.     29,
  463.     NULL,
  464.     NULL,
  465.     NULL
  466.   },
  467.  
  468.   {
  469.     EL_ACID_SPLASH_LEFT,
  470.     EL_EMPTY,
  471.     8,
  472.     NULL,
  473.     NULL,
  474.     NULL
  475.   },
  476.   {
  477.     EL_ACID_SPLASH_RIGHT,
  478.     EL_EMPTY,
  479.     8,
  480.     NULL,
  481.     NULL,
  482.     NULL
  483.   },
  484.   {
  485.     EL_SP_BUGGY_BASE,
  486.     EL_SP_BUGGY_BASE_ACTIVATING,
  487.     0,
  488.     InitBuggyBase,
  489.     NULL,
  490.     NULL
  491.   },
  492.   {
  493.     EL_SP_BUGGY_BASE_ACTIVATING,
  494.     EL_SP_BUGGY_BASE_ACTIVE,
  495.     0,
  496.     InitBuggyBase,
  497.     NULL,
  498.     NULL
  499.   },
  500.   {
  501.     EL_SP_BUGGY_BASE_ACTIVE,
  502.     EL_SP_BUGGY_BASE,
  503.     0,
  504.     InitBuggyBase,
  505.     WarnBuggyBase,
  506.     NULL
  507.   },
  508.   {
  509.     EL_TRAP,
  510.     EL_TRAP_ACTIVE,
  511.     0,
  512.     InitTrap,
  513.     NULL,
  514.     ActivateTrap
  515.   },
  516.   {
  517.     EL_TRAP_ACTIVE,
  518.     EL_TRAP,
  519.     31,
  520.     NULL,
  521.     ChangeActiveTrap,
  522.     NULL
  523.   },
  524.   {
  525.     EL_ROBOT_WHEEL_ACTIVE,
  526.     EL_ROBOT_WHEEL,
  527.     0,
  528.     InitRobotWheel,
  529.     RunRobotWheel,
  530.     StopRobotWheel
  531.   },
  532.   {
  533.     EL_TIMEGATE_SWITCH_ACTIVE,
  534.     EL_TIMEGATE_SWITCH,
  535.     0,
  536.     InitTimegateWheel,
  537.     RunTimegateWheel,
  538.     NULL
  539.   },
  540.  
  541.   {
  542.     EL_UNDEFINED,
  543.     EL_UNDEFINED,
  544.     -1,
  545.     NULL,
  546.     NULL,
  547.     NULL
  548.   }
  549. };
  550.  
  551. struct
  552. {
  553.   int element;
  554.   int push_delay_fixed, push_delay_random;
  555. }
  556. push_delay_list[] =
  557. {
  558.   { EL_SPRING,            0, 0 },
  559.   { EL_BALLOON,            0, 0 },
  560.  
  561.   { EL_SOKOBAN_OBJECT,        2, 0 },
  562.   { EL_SOKOBAN_FIELD_FULL,    2, 0 },
  563.   { EL_SATELLITE,        2, 0 },
  564.   { EL_SP_DISK_YELLOW,        2, 0 },
  565.  
  566.   { EL_UNDEFINED,        0, 0 },
  567. };
  568.  
  569. struct
  570. {
  571.   int element;
  572.   int move_stepsize;
  573. }
  574. move_stepsize_list[] =
  575. {
  576.   { EL_AMOEBA_DROP,        2 },
  577.   { EL_AMOEBA_DROPPING,        2 },
  578.   { EL_QUICKSAND_FILLING,    1 },
  579.   { EL_QUICKSAND_EMPTYING,    1 },
  580.   { EL_MAGIC_WALL_FILLING,    2 },
  581.   { EL_BD_MAGIC_WALL_FILLING,    2 },
  582.   { EL_MAGIC_WALL_EMPTYING,    2 },
  583.   { EL_BD_MAGIC_WALL_EMPTYING,    2 },
  584.  
  585.   { EL_UNDEFINED,        0 },
  586. };
  587.  
  588. struct
  589. {
  590.   int element;
  591.   int count;
  592. }
  593. collect_count_list[] =
  594. {
  595.   { EL_EMERALD,            1 },
  596.   { EL_BD_DIAMOND,        1 },
  597.   { EL_EMERALD_YELLOW,        1 },
  598.   { EL_EMERALD_RED,        1 },
  599.   { EL_EMERALD_PURPLE,        1 },
  600.   { EL_DIAMOND,            3 },
  601.   { EL_SP_INFOTRON,        1 },
  602.   { EL_PEARL,            5 },
  603.   { EL_CRYSTAL,            8 },
  604.  
  605.   { EL_UNDEFINED,        0 },
  606. };
  607.  
  608. struct
  609. {
  610.   int element;
  611.   int direction;
  612. }
  613. access_direction_list[] =
  614. {
  615.   { EL_TUBE_ANY,            MV_LEFT | MV_RIGHT | MV_UP | MV_DOWN },
  616.   { EL_TUBE_VERTICAL,                                 MV_UP | MV_DOWN },
  617.   { EL_TUBE_HORIZONTAL,            MV_LEFT | MV_RIGHT                   },
  618.   { EL_TUBE_VERTICAL_LEFT,        MV_LEFT |            MV_UP | MV_DOWN },
  619.   { EL_TUBE_VERTICAL_RIGHT,                  MV_RIGHT | MV_UP | MV_DOWN },
  620.   { EL_TUBE_HORIZONTAL_UP,        MV_LEFT | MV_RIGHT | MV_UP           },
  621.   { EL_TUBE_HORIZONTAL_DOWN,        MV_LEFT | MV_RIGHT |         MV_DOWN },
  622.   { EL_TUBE_LEFT_UP,            MV_LEFT |            MV_UP           },
  623.   { EL_TUBE_LEFT_DOWN,            MV_LEFT |                    MV_DOWN },
  624.   { EL_TUBE_RIGHT_UP,                      MV_RIGHT | MV_UP           },
  625.   { EL_TUBE_RIGHT_DOWN,                      MV_RIGHT |         MV_DOWN },
  626.  
  627.   { EL_SP_PORT_LEFT,                      MV_RIGHT                   },
  628.   { EL_SP_PORT_RIGHT,            MV_LEFT                              },
  629.   { EL_SP_PORT_UP,                                         MV_DOWN },
  630.   { EL_SP_PORT_DOWN,                                 MV_UP           },
  631.   { EL_SP_PORT_HORIZONTAL,        MV_LEFT | MV_RIGHT                   },
  632.   { EL_SP_PORT_VERTICAL,                             MV_UP | MV_DOWN },
  633.   { EL_SP_PORT_ANY,            MV_LEFT | MV_RIGHT | MV_UP | MV_DOWN },
  634.   { EL_SP_GRAVITY_PORT_LEFT,                  MV_RIGHT                   },
  635.   { EL_SP_GRAVITY_PORT_RIGHT,        MV_LEFT                              },
  636.   { EL_SP_GRAVITY_PORT_UP,                                     MV_DOWN },
  637.   { EL_SP_GRAVITY_PORT_DOWN,                             MV_UP           },
  638.   { EL_SP_GRAVITY_ON_PORT_LEFT,                  MV_RIGHT                   },
  639.   { EL_SP_GRAVITY_ON_PORT_RIGHT,    MV_LEFT                              },
  640.   { EL_SP_GRAVITY_ON_PORT_UP,                                     MV_DOWN },
  641.   { EL_SP_GRAVITY_ON_PORT_DOWN,                             MV_UP           },
  642.   { EL_SP_GRAVITY_OFF_PORT_LEFT,              MV_RIGHT                   },
  643.   { EL_SP_GRAVITY_OFF_PORT_RIGHT,    MV_LEFT                              },
  644.   { EL_SP_GRAVITY_OFF_PORT_UP,                                     MV_DOWN },
  645.   { EL_SP_GRAVITY_OFF_PORT_DOWN,                         MV_UP           },
  646.  
  647.   { EL_UNDEFINED,            MV_NO_MOVING                 }
  648. };
  649.  
  650. static unsigned long trigger_events[MAX_NUM_ELEMENTS];
  651.  
  652. #define IS_AUTO_CHANGING(e)    (element_info[e].change_events & \
  653.                  CH_EVENT_BIT(CE_DELAY))
  654. #define IS_JUST_CHANGING(x, y)    (ChangeDelay[x][y] != 0)
  655. #define IS_CHANGING(x, y)    (IS_AUTO_CHANGING(Feld[x][y]) || \
  656.                  IS_JUST_CHANGING(x, y))
  657.  
  658. #define CE_PAGE(e, ce)        (element_info[e].event_page[ce])
  659.  
  660.  
  661. void GetPlayerConfig()
  662. {
  663.   if (!audio.sound_available)
  664.     setup.sound_simple = FALSE;
  665.  
  666.   if (!audio.loops_available)
  667.     setup.sound_loops = FALSE;
  668.  
  669.   if (!audio.music_available)
  670.     setup.sound_music = FALSE;
  671.  
  672.   if (!video.fullscreen_available)
  673.     setup.fullscreen = FALSE;
  674.  
  675.   setup.sound = (setup.sound_simple || setup.sound_loops || setup.sound_music);
  676.  
  677.   SetAudioMode(setup.sound);
  678.   InitJoysticks();
  679. }
  680.  
  681. static int getBeltNrFromBeltElement(int element)
  682. {
  683.   return (element < EL_CONVEYOR_BELT_2_LEFT ? 0 :
  684.       element < EL_CONVEYOR_BELT_3_LEFT ? 1 :
  685.       element < EL_CONVEYOR_BELT_4_LEFT ? 2 : 3);
  686. }
  687.  
  688. static int getBeltNrFromBeltActiveElement(int element)
  689. {
  690.   return (element < EL_CONVEYOR_BELT_2_LEFT_ACTIVE ? 0 :
  691.       element < EL_CONVEYOR_BELT_3_LEFT_ACTIVE ? 1 :
  692.       element < EL_CONVEYOR_BELT_4_LEFT_ACTIVE ? 2 : 3);
  693. }
  694.  
  695. static int getBeltNrFromBeltSwitchElement(int element)
  696. {
  697.   return (element < EL_CONVEYOR_BELT_2_SWITCH_LEFT ? 0 :
  698.       element < EL_CONVEYOR_BELT_3_SWITCH_LEFT ? 1 :
  699.       element < EL_CONVEYOR_BELT_4_SWITCH_LEFT ? 2 : 3);
  700. }
  701.  
  702. static int getBeltDirNrFromBeltSwitchElement(int element)
  703. {
  704.   static int belt_base_element[4] =
  705.   {
  706.     EL_CONVEYOR_BELT_1_SWITCH_LEFT,
  707.     EL_CONVEYOR_BELT_2_SWITCH_LEFT,
  708.     EL_CONVEYOR_BELT_3_SWITCH_LEFT,
  709.     EL_CONVEYOR_BELT_4_SWITCH_LEFT
  710.   };
  711.  
  712.   int belt_nr = getBeltNrFromBeltSwitchElement(element);
  713.   int belt_dir_nr = element - belt_base_element[belt_nr];
  714.  
  715.   return (belt_dir_nr % 3);
  716. }
  717.  
  718. static int getBeltDirFromBeltSwitchElement(int element)
  719. {
  720.   static int belt_move_dir[3] =
  721.   {
  722.     MV_LEFT,
  723.     MV_NO_MOVING,
  724.     MV_RIGHT
  725.   };
  726.  
  727.   int belt_dir_nr = getBeltDirNrFromBeltSwitchElement(element);
  728.  
  729.   return belt_move_dir[belt_dir_nr];
  730. }
  731.  
  732. static void InitPlayerField(int x, int y, int element, boolean init_game)
  733. {
  734.   if (element == EL_SP_MURPHY)
  735.   {
  736.     if (init_game)
  737.     {
  738.       if (stored_player[0].present)
  739.       {
  740.     Feld[x][y] = EL_SP_MURPHY_CLONE;
  741.  
  742.     return;
  743.       }
  744.       else
  745.       {
  746.     stored_player[0].use_murphy_graphic = TRUE;
  747.       }
  748.  
  749.       Feld[x][y] = EL_PLAYER_1;
  750.     }
  751.   }
  752.  
  753.   if (init_game)
  754.   {
  755.     struct PlayerInfo *player = &stored_player[Feld[x][y] - EL_PLAYER_1];
  756.     int jx = player->jx, jy = player->jy;
  757.  
  758.     player->present = TRUE;
  759.  
  760.     player->block_last_field = (element == EL_SP_MURPHY ?
  761.                 level.sp_block_last_field :
  762.                 level.block_last_field);
  763.  
  764.     if (!options.network || player->connected)
  765.     {
  766.       player->active = TRUE;
  767.  
  768.       /* remove potentially duplicate players */
  769.       if (StorePlayer[jx][jy] == Feld[x][y])
  770.     StorePlayer[jx][jy] = 0;
  771.  
  772.       StorePlayer[x][y] = Feld[x][y];
  773.  
  774.       if (options.debug)
  775.       {
  776.     printf("Player %d activated.\n", player->element_nr);
  777.     printf("[Local player is %d and currently %s.]\n",
  778.            local_player->element_nr,
  779.            local_player->active ? "active" : "not active");
  780.       }
  781.     }
  782.  
  783.     Feld[x][y] = EL_EMPTY;
  784.  
  785.     player->jx = player->last_jx = x;
  786.     player->jy = player->last_jy = y;
  787.   }
  788. }
  789.  
  790. static void InitField(int x, int y, boolean init_game)
  791. {
  792.   int element = Feld[x][y];
  793.  
  794.   switch (element)
  795.   {
  796.     case EL_SP_MURPHY:
  797.     case EL_PLAYER_1:
  798.     case EL_PLAYER_2:
  799.     case EL_PLAYER_3:
  800.     case EL_PLAYER_4:
  801.       InitPlayerField(x, y, element, init_game);
  802.       break;
  803.  
  804.     case EL_SOKOBAN_FIELD_PLAYER:
  805.       element = Feld[x][y] = EL_PLAYER_1;
  806.       InitField(x, y, init_game);
  807.  
  808.       element = Feld[x][y] = EL_SOKOBAN_FIELD_EMPTY;
  809.       InitField(x, y, init_game);
  810.       break;
  811.  
  812.     case EL_SOKOBAN_FIELD_EMPTY:
  813.       local_player->sokobanfields_still_needed++;
  814.       break;
  815.  
  816.     case EL_STONEBLOCK:
  817.       if (x < lev_fieldx-1 && Feld[x+1][y] == EL_ACID)
  818.     Feld[x][y] = EL_ACID_POOL_TOPLEFT;
  819.       else if (x > 0 && Feld[x-1][y] == EL_ACID)
  820.     Feld[x][y] = EL_ACID_POOL_TOPRIGHT;
  821.       else if (y > 0 && Feld[x][y-1] == EL_ACID_POOL_TOPLEFT)
  822.     Feld[x][y] = EL_ACID_POOL_BOTTOMLEFT;
  823.       else if (y > 0 && Feld[x][y-1] == EL_ACID)
  824.     Feld[x][y] = EL_ACID_POOL_BOTTOM;
  825.       else if (y > 0 && Feld[x][y-1] == EL_ACID_POOL_TOPRIGHT)
  826.     Feld[x][y] = EL_ACID_POOL_BOTTOMRIGHT;
  827.       break;
  828.  
  829.     case EL_BUG_RIGHT:
  830.     case EL_BUG_UP:
  831.     case EL_BUG_LEFT:
  832.     case EL_BUG_DOWN:
  833.     case EL_BUG:
  834.     case EL_SPACESHIP_RIGHT:
  835.     case EL_SPACESHIP_UP:
  836.     case EL_SPACESHIP_LEFT:
  837.     case EL_SPACESHIP_DOWN:
  838.     case EL_SPACESHIP:
  839.     case EL_BD_BUTTERFLY_RIGHT:
  840.     case EL_BD_BUTTERFLY_UP:
  841.     case EL_BD_BUTTERFLY_LEFT:
  842.     case EL_BD_BUTTERFLY_DOWN:
  843.     case EL_BD_BUTTERFLY:
  844.     case EL_BD_FIREFLY_RIGHT:
  845.     case EL_BD_FIREFLY_UP:
  846.     case EL_BD_FIREFLY_LEFT:
  847.     case EL_BD_FIREFLY_DOWN:
  848.     case EL_BD_FIREFLY:
  849.     case EL_PACMAN_RIGHT:
  850.     case EL_PACMAN_UP:
  851.     case EL_PACMAN_LEFT:
  852.     case EL_PACMAN_DOWN:
  853.     case EL_YAMYAM:
  854.     case EL_DARK_YAMYAM:
  855.     case EL_ROBOT:
  856.     case EL_PACMAN:
  857.     case EL_SP_SNIKSNAK:
  858.     case EL_SP_ELECTRON:
  859.     case EL_MOLE_LEFT:
  860.     case EL_MOLE_RIGHT:
  861.     case EL_MOLE_UP:
  862.     case EL_MOLE_DOWN:
  863.     case EL_MOLE:
  864.       InitMovDir(x, y);
  865.       break;
  866.  
  867.     case EL_AMOEBA_FULL:
  868.     case EL_BD_AMOEBA:
  869.       InitAmoebaNr(x, y);
  870.       break;
  871.  
  872.     case EL_AMOEBA_DROP:
  873.       if (y == lev_fieldy - 1)
  874.       {
  875.     Feld[x][y] = EL_AMOEBA_GROWING;
  876.     Store[x][y] = EL_AMOEBA_WET;
  877.       }
  878.       break;
  879.  
  880.     case EL_DYNAMITE_ACTIVE:
  881.     case EL_SP_DISK_RED_ACTIVE:
  882.     case EL_DYNABOMB_PLAYER_1_ACTIVE:
  883.     case EL_DYNABOMB_PLAYER_2_ACTIVE:
  884.     case EL_DYNABOMB_PLAYER_3_ACTIVE:
  885.     case EL_DYNABOMB_PLAYER_4_ACTIVE:
  886.       MovDelay[x][y] = 96;
  887.       break;
  888.  
  889.     case EL_LAMP:
  890.       local_player->lights_still_needed++;
  891.       break;
  892.  
  893.     case EL_PENGUIN:
  894.       local_player->friends_still_needed++;
  895.       break;
  896.  
  897.     case EL_PIG:
  898.     case EL_DRAGON:
  899.       GfxDir[x][y] = MovDir[x][y] = 1 << RND(4);
  900.       break;
  901.  
  902. #if 0
  903.     case EL_SP_EMPTY:
  904.       Feld[x][y] = EL_EMPTY;
  905.       break;
  906. #endif
  907.  
  908. #if 0
  909.     case EL_EM_KEY_1_FILE:
  910.       Feld[x][y] = EL_EM_KEY_1;
  911.       break;
  912.     case EL_EM_KEY_2_FILE:
  913.       Feld[x][y] = EL_EM_KEY_2;
  914.       break;
  915.     case EL_EM_KEY_3_FILE:
  916.       Feld[x][y] = EL_EM_KEY_3;
  917.       break;
  918.     case EL_EM_KEY_4_FILE:
  919.       Feld[x][y] = EL_EM_KEY_4;
  920.       break;
  921. #endif
  922.  
  923.     case EL_CONVEYOR_BELT_1_SWITCH_LEFT:
  924.     case EL_CONVEYOR_BELT_1_SWITCH_MIDDLE:
  925.     case EL_CONVEYOR_BELT_1_SWITCH_RIGHT:
  926.     case EL_CONVEYOR_BELT_2_SWITCH_LEFT:
  927.     case EL_CONVEYOR_BELT_2_SWITCH_MIDDLE:
  928.     case EL_CONVEYOR_BELT_2_SWITCH_RIGHT:
  929.     case EL_CONVEYOR_BELT_3_SWITCH_LEFT:
  930.     case EL_CONVEYOR_BELT_3_SWITCH_MIDDLE:
  931.     case EL_CONVEYOR_BELT_3_SWITCH_RIGHT:
  932.     case EL_CONVEYOR_BELT_4_SWITCH_LEFT:
  933.     case EL_CONVEYOR_BELT_4_SWITCH_MIDDLE:
  934.     case EL_CONVEYOR_BELT_4_SWITCH_RIGHT:
  935.       if (init_game)
  936.       {
  937.     int belt_nr = getBeltNrFromBeltSwitchElement(Feld[x][y]);
  938.     int belt_dir = getBeltDirFromBeltSwitchElement(Feld[x][y]);
  939.     int belt_dir_nr = getBeltDirNrFromBeltSwitchElement(Feld[x][y]);
  940.  
  941.     if (game.belt_dir_nr[belt_nr] == 3)    /* initial value */
  942.     {
  943.       game.belt_dir[belt_nr] = belt_dir;
  944.       game.belt_dir_nr[belt_nr] = belt_dir_nr;
  945.     }
  946.     else    /* more than one switch -- set it like the first switch */
  947.     {
  948.       Feld[x][y] = Feld[x][y] - belt_dir_nr + game.belt_dir_nr[belt_nr];
  949.     }
  950.       }
  951.       break;
  952.  
  953.     case EL_SWITCHGATE_SWITCH_DOWN:    /* always start with same switch pos */
  954.       if (init_game)
  955.     Feld[x][y] = EL_SWITCHGATE_SWITCH_UP;
  956.       break;
  957.  
  958.     case EL_LIGHT_SWITCH_ACTIVE:
  959.       if (init_game)
  960.     game.light_time_left = level.time_light * FRAMES_PER_SECOND;
  961.       break;
  962.  
  963.     default:
  964.       if (IS_CUSTOM_ELEMENT(element) && CAN_MOVE(element))
  965.     InitMovDir(x, y);
  966.       else if (IS_GROUP_ELEMENT(element))
  967.       {
  968.     struct ElementGroupInfo *group = element_info[element].group;
  969.     int last_anim_random_frame = gfx.anim_random_frame;
  970.     int element_pos;
  971.  
  972.     if (group->choice_mode == ANIM_RANDOM)
  973.       gfx.anim_random_frame = RND(group->num_elements_resolved);
  974.  
  975.     element_pos = getAnimationFrame(group->num_elements_resolved, 1,
  976.                     group->choice_mode, 0,
  977.                     group->choice_pos);
  978.  
  979.     if (group->choice_mode == ANIM_RANDOM)
  980.       gfx.anim_random_frame = last_anim_random_frame;
  981.  
  982.     group->choice_pos++;
  983.  
  984.     Feld[x][y] = group->element_resolved[element_pos];
  985.  
  986.     InitField(x, y, init_game);
  987.       }
  988.       break;
  989.   }
  990. }
  991.  
  992. static inline void InitField_WithBug1(int x, int y, boolean init_game)
  993. {
  994.   InitField(x, y, init_game);
  995.  
  996.   /* not needed to call InitMovDir() -- already done by InitField()! */
  997.   if (game.engine_version < VERSION_IDENT(3,1,0,0) &&
  998.       CAN_MOVE(Feld[x][y]))
  999.     InitMovDir(x, y);
  1000. }
  1001.  
  1002. static inline void InitField_WithBug2(int x, int y, boolean init_game)
  1003. {
  1004.   int old_element = Feld[x][y];
  1005.  
  1006.   InitField(x, y, init_game);
  1007.  
  1008.   /* not needed to call InitMovDir() -- already done by InitField()! */
  1009.   if (game.engine_version < VERSION_IDENT(3,1,0,0) &&
  1010.       CAN_MOVE(old_element) &&
  1011.       (old_element < EL_MOLE_LEFT || old_element > EL_MOLE_DOWN))
  1012.     InitMovDir(x, y);
  1013.  
  1014.   /* this case is in fact a combination of not less than three bugs:
  1015.      first, it calls InitMovDir() for elements that can move, although this is
  1016.      already done by InitField(); then, it checks the element that was at this
  1017.      field _before_ the call to InitField() (which can change it); lastly, it
  1018.      was not called for "mole with direction" elements, which were treated as
  1019.      "cannot move" due to (fixed) wrong element initialization in "src/init.c"
  1020.   */
  1021. }
  1022.  
  1023. inline void DrawGameValue_Emeralds(int value)
  1024. {
  1025.   DrawText(DX_EMERALDS, DY_EMERALDS, int2str(value, 3), FONT_TEXT_2);
  1026. }
  1027.  
  1028. inline void DrawGameValue_Dynamite(int value)
  1029. {
  1030.   DrawText(DX_DYNAMITE, DY_DYNAMITE, int2str(value, 3), FONT_TEXT_2);
  1031. }
  1032.  
  1033. inline void DrawGameValue_Keys(struct PlayerInfo *player)
  1034. {
  1035.   int i;
  1036.  
  1037.   for (i = 0; i < MAX_KEYS; i++)
  1038.     if (player->key[i])
  1039.       DrawMiniGraphicExt(drawto, DX_KEYS + i * MINI_TILEX, DY_KEYS,
  1040.              el2edimg(EL_KEY_1 + i));
  1041. }
  1042.  
  1043. inline void DrawGameValue_Score(int value)
  1044. {
  1045.   DrawText(DX_SCORE, DY_SCORE, int2str(value, 5), FONT_TEXT_2);
  1046. }
  1047.  
  1048. inline void DrawGameValue_Time(int value)
  1049. {
  1050.   if (value < 1000)
  1051.     DrawText(DX_TIME1, DY_TIME, int2str(value, 3), FONT_TEXT_2);
  1052.   else
  1053.     DrawText(DX_TIME2, DY_TIME, int2str(value, 4), FONT_LEVEL_NUMBER);
  1054. }
  1055.  
  1056. inline void DrawGameValue_Level(int value)
  1057. {
  1058.   if (level_nr < 100)
  1059.     DrawText(DX_LEVEL, DY_LEVEL, int2str(value, 2), FONT_TEXT_2);
  1060.   else
  1061.   {
  1062.     /* misuse area for displaying emeralds to draw bigger level number */
  1063.     DrawTextExt(drawto, DX_EMERALDS, DY_EMERALDS,
  1064.         int2str(value, 3), FONT_LEVEL_NUMBER, BLIT_OPAQUE);
  1065.  
  1066.     /* now copy it to the area for displaying level number */
  1067.     BlitBitmap(drawto, drawto,
  1068.            DX_EMERALDS, DY_EMERALDS + 1,
  1069.            getFontWidth(FONT_LEVEL_NUMBER) * 3,
  1070.            getFontHeight(FONT_LEVEL_NUMBER) - 1,
  1071.            DX_LEVEL - 1, DY_LEVEL + 1);
  1072.  
  1073.     /* restore the area for displaying emeralds */
  1074.     DrawGameValue_Emeralds(local_player->gems_still_needed);
  1075.  
  1076.     /* yes, this is all really ugly :-) */
  1077.   }
  1078. }
  1079.  
  1080. void DrawGameDoorValues()
  1081. {
  1082.   int i;
  1083.  
  1084.   DrawGameValue_Level(level_nr);
  1085.  
  1086.   for (i = 0; i < MAX_PLAYERS; i++)
  1087.     DrawGameValue_Keys(&stored_player[i]);
  1088.  
  1089.   DrawGameValue_Emeralds(local_player->gems_still_needed);
  1090.   DrawGameValue_Dynamite(local_player->inventory_size);
  1091.   DrawGameValue_Score(local_player->score);
  1092.   DrawGameValue_Time(TimeLeft);
  1093. }
  1094.  
  1095. static void resolve_group_element(int group_element, int recursion_depth)
  1096. {
  1097.   static int group_nr;
  1098.   static struct ElementGroupInfo *group;
  1099.   struct ElementGroupInfo *actual_group = element_info[group_element].group;
  1100.   int i;
  1101.  
  1102.   if (recursion_depth > NUM_GROUP_ELEMENTS)    /* recursion too deep */
  1103.   {
  1104.     Error(ERR_WARN, "recursion too deep when resolving group element %d",
  1105.       group_element - EL_GROUP_START + 1);
  1106.  
  1107.     /* replace element which caused too deep recursion by question mark */
  1108.     group->element_resolved[group->num_elements_resolved++] = EL_UNKNOWN;
  1109.  
  1110.     return;
  1111.   }
  1112.  
  1113.   if (recursion_depth == 0)            /* initialization */
  1114.   {
  1115.     group = element_info[group_element].group;
  1116.     group_nr = group_element - EL_GROUP_START;
  1117.  
  1118.     group->num_elements_resolved = 0;
  1119.     group->choice_pos = 0;
  1120.   }
  1121.  
  1122.   for (i = 0; i < actual_group->num_elements; i++)
  1123.   {
  1124.     int element = actual_group->element[i];
  1125.  
  1126.     if (group->num_elements_resolved == NUM_FILE_ELEMENTS)
  1127.       break;
  1128.  
  1129.     if (IS_GROUP_ELEMENT(element))
  1130.       resolve_group_element(element, recursion_depth + 1);
  1131.     else
  1132.     {
  1133.       group->element_resolved[group->num_elements_resolved++] = element;
  1134.       element_info[element].in_group[group_nr] = TRUE;
  1135.     }
  1136.   }
  1137.  
  1138. #if 0
  1139.   if (recursion_depth == 0 && group_element <= EL_GROUP_4)
  1140.   {
  1141.     printf("::: group %d: %d resolved elements\n",
  1142.        group_element - EL_GROUP_START, group->num_elements_resolved);
  1143.     for (i = 0; i < group->num_elements_resolved; i++)
  1144.       printf("::: - %d ['%s']\n", group->element_resolved[i],
  1145.          element_info[group->element_resolved[i]].token_name);
  1146.   }
  1147. #endif
  1148. }
  1149.  
  1150.  
  1151. /*
  1152.   =============================================================================
  1153.   InitGameEngine()
  1154.   -----------------------------------------------------------------------------
  1155.   initialize game engine due to level / tape version number
  1156.   =============================================================================
  1157. */
  1158.  
  1159. static void InitGameEngine()
  1160. {
  1161.   int i, j, k;
  1162.  
  1163.   /* set game engine from tape file when re-playing, else from level file */
  1164.   game.engine_version = (tape.playing ? tape.engine_version :
  1165.              level.game_version);
  1166.  
  1167.   /* dynamically adjust element properties according to game engine version */
  1168.   InitElementPropertiesEngine(game.engine_version);
  1169.  
  1170. #if 0
  1171.   printf("level %d: level version == %06d\n", level_nr, level.game_version);
  1172.   printf("          tape version == %06d [%s] [file: %06d]\n",
  1173.      tape.engine_version, (tape.playing ? "PLAYING" : "RECORDING"),
  1174.      tape.file_version);
  1175.   printf("       => game.engine_version == %06d\n", game.engine_version);
  1176. #endif
  1177.  
  1178.   /* ---------- recursively resolve group elements ------------------------- */
  1179.  
  1180.   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
  1181.     for (j = 0; j < NUM_GROUP_ELEMENTS; j++)
  1182.       element_info[i].in_group[j] = FALSE;
  1183.  
  1184.   for (i = 0; i < NUM_GROUP_ELEMENTS; i++)
  1185.     resolve_group_element(EL_GROUP_START + i, 0);
  1186.  
  1187.   /* ---------- initialize player's initial move delay --------------------- */
  1188.  
  1189.   /* dynamically adjust player properties according to game engine version */
  1190.   game.initial_move_delay =
  1191.     (game.engine_version <= VERSION_IDENT(2,0,1,0) ? INITIAL_MOVE_DELAY_ON :
  1192.      INITIAL_MOVE_DELAY_OFF);
  1193.  
  1194.   /* dynamically adjust player properties according to level information */
  1195.   game.initial_move_delay_value =
  1196.     (level.double_speed ? MOVE_DELAY_HIGH_SPEED : MOVE_DELAY_NORMAL_SPEED);
  1197.  
  1198.   /* ---------- initialize player's initial push delay --------------------- */
  1199.  
  1200.   /* dynamically adjust player properties according to game engine version */
  1201.   game.initial_push_delay_value =
  1202.     (game.engine_version < VERSION_IDENT(3,0,7,1) ? 5 : -1);
  1203.  
  1204.   /* ---------- initialize changing elements ------------------------------- */
  1205.  
  1206.   /* initialize changing elements information */
  1207.   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
  1208.   {
  1209.     struct ElementInfo *ei = &element_info[i];
  1210.  
  1211.     /* this pointer might have been changed in the level editor */
  1212.     ei->change = &ei->change_page[0];
  1213.  
  1214.     if (!IS_CUSTOM_ELEMENT(i))
  1215.     {
  1216.       ei->change->target_element = EL_EMPTY_SPACE;
  1217.       ei->change->delay_fixed = 0;
  1218.       ei->change->delay_random = 0;
  1219.       ei->change->delay_frames = 1;
  1220.     }
  1221.  
  1222.     ei->change_events = CE_BITMASK_DEFAULT;
  1223.     for (j = 0; j < NUM_CHANGE_EVENTS; j++)
  1224.     {
  1225.       ei->event_page_nr[j] = 0;
  1226.       ei->event_page[j] = &ei->change_page[0];
  1227.     }
  1228.   }
  1229.  
  1230.   /* add changing elements from pre-defined list */
  1231.   for (i = 0; change_delay_list[i].element != EL_UNDEFINED; i++)
  1232.   {
  1233.     struct ChangingElementInfo *ch_delay = &change_delay_list[i];
  1234.     struct ElementInfo *ei = &element_info[ch_delay->element];
  1235.  
  1236.     ei->change->target_element       = ch_delay->target_element;
  1237.     ei->change->delay_fixed          = ch_delay->change_delay;
  1238.  
  1239.     ei->change->pre_change_function  = ch_delay->pre_change_function;
  1240.     ei->change->change_function      = ch_delay->change_function;
  1241.     ei->change->post_change_function = ch_delay->post_change_function;
  1242.  
  1243.     ei->change_events |= CH_EVENT_BIT(CE_DELAY);
  1244.  
  1245. #if 1
  1246.     SET_PROPERTY(ch_delay->element, EP_CAN_CHANGE, TRUE);
  1247. #endif
  1248.   }
  1249.  
  1250. #if 1
  1251.   /* add change events from custom element configuration */
  1252.   for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
  1253.   {
  1254.     struct ElementInfo *ei = &element_info[EL_CUSTOM_START + i];
  1255.  
  1256.     for (j = 0; j < ei->num_change_pages; j++)
  1257.     {
  1258.       if (!ei->change_page[j].can_change)
  1259.     continue;
  1260.  
  1261.       for (k = 0; k < NUM_CHANGE_EVENTS; k++)
  1262.       {
  1263.     /* only add event page for the first page found with this event */
  1264.     if (ei->change_page[j].events & CH_EVENT_BIT(k) &&
  1265.         !(ei->change_events & CH_EVENT_BIT(k)))
  1266.     {
  1267.       ei->change_events |= CH_EVENT_BIT(k);
  1268.       ei->event_page_nr[k] = j;
  1269.       ei->event_page[k] = &ei->change_page[j];
  1270.     }
  1271.       }
  1272.     }
  1273.   }
  1274.  
  1275. #else
  1276.  
  1277.   /* add change events from custom element configuration */
  1278.   for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
  1279.   {
  1280.     int element = EL_CUSTOM_START + i;
  1281.  
  1282.     /* only add custom elements that change after fixed/random frame delay */
  1283.     if (CAN_CHANGE(element) && HAS_CHANGE_EVENT(element, CE_DELAY))
  1284.       element_info[element].change_events |= CH_EVENT_BIT(CE_DELAY);
  1285.   }
  1286. #endif
  1287.  
  1288.   /* ---------- initialize run-time trigger player and element ------------- */
  1289.  
  1290.   for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
  1291.   {
  1292.     struct ElementInfo *ei = &element_info[EL_CUSTOM_START + i];
  1293.  
  1294.     for (j = 0; j < ei->num_change_pages; j++)
  1295.     {
  1296.       ei->change_page[j].actual_trigger_element = EL_EMPTY;
  1297.       ei->change_page[j].actual_trigger_player = EL_PLAYER_1;
  1298.     }
  1299.   }
  1300.  
  1301.   /* ---------- initialize trigger events ---------------------------------- */
  1302.  
  1303.   /* initialize trigger events information */
  1304.   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
  1305.     trigger_events[i] = EP_BITMASK_DEFAULT;
  1306.  
  1307. #if 1
  1308.   /* add trigger events from element change event properties */
  1309.   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
  1310.   {
  1311.     struct ElementInfo *ei = &element_info[i];
  1312.  
  1313.     for (j = 0; j < ei->num_change_pages; j++)
  1314.     {
  1315.       if (!ei->change_page[j].can_change)
  1316.     continue;
  1317.  
  1318.       if (ei->change_page[j].events & CH_EVENT_BIT(CE_BY_OTHER_ACTION))
  1319.       {
  1320.     int trigger_element = ei->change_page[j].trigger_element;
  1321.  
  1322.     if (IS_GROUP_ELEMENT(trigger_element))
  1323.     {
  1324.       struct ElementGroupInfo *group = element_info[trigger_element].group;
  1325.  
  1326.       for (k = 0; k < group->num_elements_resolved; k++)
  1327.         trigger_events[group->element_resolved[k]]
  1328.           |= ei->change_page[j].events;
  1329.     }
  1330.     else
  1331.       trigger_events[trigger_element] |= ei->change_page[j].events;
  1332.       }
  1333.     }
  1334.   }
  1335. #else
  1336.   /* add trigger events from element change event properties */
  1337.   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
  1338.     if (HAS_CHANGE_EVENT(i, CE_BY_OTHER_ACTION))
  1339.       trigger_events[element_info[i].change->trigger_element] |=
  1340.     element_info[i].change->events;
  1341. #endif
  1342.  
  1343.   /* ---------- initialize push delay -------------------------------------- */
  1344.  
  1345.   /* initialize push delay values to default */
  1346.   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
  1347.   {
  1348.     if (!IS_CUSTOM_ELEMENT(i))
  1349.     {
  1350.       element_info[i].push_delay_fixed  = game.default_push_delay_fixed;
  1351.       element_info[i].push_delay_random = game.default_push_delay_random;
  1352.     }
  1353.   }
  1354.  
  1355.   /* set push delay value for certain elements from pre-defined list */
  1356.   for (i = 0; push_delay_list[i].element != EL_UNDEFINED; i++)
  1357.   {
  1358.     int e = push_delay_list[i].element;
  1359.  
  1360.     element_info[e].push_delay_fixed  = push_delay_list[i].push_delay_fixed;
  1361.     element_info[e].push_delay_random = push_delay_list[i].push_delay_random;
  1362.   }
  1363.  
  1364.   /* set push delay value for Supaplex elements for newer engine versions */
  1365.   if (game.engine_version >= VERSION_IDENT(3,1,0,0))
  1366.   {
  1367.     for (i = 0; i < MAX_NUM_ELEMENTS; i++)
  1368.     {
  1369.       if (IS_SP_ELEMENT(i))
  1370.       {
  1371.     element_info[i].push_delay_fixed  = 6;    /* just enough to escape ... */
  1372.     element_info[i].push_delay_random = 0;    /* ... from falling zonk     */
  1373.       }
  1374.     }
  1375.   }
  1376.  
  1377.   /* ---------- initialize move stepsize ----------------------------------- */
  1378.  
  1379.   /* initialize move stepsize values to default */
  1380.   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
  1381.     if (!IS_CUSTOM_ELEMENT(i))
  1382.       element_info[i].move_stepsize = MOVE_STEPSIZE_NORMAL;
  1383.  
  1384.   /* set move stepsize value for certain elements from pre-defined list */
  1385.   for (i = 0; move_stepsize_list[i].element != EL_UNDEFINED; i++)
  1386.   {
  1387.     int e = move_stepsize_list[i].element;
  1388.  
  1389.     element_info[e].move_stepsize = move_stepsize_list[i].move_stepsize;
  1390.   }
  1391.  
  1392. #if 0
  1393.   /* ---------- initialize move dig/leave ---------------------------------- */
  1394.  
  1395.   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
  1396.   {
  1397.     element_info[i].can_leave_element = FALSE;
  1398.     element_info[i].can_leave_element_last = FALSE;
  1399.   }
  1400. #endif
  1401.  
  1402.   /* ---------- initialize gem count --------------------------------------- */
  1403.  
  1404.   /* initialize gem count values for each element */
  1405.   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
  1406.     if (!IS_CUSTOM_ELEMENT(i))
  1407.       element_info[i].collect_count = 0;
  1408.  
  1409.   /* add gem count values for all elements from pre-defined list */
  1410.   for (i = 0; collect_count_list[i].element != EL_UNDEFINED; i++)
  1411.     element_info[collect_count_list[i].element].collect_count =
  1412.       collect_count_list[i].count;
  1413.  
  1414.   /* ---------- initialize access direction -------------------------------- */
  1415.  
  1416.   /* initialize access direction values to default (access from every side) */
  1417.   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
  1418.     if (!IS_CUSTOM_ELEMENT(i))
  1419.       element_info[i].access_direction = MV_ALL_DIRECTIONS;
  1420.  
  1421.   /* set access direction value for certain elements from pre-defined list */
  1422.   for (i = 0; access_direction_list[i].element != EL_UNDEFINED; i++)
  1423.     element_info[access_direction_list[i].element].access_direction =
  1424.       access_direction_list[i].direction;
  1425. }
  1426.  
  1427.  
  1428. /*
  1429.   =============================================================================
  1430.   InitGame()
  1431.   -----------------------------------------------------------------------------
  1432.   initialize and start new game
  1433.   =============================================================================
  1434. */
  1435.  
  1436. void InitGame()
  1437. {
  1438.   boolean emulate_bd = TRUE;    /* unless non-BOULDERDASH elements found */
  1439.   boolean emulate_sb = TRUE;    /* unless non-SOKOBAN     elements found */
  1440.   boolean emulate_sp = TRUE;    /* unless non-SUPAPLEX    elements found */
  1441.   int i, j, k, x, y;
  1442.  
  1443.   InitGameEngine();
  1444.  
  1445. #if 0
  1446. #if DEBUG
  1447. #if USE_NEW_AMOEBA_CODE
  1448.   printf("Using new amoeba code.\n");
  1449. #else
  1450.   printf("Using old amoeba code.\n");
  1451. #endif
  1452. #endif
  1453. #endif
  1454.  
  1455.   /* don't play tapes over network */
  1456.   network_playing = (options.network && !tape.playing);
  1457.  
  1458.   for (i = 0; i < MAX_PLAYERS; i++)
  1459.   {
  1460.     struct PlayerInfo *player = &stored_player[i];
  1461.  
  1462.     player->index_nr = i;
  1463.     player->index_bit = (1 << i);
  1464.     player->element_nr = EL_PLAYER_1 + i;
  1465.  
  1466.     player->present = FALSE;
  1467.     player->active = FALSE;
  1468.  
  1469.     player->action = 0;
  1470.     player->effective_action = 0;
  1471.     player->programmed_action = 0;
  1472.  
  1473.     player->score = 0;
  1474.     player->gems_still_needed = level.gems_needed;
  1475.     player->sokobanfields_still_needed = 0;
  1476.     player->lights_still_needed = 0;
  1477.     player->friends_still_needed = 0;
  1478.  
  1479.     for (j = 0; j < MAX_KEYS; j++)
  1480.       player->key[j] = FALSE;
  1481.  
  1482.     player->dynabomb_count = 0;
  1483.     player->dynabomb_size = 1;
  1484.     player->dynabombs_left = 0;
  1485.     player->dynabomb_xl = FALSE;
  1486.  
  1487.     player->MovDir = MV_NO_MOVING;
  1488.     player->MovPos = 0;
  1489.     player->GfxPos = 0;
  1490.     player->GfxDir = MV_NO_MOVING;
  1491.     player->GfxAction = ACTION_DEFAULT;
  1492.     player->Frame = 0;
  1493.     player->StepFrame = 0;
  1494.  
  1495.     player->use_murphy_graphic = FALSE;
  1496.  
  1497.     player->block_last_field = FALSE;
  1498.     player->can_fall_into_acid = CAN_MOVE_INTO_ACID(player->element_nr);
  1499.  
  1500.     player->actual_frame_counter = 0;
  1501.  
  1502.     player->step_counter = 0;
  1503.  
  1504.     player->last_move_dir = MV_NO_MOVING;
  1505.  
  1506.     player->is_waiting = FALSE;
  1507.     player->is_moving = FALSE;
  1508.     player->is_auto_moving = FALSE;
  1509.     player->is_digging = FALSE;
  1510.     player->is_snapping = FALSE;
  1511.     player->is_collecting = FALSE;
  1512.     player->is_pushing = FALSE;
  1513.     player->is_switching = FALSE;
  1514.     player->is_dropping = FALSE;
  1515.  
  1516.     player->is_bored = FALSE;
  1517.     player->is_sleeping = FALSE;
  1518.  
  1519.     player->frame_counter_bored = -1;
  1520.     player->frame_counter_sleeping = -1;
  1521.  
  1522.     player->anim_delay_counter = 0;
  1523.     player->post_delay_counter = 0;
  1524.  
  1525.     player->action_waiting = ACTION_DEFAULT;
  1526.     player->last_action_waiting = ACTION_DEFAULT;
  1527.     player->special_action_bored = ACTION_DEFAULT;
  1528.     player->special_action_sleeping = ACTION_DEFAULT;
  1529.  
  1530.     player->num_special_action_bored = 0;
  1531.     player->num_special_action_sleeping = 0;
  1532.  
  1533.     /* determine number of special actions for bored and sleeping animation */
  1534.     for (j = ACTION_BORING_1; j <= ACTION_BORING_LAST; j++)
  1535.     {
  1536.       boolean found = FALSE;
  1537.  
  1538.       for (k = 0; k < NUM_DIRECTIONS; k++)
  1539.     if (el_act_dir2img(player->element_nr, j, k) !=
  1540.         el_act_dir2img(player->element_nr, ACTION_DEFAULT, k))
  1541.       found = TRUE;
  1542.  
  1543.       if (found)
  1544.     player->num_special_action_bored++;
  1545.       else
  1546.     break;
  1547.     }
  1548.     for (j = ACTION_SLEEPING_1; j <= ACTION_SLEEPING_LAST; j++)
  1549.     {
  1550.       boolean found = FALSE;
  1551.  
  1552.       for (k = 0; k < NUM_DIRECTIONS; k++)
  1553.     if (el_act_dir2img(player->element_nr, j, k) !=
  1554.         el_act_dir2img(player->element_nr, ACTION_DEFAULT, k))
  1555.       found = TRUE;
  1556.  
  1557.       if (found)
  1558.     player->num_special_action_sleeping++;
  1559.       else
  1560.     break;
  1561.     }
  1562.  
  1563.     player->switch_x = -1;
  1564.     player->switch_y = -1;
  1565.  
  1566.     player->show_envelope = 0;
  1567.  
  1568.     player->move_delay       = game.initial_move_delay;
  1569.     player->move_delay_value = game.initial_move_delay_value;
  1570.  
  1571.     player->move_delay_reset_counter = 0;
  1572.  
  1573.     player->push_delay = 0;
  1574.     player->push_delay_value = game.initial_push_delay_value;
  1575.  
  1576.     player->drop_delay = 0;
  1577.  
  1578.     player->last_jx = player->last_jy = 0;
  1579.     player->jx = player->jy = 0;
  1580.  
  1581.     player->shield_normal_time_left = 0;
  1582.     player->shield_deadly_time_left = 0;
  1583.  
  1584.     player->inventory_infinite_element = EL_UNDEFINED;
  1585.     player->inventory_size = 0;
  1586.  
  1587.     DigField(player, 0, 0, 0, 0, 0, 0, DF_NO_PUSH);
  1588.     SnapField(player, 0, 0);
  1589.  
  1590.     player->LevelSolved = FALSE;
  1591.     player->GameOver = FALSE;
  1592.   }
  1593.  
  1594.   network_player_action_received = FALSE;
  1595.  
  1596. #if defined(NETWORK_AVALIABLE)
  1597.   /* initial null action */
  1598.   if (network_playing)
  1599.     SendToServer_MovePlayer(MV_NO_MOVING);
  1600. #endif
  1601.  
  1602.   ZX = ZY = -1;
  1603.  
  1604.   FrameCounter = 0;
  1605.   TimeFrames = 0;
  1606.   TimePlayed = 0;
  1607.   TimeLeft = level.time;
  1608.   TapeTime = 0;
  1609.  
  1610.   ScreenMovDir = MV_NO_MOVING;
  1611.   ScreenMovPos = 0;
  1612.   ScreenGfxPos = 0;
  1613.  
  1614.   ScrollStepSize = 0;    /* will be correctly initialized by ScrollScreen() */
  1615.  
  1616.   AllPlayersGone = FALSE;
  1617.  
  1618.   game.yamyam_content_nr = 0;
  1619.   game.magic_wall_active = FALSE;
  1620.   game.magic_wall_time_left = 0;
  1621.   game.light_time_left = 0;
  1622.   game.timegate_time_left = 0;
  1623.   game.switchgate_pos = 0;
  1624.   game.balloon_dir = MV_NO_MOVING;
  1625.   game.gravity = level.initial_gravity;
  1626.   game.explosions_delayed = TRUE;
  1627.  
  1628.   game.envelope_active = FALSE;
  1629.  
  1630.   for (i = 0; i < NUM_BELTS; i++)
  1631.   {
  1632.     game.belt_dir[i] = MV_NO_MOVING;
  1633.     game.belt_dir_nr[i] = 3;        /* not moving, next moving left */
  1634.   }
  1635.  
  1636.   for (i = 0; i < MAX_NUM_AMOEBA; i++)
  1637.     AmoebaCnt[i] = AmoebaCnt2[i] = 0;
  1638.  
  1639.   for (x = 0; x < lev_fieldx; x++)
  1640.   {
  1641.     for (y = 0; y < lev_fieldy; y++)
  1642.     {
  1643.       Feld[x][y] = level.field[x][y];
  1644.       MovPos[x][y] = MovDir[x][y] = MovDelay[x][y] = 0;
  1645.       ChangeDelay[x][y] = 0;
  1646.       ChangePage[x][y] = -1;
  1647.       Store[x][y] = Store2[x][y] = StorePlayer[x][y] = Back[x][y] = 0;
  1648.       AmoebaNr[x][y] = 0;
  1649.       WasJustMoving[x][y] = 0;
  1650.       WasJustFalling[x][y] = 0;
  1651.       CheckCollision[x][y] = 0;
  1652.       Stop[x][y] = FALSE;
  1653.       Pushed[x][y] = FALSE;
  1654.  
  1655.       Changed[x][y] = CE_BITMASK_DEFAULT;
  1656.       ChangeEvent[x][y] = CE_BITMASK_DEFAULT;
  1657.  
  1658.       ExplodePhase[x][y] = 0;
  1659.       ExplodeDelay[x][y] = 0;
  1660.       ExplodeField[x][y] = EX_TYPE_NONE;
  1661.  
  1662.       RunnerVisit[x][y] = 0;
  1663.       PlayerVisit[x][y] = 0;
  1664.  
  1665.       GfxFrame[x][y] = 0;
  1666.       GfxRandom[x][y] = INIT_GFX_RANDOM();
  1667.       GfxElement[x][y] = EL_UNDEFINED;
  1668.       GfxAction[x][y] = ACTION_DEFAULT;
  1669.       GfxDir[x][y] = MV_NO_MOVING;
  1670.     }
  1671.   }
  1672.  
  1673.   for (y = 0; y < lev_fieldy; y++)
  1674.   {
  1675.     for (x = 0; x < lev_fieldx; x++)
  1676.     {
  1677.       if (emulate_bd && !IS_BD_ELEMENT(Feld[x][y]))
  1678.     emulate_bd = FALSE;
  1679.       if (emulate_sb && !IS_SB_ELEMENT(Feld[x][y]))
  1680.     emulate_sb = FALSE;
  1681.       if (emulate_sp && !IS_SP_ELEMENT(Feld[x][y]))
  1682.     emulate_sp = FALSE;
  1683.  
  1684.       InitField(x, y, TRUE);
  1685.     }
  1686.   }
  1687.  
  1688.   InitBeltMovement();
  1689.  
  1690.   game.emulation = (emulate_bd ? EMU_BOULDERDASH :
  1691.             emulate_sb ? EMU_SOKOBAN :
  1692.             emulate_sp ? EMU_SUPAPLEX : EMU_NONE);
  1693.  
  1694.   /* initialize explosion and ignition delay */
  1695.   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
  1696.   {
  1697.     if (!IS_CUSTOM_ELEMENT(i))
  1698.     {
  1699.       int num_phase = 8;
  1700.       int delay = (((IS_SP_ELEMENT(i) && i != EL_EMPTY_SPACE) &&
  1701.             game.engine_version >= VERSION_IDENT(3,1,0,0)) ||
  1702.            game.emulation == EMU_SUPAPLEX ? 3 : 2);
  1703.       int last_phase = (num_phase + 1) * delay;
  1704.       int half_phase = (num_phase / 2) * delay;
  1705.  
  1706.       element_info[i].explosion_delay = last_phase - 1;
  1707.       element_info[i].ignition_delay = half_phase;
  1708.  
  1709. #if 0
  1710.       if (i == EL_BLACK_ORB)
  1711.     element_info[i].ignition_delay = 0;
  1712. #else
  1713.       if (i == EL_BLACK_ORB)
  1714.     element_info[i].ignition_delay = 1;
  1715. #endif
  1716.     }
  1717.  
  1718. #if 0
  1719.     if (element_info[i].explosion_delay < 1)    /* !!! check again !!! */
  1720.       element_info[i].explosion_delay = 1;
  1721.  
  1722.     if (element_info[i].ignition_delay < 1)    /* !!! check again !!! */
  1723.       element_info[i].ignition_delay = 1;
  1724. #endif
  1725.   }
  1726.  
  1727.   /* correct non-moving belts to start moving left */
  1728.   for (i = 0; i < NUM_BELTS; i++)
  1729.     if (game.belt_dir[i] == MV_NO_MOVING)
  1730.       game.belt_dir_nr[i] = 3;        /* not moving, next moving left */
  1731.  
  1732.   /* check if any connected player was not found in playfield */
  1733.   for (i = 0; i < MAX_PLAYERS; i++)
  1734.   {
  1735.     struct PlayerInfo *player = &stored_player[i];
  1736.  
  1737.     if (player->connected && !player->present)
  1738.     {
  1739.       for (j = 0; j < MAX_PLAYERS; j++)
  1740.       {
  1741.     struct PlayerInfo *some_player = &stored_player[j];
  1742.     int jx = some_player->jx, jy = some_player->jy;
  1743.  
  1744.     /* assign first free player found that is present in the playfield */
  1745.     if (some_player->present && !some_player->connected)
  1746.     {
  1747.       player->present = TRUE;
  1748.       player->active = TRUE;
  1749.  
  1750.       some_player->present = FALSE;
  1751.       some_player->active = FALSE;
  1752.  
  1753. #if 0
  1754.       player->element_nr = some_player->element_nr;
  1755. #endif
  1756.  
  1757.       StorePlayer[jx][jy] = player->element_nr;
  1758.       player->jx = player->last_jx = jx;
  1759.       player->jy = player->last_jy = jy;
  1760.  
  1761.       break;
  1762.     }
  1763.       }
  1764.     }
  1765.   }
  1766.  
  1767.   if (tape.playing)
  1768.   {
  1769.     /* when playing a tape, eliminate all players which do not participate */
  1770.  
  1771.     for (i = 0; i < MAX_PLAYERS; i++)
  1772.     {
  1773.       if (stored_player[i].active && !tape.player_participates[i])
  1774.       {
  1775.     struct PlayerInfo *player = &stored_player[i];
  1776.     int jx = player->jx, jy = player->jy;
  1777.  
  1778.     player->active = FALSE;
  1779.     StorePlayer[jx][jy] = 0;
  1780.     Feld[jx][jy] = EL_EMPTY;
  1781.       }
  1782.     }
  1783.   }
  1784.   else if (!options.network && !setup.team_mode)    /* && !tape.playing */
  1785.   {
  1786.     /* when in single player mode, eliminate all but the first active player */
  1787.  
  1788.     for (i = 0; i < MAX_PLAYERS; i++)
  1789.     {
  1790.       if (stored_player[i].active)
  1791.       {
  1792.     for (j = i + 1; j < MAX_PLAYERS; j++)
  1793.     {
  1794.       if (stored_player[j].active)
  1795.       {
  1796.         struct PlayerInfo *player = &stored_player[j];
  1797.         int jx = player->jx, jy = player->jy;
  1798.  
  1799.         player->active = FALSE;
  1800.         player->present = FALSE;
  1801.  
  1802.         StorePlayer[jx][jy] = 0;
  1803.         Feld[jx][jy] = EL_EMPTY;
  1804.       }
  1805.     }
  1806.       }
  1807.     }
  1808.   }
  1809.  
  1810.   /* when recording the game, store which players take part in the game */
  1811.   if (tape.recording)
  1812.   {
  1813.     for (i = 0; i < MAX_PLAYERS; i++)
  1814.       if (stored_player[i].active)
  1815.     tape.player_participates[i] = TRUE;
  1816.   }
  1817.  
  1818.   if (options.debug)
  1819.   {
  1820.     for (i = 0; i < MAX_PLAYERS; i++)
  1821.     {
  1822.       struct PlayerInfo *player = &stored_player[i];
  1823.  
  1824.       printf("Player %d: present == %d, connected == %d, active == %d.\n",
  1825.          i+1,
  1826.          player->present,
  1827.          player->connected,
  1828.          player->active);
  1829.       if (local_player == player)
  1830.     printf("Player     %d is local player.\n", i+1);
  1831.     }
  1832.   }
  1833.  
  1834.   if (BorderElement == EL_EMPTY)
  1835.   {
  1836.     SBX_Left = 0;
  1837.     SBX_Right = lev_fieldx - SCR_FIELDX;
  1838.     SBY_Upper = 0;
  1839.     SBY_Lower = lev_fieldy - SCR_FIELDY;
  1840.   }
  1841.   else
  1842.   {
  1843.     SBX_Left = -1;
  1844.     SBX_Right = lev_fieldx - SCR_FIELDX + 1;
  1845.     SBY_Upper = -1;
  1846.     SBY_Lower = lev_fieldy - SCR_FIELDY + 1;
  1847.   }
  1848.  
  1849.   if (lev_fieldx + (SBX_Left == -1 ? 2 : 0) <= SCR_FIELDX)
  1850.     SBX_Left = SBX_Right = -1 * (SCR_FIELDX - lev_fieldx) / 2;
  1851.  
  1852.   if (lev_fieldy + (SBY_Upper == -1 ? 2 : 0) <= SCR_FIELDY)
  1853.     SBY_Upper = SBY_Lower = -1 * (SCR_FIELDY - lev_fieldy) / 2;
  1854.  
  1855.   /* if local player not found, look for custom element that might create
  1856.      the player (make some assumptions about the right custom element) */
  1857.   if (!local_player->present)
  1858.   {
  1859.     int start_x = 0, start_y = 0;
  1860.     int found_rating = 0;
  1861.     int found_element = EL_UNDEFINED;
  1862.  
  1863.     for (y = 0; y < lev_fieldy; y++) for (x = 0; x < lev_fieldx; x++)
  1864.     {
  1865.       int element = Feld[x][y];
  1866.       int content;
  1867.       int xx, yy;
  1868.       boolean is_player;
  1869.  
  1870.       if (!IS_CUSTOM_ELEMENT(element))
  1871.     continue;
  1872.  
  1873.       if (CAN_CHANGE(element))
  1874.       {
  1875.     for (i = 0; i < element_info[element].num_change_pages; i++)
  1876.     {
  1877.       content = element_info[element].change_page[i].target_element;
  1878.       is_player = ELEM_IS_PLAYER(content);
  1879.  
  1880.       if (is_player && (found_rating < 3 || element < found_element))
  1881.       {
  1882.         start_x = x;
  1883.         start_y = y;
  1884.  
  1885.         found_rating = 3;
  1886.         found_element = element;
  1887.       }
  1888.     }
  1889.       }
  1890.  
  1891.       for (yy = 0; yy < 3; yy++) for (xx = 0; xx < 3; xx++)
  1892.       {
  1893.     content = element_info[element].content[xx][yy];
  1894.     is_player = ELEM_IS_PLAYER(content);
  1895.  
  1896.     if (is_player && (found_rating < 2 || element < found_element))
  1897.     {
  1898.       start_x = x + xx - 1;
  1899.       start_y = y + yy - 1;
  1900.  
  1901.       found_rating = 2;
  1902.       found_element = element;
  1903.     }
  1904.  
  1905.     if (!CAN_CHANGE(element))
  1906.       continue;
  1907.  
  1908.     for (i = 0; i < element_info[element].num_change_pages; i++)
  1909.     {
  1910.       content= element_info[element].change_page[i].target_content[xx][yy];
  1911.       is_player = ELEM_IS_PLAYER(content);
  1912.  
  1913.       if (is_player && (found_rating < 1 || element < found_element))
  1914.       {
  1915.         start_x = x + xx - 1;
  1916.         start_y = y + yy - 1;
  1917.  
  1918.         found_rating = 1;
  1919.         found_element = element;
  1920.       }
  1921.     }
  1922.       }
  1923.     }
  1924.  
  1925.     scroll_x = (start_x < SBX_Left  + MIDPOSX ? SBX_Left :
  1926.         start_x > SBX_Right + MIDPOSX ? SBX_Right :
  1927.         start_x - MIDPOSX);
  1928.  
  1929.     scroll_y = (start_y < SBY_Upper + MIDPOSY ? SBY_Upper :
  1930.         start_y > SBY_Lower + MIDPOSY ? SBY_Lower :
  1931.         start_y - MIDPOSY);
  1932.   }
  1933.   else
  1934.   {
  1935. #if 1
  1936.     scroll_x = (local_player->jx < SBX_Left  + MIDPOSX ? SBX_Left :
  1937.         local_player->jx > SBX_Right + MIDPOSX ? SBX_Right :
  1938.         local_player->jx - MIDPOSX);
  1939.  
  1940.     scroll_y = (local_player->jy < SBY_Upper + MIDPOSY ? SBY_Upper :
  1941.         local_player->jy > SBY_Lower + MIDPOSY ? SBY_Lower :
  1942.         local_player->jy - MIDPOSY);
  1943. #else
  1944.     scroll_x = SBX_Left;
  1945.     scroll_y = SBY_Upper;
  1946.     if (local_player->jx >= SBX_Left + MIDPOSX)
  1947.       scroll_x = (local_player->jx <= SBX_Right + MIDPOSX ?
  1948.           local_player->jx - MIDPOSX :
  1949.           SBX_Right);
  1950.     if (local_player->jy >= SBY_Upper + MIDPOSY)
  1951.       scroll_y = (local_player->jy <= SBY_Lower + MIDPOSY ?
  1952.           local_player->jy - MIDPOSY :
  1953.           SBY_Lower);
  1954. #endif
  1955.   }
  1956.  
  1957.   CloseDoor(DOOR_CLOSE_1);
  1958.  
  1959.   DrawLevel();
  1960.   DrawAllPlayers();
  1961.  
  1962.   /* after drawing the level, correct some elements */
  1963.   if (game.timegate_time_left == 0)
  1964.     CloseAllOpenTimegates();
  1965.  
  1966.   if (setup.soft_scrolling)
  1967.     BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
  1968.  
  1969.   redraw_mask |= REDRAW_FROM_BACKBUFFER;
  1970.   FadeToFront();
  1971.  
  1972.   /* copy default game door content to main double buffer */
  1973.   BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
  1974.          DOOR_GFX_PAGEX5, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE, DX, DY);
  1975.  
  1976.   DrawGameDoorValues();
  1977.  
  1978.   UnmapGameButtons();
  1979.   UnmapTapeButtons();
  1980.   game_gadget[SOUND_CTRL_ID_MUSIC]->checked = setup.sound_music;
  1981.   game_gadget[SOUND_CTRL_ID_LOOPS]->checked = setup.sound_loops;
  1982.   game_gadget[SOUND_CTRL_ID_SIMPLE]->checked = setup.sound_simple;
  1983.   MapGameButtons();
  1984.   MapTapeButtons();
  1985.  
  1986.   /* copy actual game door content to door double buffer for OpenDoor() */
  1987.   BlitBitmap(drawto, bitmap_db_door,
  1988.          DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
  1989.  
  1990.   OpenDoor(DOOR_OPEN_ALL);
  1991.  
  1992.   PlaySoundStereo(SND_GAME_STARTING, SOUND_MIDDLE);
  1993.  
  1994.   if (setup.sound_music)
  1995.     PlayLevelMusic();
  1996.  
  1997.   KeyboardAutoRepeatOffUnlessAutoplay();
  1998.  
  1999.   if (options.debug)
  2000.   {
  2001.     for (i = 0; i < MAX_PLAYERS; i++)
  2002.       printf("Player %d %sactive.\n",
  2003.          i + 1, (stored_player[i].active ? "" : "not "));
  2004.   }
  2005.  
  2006. #if 0
  2007.   printf("::: starting game [%d]\n", FrameCounter);
  2008. #endif
  2009. }
  2010.  
  2011. void InitMovDir(int x, int y)
  2012. {
  2013.   int i, element = Feld[x][y];
  2014.   static int xy[4][2] =
  2015.   {
  2016.     {  0, +1 },
  2017.     { +1,  0 },
  2018.     {  0, -1 },
  2019.     { -1,  0 }
  2020.   };
  2021.   static int direction[3][4] =
  2022.   {
  2023.     { MV_RIGHT, MV_UP,   MV_LEFT,  MV_DOWN },
  2024.     { MV_LEFT,  MV_DOWN, MV_RIGHT, MV_UP },
  2025.     { MV_LEFT,  MV_RIGHT, MV_UP, MV_DOWN }
  2026.   };
  2027.  
  2028.   switch(element)
  2029.   {
  2030.     case EL_BUG_RIGHT:
  2031.     case EL_BUG_UP:
  2032.     case EL_BUG_LEFT:
  2033.     case EL_BUG_DOWN:
  2034.       Feld[x][y] = EL_BUG;
  2035.       MovDir[x][y] = direction[0][element - EL_BUG_RIGHT];
  2036.       break;
  2037.  
  2038.     case EL_SPACESHIP_RIGHT:
  2039.     case EL_SPACESHIP_UP:
  2040.     case EL_SPACESHIP_LEFT:
  2041.     case EL_SPACESHIP_DOWN:
  2042.       Feld[x][y] = EL_SPACESHIP;
  2043.       MovDir[x][y] = direction[0][element - EL_SPACESHIP_RIGHT];
  2044.       break;
  2045.  
  2046.     case EL_BD_BUTTERFLY_RIGHT:
  2047.     case EL_BD_BUTTERFLY_UP:
  2048.     case EL_BD_BUTTERFLY_LEFT:
  2049.     case EL_BD_BUTTERFLY_DOWN:
  2050.       Feld[x][y] = EL_BD_BUTTERFLY;
  2051.       MovDir[x][y] = direction[0][element - EL_BD_BUTTERFLY_RIGHT];
  2052.       break;
  2053.  
  2054.     case EL_BD_FIREFLY_RIGHT:
  2055.     case EL_BD_FIREFLY_UP:
  2056.     case EL_BD_FIREFLY_LEFT:
  2057.     case EL_BD_FIREFLY_DOWN:
  2058.       Feld[x][y] = EL_BD_FIREFLY;
  2059.       MovDir[x][y] = direction[0][element - EL_BD_FIREFLY_RIGHT];
  2060.       break;
  2061.  
  2062.     case EL_PACMAN_RIGHT:
  2063.     case EL_PACMAN_UP:
  2064.     case EL_PACMAN_LEFT:
  2065.     case EL_PACMAN_DOWN:
  2066.       Feld[x][y] = EL_PACMAN;
  2067.       MovDir[x][y] = direction[0][element - EL_PACMAN_RIGHT];
  2068.       break;
  2069.  
  2070.     case EL_SP_SNIKSNAK:
  2071.       MovDir[x][y] = MV_UP;
  2072.       break;
  2073.  
  2074.     case EL_SP_ELECTRON:
  2075.       MovDir[x][y] = MV_LEFT;
  2076.       break;
  2077.  
  2078.     case EL_MOLE_LEFT:
  2079.     case EL_MOLE_RIGHT:
  2080.     case EL_MOLE_UP:
  2081.     case EL_MOLE_DOWN:
  2082.       Feld[x][y] = EL_MOLE;
  2083.       MovDir[x][y] = direction[2][element - EL_MOLE_LEFT];
  2084.       break;
  2085.  
  2086.     default:
  2087.       if (IS_CUSTOM_ELEMENT(element))
  2088.       {
  2089.     struct ElementInfo *ei = &element_info[element];
  2090.     int move_direction_initial = ei->move_direction_initial;
  2091.     int move_pattern = ei->move_pattern;
  2092.  
  2093.     if (move_direction_initial == MV_START_PREVIOUS)
  2094.     {
  2095.       if (MovDir[x][y] != MV_NO_MOVING)
  2096.         return;
  2097.  
  2098.       move_direction_initial = MV_START_AUTOMATIC;
  2099.     }
  2100.  
  2101.     if (move_direction_initial == MV_START_RANDOM)
  2102.       MovDir[x][y] = 1 << RND(4);
  2103.     else if (move_direction_initial & MV_ANY_DIRECTION)
  2104.       MovDir[x][y] = move_direction_initial;
  2105.     else if (move_pattern == MV_ALL_DIRECTIONS ||
  2106.          move_pattern == MV_TURNING_LEFT ||
  2107.          move_pattern == MV_TURNING_RIGHT ||
  2108.          move_pattern == MV_TURNING_LEFT_RIGHT ||
  2109.          move_pattern == MV_TURNING_RIGHT_LEFT ||
  2110.          move_pattern == MV_TURNING_RANDOM)
  2111.       MovDir[x][y] = 1 << RND(4);
  2112.     else if (move_pattern == MV_HORIZONTAL)
  2113.       MovDir[x][y] = (RND(2) ? MV_LEFT : MV_RIGHT);
  2114.     else if (move_pattern == MV_VERTICAL)
  2115.       MovDir[x][y] = (RND(2) ? MV_UP : MV_DOWN);
  2116.     else if (move_pattern & MV_ANY_DIRECTION)
  2117.       MovDir[x][y] = element_info[element].move_pattern;
  2118.     else if (move_pattern == MV_ALONG_LEFT_SIDE ||
  2119.          move_pattern == MV_ALONG_RIGHT_SIDE)
  2120.     {
  2121. #if 1
  2122.       /* use random direction as default start direction */
  2123.       if (game.engine_version >= VERSION_IDENT(3,1,0,0))
  2124.         MovDir[x][y] = 1 << RND(4);
  2125. #endif
  2126.  
  2127.       for (i = 0; i < NUM_DIRECTIONS; i++)
  2128.       {
  2129.         int x1 = x + xy[i][0];
  2130.         int y1 = y + xy[i][1];
  2131.  
  2132.         if (!IN_LEV_FIELD(x1, y1) || !IS_FREE(x1, y1))
  2133.         {
  2134.           if (move_pattern == MV_ALONG_RIGHT_SIDE)
  2135.         MovDir[x][y] = direction[0][i];
  2136.           else
  2137.         MovDir[x][y] = direction[1][i];
  2138.  
  2139.           break;
  2140.         }
  2141.       }
  2142.     }         
  2143.       }
  2144.       else
  2145.       {
  2146.     MovDir[x][y] = 1 << RND(4);
  2147.  
  2148.     if (element != EL_BUG &&
  2149.         element != EL_SPACESHIP &&
  2150.         element != EL_BD_BUTTERFLY &&
  2151.         element != EL_BD_FIREFLY)
  2152.       break;
  2153.  
  2154.     for (i = 0; i < NUM_DIRECTIONS; i++)
  2155.     {
  2156.       int x1 = x + xy[i][0];
  2157.       int y1 = y + xy[i][1];
  2158.  
  2159.       if (!IN_LEV_FIELD(x1, y1) || !IS_FREE(x1, y1))
  2160.       {
  2161.         if (element == EL_BUG || element == EL_BD_BUTTERFLY)
  2162.         {
  2163.           MovDir[x][y] = direction[0][i];
  2164.           break;
  2165.         }
  2166.         else if (element == EL_SPACESHIP || element == EL_BD_FIREFLY ||
  2167.              element == EL_SP_SNIKSNAK || element == EL_SP_ELECTRON)
  2168.         {
  2169.           MovDir[x][y] = direction[1][i];
  2170.           break;
  2171.         }
  2172.       }
  2173.     }
  2174.       }
  2175.       break;
  2176.   }
  2177.  
  2178.   GfxDir[x][y] = MovDir[x][y];
  2179. }
  2180.  
  2181. void InitAmoebaNr(int x, int y)
  2182. {
  2183.   int i;
  2184.   int group_nr = AmoebeNachbarNr(x, y);
  2185.  
  2186.   if (group_nr == 0)
  2187.   {
  2188.     for (i = 1; i < MAX_NUM_AMOEBA; i++)
  2189.     {
  2190.       if (AmoebaCnt[i] == 0)
  2191.       {
  2192.     group_nr = i;
  2193.     break;
  2194.       }
  2195.     }
  2196.   }
  2197.  
  2198.   AmoebaNr[x][y] = group_nr;
  2199.   AmoebaCnt[group_nr]++;
  2200.   AmoebaCnt2[group_nr]++;
  2201. }
  2202.  
  2203. void GameWon()
  2204. {
  2205.   int hi_pos;
  2206.   boolean raise_level = FALSE;
  2207.  
  2208.   if (local_player->MovPos)
  2209.     return;
  2210.  
  2211. #if 1
  2212.   if (tape.auto_play)        /* tape might already be stopped here */
  2213.     tape.auto_play_level_solved = TRUE;
  2214. #else
  2215.   if (tape.playing && tape.auto_play)
  2216.     tape.auto_play_level_solved = TRUE;
  2217. #endif
  2218.  
  2219.   local_player->LevelSolved = FALSE;
  2220.  
  2221.   PlaySoundStereo(SND_GAME_WINNING, SOUND_MIDDLE);
  2222.  
  2223.   if (TimeLeft)
  2224.   {
  2225.     if (!tape.playing && setup.sound_loops)
  2226.       PlaySoundExt(SND_GAME_LEVELTIME_BONUS, SOUND_MAX_VOLUME, SOUND_MIDDLE,
  2227.            SND_CTRL_PLAY_LOOP);
  2228.  
  2229.     while (TimeLeft > 0)
  2230.     {
  2231.       if (!tape.playing && !setup.sound_loops)
  2232.     PlaySoundStereo(SND_GAME_LEVELTIME_BONUS, SOUND_MIDDLE);
  2233.       if (TimeLeft > 0 && !(TimeLeft % 10))
  2234.     RaiseScore(level.score[SC_TIME_BONUS]);
  2235.       if (TimeLeft > 100 && !(TimeLeft % 10))
  2236.     TimeLeft -= 10;
  2237.       else
  2238.     TimeLeft--;
  2239.  
  2240.       DrawGameValue_Time(TimeLeft);
  2241.  
  2242.       BackToFront();
  2243.  
  2244.       if (!tape.playing)
  2245.     Delay(10);
  2246.     }
  2247.  
  2248.     if (!tape.playing && setup.sound_loops)
  2249.       StopSound(SND_GAME_LEVELTIME_BONUS);
  2250.   }
  2251.   else if (level.time == 0)        /* level without time limit */
  2252.   {
  2253.     if (!tape.playing && setup.sound_loops)
  2254.       PlaySoundExt(SND_GAME_LEVELTIME_BONUS, SOUND_MAX_VOLUME, SOUND_MIDDLE,
  2255.            SND_CTRL_PLAY_LOOP);
  2256.  
  2257.     while (TimePlayed < 999)
  2258.     {
  2259.       if (!tape.playing && !setup.sound_loops)
  2260.     PlaySoundStereo(SND_GAME_LEVELTIME_BONUS, SOUND_MIDDLE);
  2261.       if (TimePlayed < 999 && !(TimePlayed % 10))
  2262.     RaiseScore(level.score[SC_TIME_BONUS]);
  2263.       if (TimePlayed < 900 && !(TimePlayed % 10))
  2264.     TimePlayed += 10;
  2265.       else
  2266.     TimePlayed++;
  2267.  
  2268.       DrawGameValue_Time(TimePlayed);
  2269.  
  2270.       BackToFront();
  2271.  
  2272.       if (!tape.playing)
  2273.     Delay(10);
  2274.     }
  2275.  
  2276.     if (!tape.playing && setup.sound_loops)
  2277.       StopSound(SND_GAME_LEVELTIME_BONUS);
  2278.   }
  2279.  
  2280.   /* close exit door after last player */
  2281.   if ((Feld[ExitX][ExitY] == EL_EXIT_OPEN ||
  2282.        Feld[ExitX][ExitY] == EL_SP_EXIT_OPEN) && AllPlayersGone)
  2283.   {
  2284.     int element = Feld[ExitX][ExitY];
  2285.  
  2286.     Feld[ExitX][ExitY] = (element == EL_EXIT_OPEN ? EL_EXIT_CLOSING :
  2287.               EL_SP_EXIT_CLOSING);
  2288.  
  2289.     PlayLevelSoundElementAction(ExitX, ExitY, element, ACTION_CLOSING);
  2290.   }
  2291.  
  2292.   /* Hero disappears */
  2293.   DrawLevelField(ExitX, ExitY);
  2294.   BackToFront();
  2295.  
  2296.   if (tape.playing)
  2297.     return;
  2298.  
  2299.   CloseDoor(DOOR_CLOSE_1);
  2300.  
  2301.   if (tape.recording)
  2302.   {
  2303.     TapeStop();
  2304.     SaveTape(tape.level_nr);        /* Ask to save tape */
  2305.   }
  2306.  
  2307.   if (level_nr == leveldir_current->handicap_level)
  2308.   {
  2309.     leveldir_current->handicap_level++;
  2310.     SaveLevelSetup_SeriesInfo();
  2311.   }
  2312.  
  2313.   if (level_editor_test_game)
  2314.     local_player->score = -1;    /* no highscore when playing from editor */
  2315.   else if (level_nr < leveldir_current->last_level)
  2316.     raise_level = TRUE;        /* advance to next level */
  2317.  
  2318.   if ((hi_pos = NewHiScore()) >= 0) 
  2319.   {
  2320.     game_status = GAME_MODE_SCORES;
  2321.     DrawHallOfFame(hi_pos);
  2322.     if (raise_level)
  2323.     {
  2324.       level_nr++;
  2325.       TapeErase();
  2326.     }
  2327.   }
  2328.   else
  2329.   {
  2330.     game_status = GAME_MODE_MAIN;
  2331.     if (raise_level)
  2332.     {
  2333.       level_nr++;
  2334.       TapeErase();
  2335.     }
  2336.     DrawMainMenu();
  2337.   }
  2338.  
  2339.   BackToFront();
  2340. }
  2341.  
  2342. int NewHiScore()
  2343. {
  2344.   int k, l;
  2345.   int position = -1;
  2346.  
  2347.   LoadScore(level_nr);
  2348.  
  2349.   if (strcmp(setup.player_name, EMPTY_PLAYER_NAME) == 0 ||
  2350.       local_player->score < highscore[MAX_SCORE_ENTRIES - 1].Score) 
  2351.     return -1;
  2352.  
  2353.   for (k = 0; k < MAX_SCORE_ENTRIES; k++) 
  2354.   {
  2355.     if (local_player->score > highscore[k].Score)
  2356.     {
  2357.       /* player has made it to the hall of fame */
  2358.  
  2359.       if (k < MAX_SCORE_ENTRIES - 1)
  2360.       {
  2361.     int m = MAX_SCORE_ENTRIES - 1;
  2362.  
  2363. #ifdef ONE_PER_NAME
  2364.     for (l = k; l < MAX_SCORE_ENTRIES; l++)
  2365.       if (!strcmp(setup.player_name, highscore[l].Name))
  2366.         m = l;
  2367.     if (m == k)    /* player's new highscore overwrites his old one */
  2368.       goto put_into_list;
  2369. #endif
  2370.  
  2371.     for (l = m; l > k; l--)
  2372.     {
  2373.       strcpy(highscore[l].Name, highscore[l - 1].Name);
  2374.       highscore[l].Score = highscore[l - 1].Score;
  2375.     }
  2376.       }
  2377.  
  2378. #ifdef ONE_PER_NAME
  2379.       put_into_list:
  2380. #endif
  2381.       strncpy(highscore[k].Name, setup.player_name, MAX_PLAYER_NAME_LEN);
  2382.       highscore[k].Name[MAX_PLAYER_NAME_LEN] = '\0';
  2383.       highscore[k].Score = local_player->score; 
  2384.       position = k;
  2385.       break;
  2386.     }
  2387.  
  2388. #ifdef ONE_PER_NAME
  2389.     else if (!strncmp(setup.player_name, highscore[k].Name,
  2390.               MAX_PLAYER_NAME_LEN))
  2391.       break;    /* player already there with a higher score */
  2392. #endif
  2393.  
  2394.   }
  2395.  
  2396.   if (position >= 0) 
  2397.     SaveScore(level_nr);
  2398.  
  2399.   return position;
  2400. }
  2401.  
  2402. void InitPlayerGfxAnimation(struct PlayerInfo *player, int action, int dir)
  2403. {
  2404.   if (player->GfxAction != action || player->GfxDir != dir)
  2405.   {
  2406. #if 0
  2407.     printf("Player frame reset! (%d => %d, %d => %d)\n",
  2408.        player->GfxAction, action, player->GfxDir, dir);
  2409. #endif
  2410.  
  2411.     player->GfxAction = action;
  2412.     player->GfxDir = dir;
  2413.     player->Frame = 0;
  2414.     player->StepFrame = 0;
  2415.   }
  2416. }
  2417.  
  2418. static void ResetRandomAnimationValue(int x, int y)
  2419. {
  2420.   GfxRandom[x][y] = INIT_GFX_RANDOM();
  2421. }
  2422.  
  2423. static void ResetGfxAnimation(int x, int y)
  2424. {
  2425.   GfxFrame[x][y] = 0;
  2426.   GfxAction[x][y] = ACTION_DEFAULT;
  2427.   GfxDir[x][y] = MovDir[x][y];
  2428. }
  2429.  
  2430. void InitMovingField(int x, int y, int direction)
  2431. {
  2432.   int element = Feld[x][y];
  2433.   int dx = (direction == MV_LEFT ? -1 : direction == MV_RIGHT ? +1 : 0);
  2434.   int dy = (direction == MV_UP   ? -1 : direction == MV_DOWN  ? +1 : 0);
  2435.   int newx = x + dx;
  2436.   int newy = y + dy;
  2437.  
  2438.   if (!WasJustMoving[x][y] || direction != MovDir[x][y])
  2439.     ResetGfxAnimation(x, y);
  2440.  
  2441.   MovDir[newx][newy] = MovDir[x][y] = direction;
  2442.   GfxDir[x][y] = direction;
  2443.  
  2444.   if (Feld[newx][newy] == EL_EMPTY)
  2445.     Feld[newx][newy] = EL_BLOCKED;
  2446.  
  2447.   if (direction == MV_DOWN && CAN_FALL(element))
  2448.     GfxAction[x][y] = ACTION_FALLING;
  2449.   else
  2450.     GfxAction[x][y] = ACTION_MOVING;
  2451.  
  2452.   GfxFrame[newx][newy] = GfxFrame[x][y];
  2453.   GfxRandom[newx][newy] = GfxRandom[x][y];
  2454.   GfxAction[newx][newy] = GfxAction[x][y];
  2455.   GfxDir[newx][newy] = GfxDir[x][y];
  2456. }
  2457.  
  2458. void Moving2Blocked(int x, int y, int *goes_to_x, int *goes_to_y)
  2459. {
  2460.   int direction = MovDir[x][y];
  2461.   int newx = x + (direction == MV_LEFT ? -1 : direction == MV_RIGHT ? +1 : 0);
  2462.   int newy = y + (direction == MV_UP   ? -1 : direction == MV_DOWN  ? +1 : 0);
  2463.  
  2464.   *goes_to_x = newx;
  2465.   *goes_to_y = newy;
  2466. }
  2467.  
  2468. void Blocked2Moving(int x, int y, int *comes_from_x, int *comes_from_y)
  2469. {
  2470.   int oldx = x, oldy = y;
  2471.   int direction = MovDir[x][y];
  2472.  
  2473.   if (direction == MV_LEFT)
  2474.     oldx++;
  2475.   else if (direction == MV_RIGHT)
  2476.     oldx--;
  2477.   else if (direction == MV_UP)
  2478.     oldy++;
  2479.   else if (direction == MV_DOWN)
  2480.     oldy--;
  2481.  
  2482.   *comes_from_x = oldx;
  2483.   *comes_from_y = oldy;
  2484. }
  2485.  
  2486. int MovingOrBlocked2Element(int x, int y)
  2487. {
  2488.   int element = Feld[x][y];
  2489.  
  2490.   if (element == EL_BLOCKED)
  2491.   {
  2492.     int oldx, oldy;
  2493.  
  2494.     Blocked2Moving(x, y, &oldx, &oldy);
  2495.     return Feld[oldx][oldy];
  2496.   }
  2497.   else
  2498.     return element;
  2499. }
  2500.  
  2501. static int MovingOrBlocked2ElementIfNotLeaving(int x, int y)
  2502. {
  2503.   /* like MovingOrBlocked2Element(), but if element is moving
  2504.      and (x,y) is the field the moving element is just leaving,
  2505.      return EL_BLOCKED instead of the element value */
  2506.   int element = Feld[x][y];
  2507.  
  2508.   if (IS_MOVING(x, y))
  2509.   {
  2510.     if (element == EL_BLOCKED)
  2511.     {
  2512.       int oldx, oldy;
  2513.  
  2514.       Blocked2Moving(x, y, &oldx, &oldy);
  2515.       return Feld[oldx][oldy];
  2516.     }
  2517.     else
  2518.       return EL_BLOCKED;
  2519.   }
  2520.   else
  2521.     return element;
  2522. }
  2523.  
  2524. static void RemoveField(int x, int y)
  2525. {
  2526.   Feld[x][y] = EL_EMPTY;
  2527.  
  2528.   MovPos[x][y] = 0;
  2529.   MovDir[x][y] = 0;
  2530.   MovDelay[x][y] = 0;
  2531.  
  2532.   AmoebaNr[x][y] = 0;
  2533.   ChangeDelay[x][y] = 0;
  2534.   ChangePage[x][y] = -1;
  2535.   Pushed[x][y] = FALSE;
  2536.  
  2537. #if 0
  2538.   ExplodeField[x][y] = EX_TYPE_NONE;
  2539. #endif
  2540.  
  2541.   GfxElement[x][y] = EL_UNDEFINED;
  2542.   GfxAction[x][y] = ACTION_DEFAULT;
  2543.   GfxDir[x][y] = MV_NO_MOVING;
  2544. }
  2545.  
  2546. void RemoveMovingField(int x, int y)
  2547. {
  2548.   int oldx = x, oldy = y, newx = x, newy = y;
  2549.   int element = Feld[x][y];
  2550.   int next_element = EL_UNDEFINED;
  2551.  
  2552.   if (element != EL_BLOCKED && !IS_MOVING(x, y))
  2553.     return;
  2554.  
  2555.   if (IS_MOVING(x, y))
  2556.   {
  2557.     Moving2Blocked(x, y, &newx, &newy);
  2558. #if 0
  2559.     if (Feld[newx][newy] != EL_BLOCKED)
  2560.       return;
  2561. #else
  2562.     if (Feld[newx][newy] != EL_BLOCKED)
  2563.     {
  2564.       /* element is moving, but target field is not free (blocked), but
  2565.      already occupied by something different (example: acid pool);
  2566.      in this case, only remove the moving field, but not the target */
  2567.  
  2568.       RemoveField(oldx, oldy);
  2569.  
  2570.       Store[oldx][oldy] = Store2[oldx][oldy] = 0;
  2571.  
  2572.       DrawLevelField(oldx, oldy);
  2573.  
  2574.       return;
  2575.     }
  2576. #endif
  2577.   }
  2578.   else if (element == EL_BLOCKED)
  2579.   {
  2580.     Blocked2Moving(x, y, &oldx, &oldy);
  2581.     if (!IS_MOVING(oldx, oldy))
  2582.       return;
  2583.   }
  2584.  
  2585.   if (element == EL_BLOCKED &&
  2586.       (Feld[oldx][oldy] == EL_QUICKSAND_EMPTYING ||
  2587.        Feld[oldx][oldy] == EL_MAGIC_WALL_EMPTYING ||
  2588.        Feld[oldx][oldy] == EL_BD_MAGIC_WALL_EMPTYING ||
  2589.        Feld[oldx][oldy] == EL_AMOEBA_DROPPING))
  2590.     next_element = get_next_element(Feld[oldx][oldy]);
  2591.  
  2592.   RemoveField(oldx, oldy);
  2593.   RemoveField(newx, newy);
  2594.  
  2595.   Store[oldx][oldy] = Store2[oldx][oldy] = 0;
  2596.  
  2597.   if (next_element != EL_UNDEFINED)
  2598.     Feld[oldx][oldy] = next_element;
  2599.  
  2600.   DrawLevelField(oldx, oldy);
  2601.   DrawLevelField(newx, newy);
  2602. }
  2603.  
  2604. void DrawDynamite(int x, int y)
  2605. {
  2606.   int sx = SCREENX(x), sy = SCREENY(y);
  2607.   int graphic = el2img(Feld[x][y]);
  2608.   int frame;
  2609.  
  2610.   if (!IN_SCR_FIELD(sx, sy) || IS_PLAYER(x, y))
  2611.     return;
  2612.  
  2613.   if (IS_WALKABLE_INSIDE(Back[x][y]))
  2614.     return;
  2615.  
  2616.   if (Back[x][y])
  2617.     DrawGraphic(sx, sy, el2img(Back[x][y]), 0);
  2618.   else if (Store[x][y])
  2619.     DrawGraphic(sx, sy, el2img(Store[x][y]), 0);
  2620.  
  2621.   frame = getGraphicAnimationFrame(graphic, GfxFrame[x][y]);
  2622.  
  2623. #if 1
  2624.   if (Back[x][y] || Store[x][y])
  2625.     DrawGraphicThruMask(sx, sy, graphic, frame);
  2626.   else
  2627.     DrawGraphic(sx, sy, graphic, frame);
  2628. #else
  2629.   if (game.emulation == EMU_SUPAPLEX)
  2630.     DrawGraphic(sx, sy, IMG_SP_DISK_RED, frame);
  2631.   else if (Store[x][y])
  2632.     DrawGraphicThruMask(sx, sy, graphic, frame);
  2633.   else
  2634.     DrawGraphic(sx, sy, graphic, frame);
  2635. #endif
  2636. }
  2637.  
  2638. void CheckDynamite(int x, int y)
  2639. {
  2640.   if (MovDelay[x][y] != 0)    /* dynamite is still waiting to explode */
  2641.   {
  2642.     MovDelay[x][y]--;
  2643.  
  2644.     if (MovDelay[x][y] != 0)
  2645.     {
  2646.       DrawDynamite(x, y);
  2647.       PlayLevelSoundActionIfLoop(x, y, ACTION_ACTIVE);
  2648.  
  2649.       return;
  2650.     }
  2651.   }
  2652.  
  2653. #if 1
  2654.   StopLevelSoundActionIfLoop(x, y, ACTION_ACTIVE);
  2655. #else
  2656.   if (Feld[x][y] == EL_DYNAMITE_ACTIVE ||
  2657.       Feld[x][y] == EL_SP_DISK_RED_ACTIVE)
  2658.     StopSound(SND_DYNAMITE_ACTIVE);
  2659.   else
  2660.     StopSound(SND_DYNABOMB_ACTIVE);
  2661. #endif
  2662.  
  2663.   Bang(x, y);
  2664. }
  2665.  
  2666. void DrawRelocatePlayer(struct PlayerInfo *player)
  2667. {
  2668.   boolean ffwd_delay = (tape.playing && tape.fast_forward);
  2669.   boolean no_delay = (tape.warp_forward);
  2670.   int frame_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
  2671.   int wait_delay_value = (no_delay ? 0 : frame_delay_value);
  2672.   int jx = player->jx;
  2673.   int jy = player->jy;
  2674.  
  2675.   if (level.instant_relocation)
  2676.   {
  2677. #if 1
  2678.     int offset = (setup.scroll_delay ? 3 : 0);
  2679.  
  2680.     if (!IN_VIS_FIELD(SCREENX(jx), SCREENY(jy)))
  2681.     {
  2682.       scroll_x = (local_player->jx < SBX_Left  + MIDPOSX ? SBX_Left :
  2683.           local_player->jx > SBX_Right + MIDPOSX ? SBX_Right :
  2684.           local_player->jx - MIDPOSX);
  2685.  
  2686.       scroll_y = (local_player->jy < SBY_Upper + MIDPOSY ? SBY_Upper :
  2687.           local_player->jy > SBY_Lower + MIDPOSY ? SBY_Lower :
  2688.           local_player->jy - MIDPOSY);
  2689.     }
  2690.     else
  2691.     {
  2692.       if ((player->MovDir == MV_LEFT  && scroll_x > jx - MIDPOSX + offset) ||
  2693.       (player->MovDir == MV_RIGHT && scroll_x < jx - MIDPOSX - offset))
  2694.     scroll_x = jx - MIDPOSX + (scroll_x < jx-MIDPOSX ? -offset : +offset);
  2695.  
  2696.       if ((player->MovDir == MV_UP  && scroll_y > jy - MIDPOSY + offset) ||
  2697.       (player->MovDir == MV_DOWN && scroll_y < jy - MIDPOSY - offset))
  2698.     scroll_y = jy - MIDPOSY + (scroll_y < jy-MIDPOSY ? -offset : +offset);
  2699.  
  2700.       /* don't scroll over playfield boundaries */
  2701.       if (scroll_x < SBX_Left || scroll_x > SBX_Right)
  2702.     scroll_x = (scroll_x < SBX_Left ? SBX_Left : SBX_Right);
  2703.  
  2704.       /* don't scroll over playfield boundaries */
  2705.       if (scroll_y < SBY_Upper || scroll_y > SBY_Lower)
  2706.     scroll_y = (scroll_y < SBY_Upper ? SBY_Upper : SBY_Lower);
  2707.     }
  2708. #else
  2709.     scroll_x += (local_player->jx - old_jx);
  2710.     scroll_y += (local_player->jy - old_jy);
  2711.  
  2712.     /* don't scroll over playfield boundaries */
  2713.     if (scroll_x < SBX_Left || scroll_x > SBX_Right)
  2714.       scroll_x = (scroll_x < SBX_Left ? SBX_Left : SBX_Right);
  2715.  
  2716.     /* don't scroll over playfield boundaries */
  2717.     if (scroll_y < SBY_Upper || scroll_y > SBY_Lower)
  2718.       scroll_y = (scroll_y < SBY_Upper ? SBY_Upper : SBY_Lower);
  2719. #endif
  2720.  
  2721.     RedrawPlayfield(TRUE, 0,0,0,0);
  2722.   }
  2723.   else
  2724.   {
  2725. #if 1
  2726. #if 0
  2727.     int offset = (setup.scroll_delay ? 3 : 0);
  2728. #endif
  2729.     int scroll_xx = -999, scroll_yy = -999;
  2730.  
  2731.     ScrollScreen(NULL, SCROLL_GO_ON);    /* scroll last frame to full tile */
  2732.  
  2733.     while (scroll_xx != scroll_x || scroll_yy != scroll_y)
  2734.     {
  2735.       int dx = 0, dy = 0;
  2736.       int fx = FX, fy = FY;
  2737.  
  2738.       scroll_xx = (local_player->jx < SBX_Left  + MIDPOSX ? SBX_Left :
  2739.            local_player->jx > SBX_Right + MIDPOSX ? SBX_Right :
  2740.            local_player->jx - MIDPOSX);
  2741.  
  2742.       scroll_yy = (local_player->jy < SBY_Upper + MIDPOSY ? SBY_Upper :
  2743.            local_player->jy > SBY_Lower + MIDPOSY ? SBY_Lower :
  2744.            local_player->jy - MIDPOSY);
  2745.  
  2746.       dx = (scroll_xx < scroll_x ? +1 : scroll_xx > scroll_x ? -1 : 0);
  2747.       dy = (scroll_yy < scroll_y ? +1 : scroll_yy > scroll_y ? -1 : 0);
  2748.  
  2749. #if 1
  2750.       if (dx == 0 && dy == 0)        /* no scrolling needed at all */
  2751.     break;
  2752. #else
  2753.       if (scroll_xx == scroll_x && scroll_yy == scroll_y)
  2754.     break;
  2755. #endif
  2756.  
  2757.       scroll_x -= dx;
  2758.       scroll_y -= dy;
  2759.  
  2760.       fx += dx * TILEX / 2;
  2761.       fy += dy * TILEY / 2;
  2762.  
  2763.       ScrollLevel(dx, dy);
  2764.       DrawAllPlayers();
  2765.  
  2766.       /* scroll in two steps of half tile size to make things smoother */
  2767.       BlitBitmap(drawto_field, window, fx, fy, SXSIZE, SYSIZE, SX, SY);
  2768.       FlushDisplay();
  2769.       Delay(wait_delay_value);
  2770.  
  2771.       /* scroll second step to align at full tile size */
  2772.       BackToFront();
  2773.       Delay(wait_delay_value);
  2774.     }
  2775. #else
  2776.     int scroll_xx = -999, scroll_yy = -999;
  2777.  
  2778.     ScrollScreen(NULL, SCROLL_GO_ON);    /* scroll last frame to full tile */
  2779.  
  2780.     while (scroll_xx != scroll_x || scroll_yy != scroll_y)
  2781.     {
  2782.       int dx = 0, dy = 0;
  2783.       int fx = FX, fy = FY;
  2784.  
  2785.       scroll_xx = (local_player->jx < SBX_Left  + MIDPOSX ? SBX_Left :
  2786.            local_player->jx > SBX_Right + MIDPOSX ? SBX_Right :
  2787.            local_player->jx - MIDPOSX);
  2788.  
  2789.       scroll_yy = (local_player->jy < SBY_Upper + MIDPOSY ? SBY_Upper :
  2790.            local_player->jy > SBY_Lower + MIDPOSY ? SBY_Lower :
  2791.            local_player->jy - MIDPOSY);
  2792.  
  2793.       dx = (scroll_xx < scroll_x ? +1 : scroll_xx > scroll_x ? -1 : 0);
  2794.       dy = (scroll_yy < scroll_y ? +1 : scroll_yy > scroll_y ? -1 : 0);
  2795.  
  2796. #if 1
  2797.       if (dx == 0 && dy == 0)        /* no scrolling needed at all */
  2798.     break;
  2799. #else
  2800.       if (scroll_xx == scroll_x && scroll_yy == scroll_y)
  2801.     break;
  2802. #endif
  2803.  
  2804.       scroll_x -= dx;
  2805.       scroll_y -= dy;
  2806.  
  2807.       fx += dx * TILEX / 2;
  2808.       fy += dy * TILEY / 2;
  2809.  
  2810.       ScrollLevel(dx, dy);
  2811.       DrawAllPlayers();
  2812.  
  2813.       /* scroll in two steps of half tile size to make things smoother */
  2814.       BlitBitmap(drawto_field, window, fx, fy, SXSIZE, SYSIZE, SX, SY);
  2815.       FlushDisplay();
  2816.       Delay(wait_delay_value);
  2817.  
  2818.       /* scroll second step to align at full tile size */
  2819.       BackToFront();
  2820.       Delay(wait_delay_value);
  2821.     }
  2822. #endif
  2823.  
  2824.     DrawPlayer(player);
  2825.     BackToFront();
  2826.     Delay(wait_delay_value);
  2827.   }
  2828. }
  2829.  
  2830. void RelocatePlayer(int jx, int jy, int el_player_raw)
  2831. {
  2832. #if 1
  2833.   int el_player = GET_VALID_PLAYER_ELEMENT(el_player_raw);
  2834. #else
  2835.   int el_player = (el_player_raw == EL_SP_MURPHY ? EL_PLAYER_1 :el_player_raw);
  2836. #endif
  2837.   struct PlayerInfo *player = &stored_player[el_player - EL_PLAYER_1];
  2838.   boolean ffwd_delay = (tape.playing && tape.fast_forward);
  2839.   boolean no_delay = (tape.warp_forward);
  2840.   int frame_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
  2841.   int wait_delay_value = (no_delay ? 0 : frame_delay_value);
  2842.   int old_jx = player->jx;
  2843.   int old_jy = player->jy;
  2844.   int old_element = Feld[old_jx][old_jy];
  2845.   int element = Feld[jx][jy];
  2846.   boolean player_relocated = (old_jx != jx || old_jy != jy);
  2847.  
  2848.   int move_dir_horiz = (jx < old_jx ? MV_LEFT : jx > old_jx ? MV_RIGHT : 0);
  2849.   int move_dir_vert  = (jy < old_jy ? MV_UP   : jy > old_jy ? MV_DOWN  : 0);
  2850. #if 1
  2851.   int enter_side_horiz = MV_DIR_OPPOSITE(move_dir_horiz);
  2852.   int enter_side_vert  = MV_DIR_OPPOSITE(move_dir_vert);
  2853.   int leave_side_horiz = move_dir_horiz;
  2854.   int leave_side_vert  = move_dir_vert;
  2855. #else
  2856.   static int trigger_sides[4][2] =
  2857.   {
  2858.     /* enter side               leave side */
  2859.     { CH_SIDE_RIGHT,        CH_SIDE_LEFT    },    /* moving left  */
  2860.     { CH_SIDE_LEFT,        CH_SIDE_RIGHT    },    /* moving right */
  2861.     { CH_SIDE_BOTTOM,        CH_SIDE_TOP    },    /* moving up    */
  2862.     { CH_SIDE_TOP,        CH_SIDE_BOTTOM    }    /* moving down  */
  2863.   };
  2864.   int enter_side_horiz = trigger_sides[MV_DIR_BIT(move_dir_horiz)][0];
  2865.   int enter_side_vert  = trigger_sides[MV_DIR_BIT(move_dir_vert)][0];
  2866.   int leave_side_horiz = trigger_sides[MV_DIR_BIT(move_dir_horiz)][1];
  2867.   int leave_side_vert  = trigger_sides[MV_DIR_BIT(move_dir_vert)][1];
  2868. #endif
  2869.   int enter_side = enter_side_horiz | enter_side_vert;
  2870.   int leave_side = leave_side_horiz | leave_side_vert;
  2871.  
  2872.   if (player->GameOver)        /* do not reanimate dead player */
  2873.     return;
  2874.  
  2875.   if (!player_relocated)    /* no need to relocate the player */
  2876.     return;
  2877.  
  2878.   if (IS_PLAYER(jx, jy))    /* player already placed at new position */
  2879.   {
  2880.     RemoveField(jx, jy);    /* temporarily remove newly placed player */
  2881.     DrawLevelField(jx, jy);
  2882.   }
  2883.  
  2884.   if (player->present)
  2885.   {
  2886.     while (player->MovPos)
  2887.     {
  2888.       ScrollPlayer(player, SCROLL_GO_ON);
  2889.       ScrollScreen(NULL, SCROLL_GO_ON);
  2890.       FrameCounter++;
  2891.  
  2892.       DrawPlayer(player);
  2893.  
  2894.       BackToFront();
  2895.       Delay(wait_delay_value);
  2896.     }
  2897.  
  2898.     DrawPlayer(player);        /* needed here only to cleanup last field */
  2899.     DrawLevelField(player->jx, player->jy);    /* remove player graphic */
  2900.  
  2901.     player->is_moving = FALSE;
  2902.   }
  2903.  
  2904. #if 1
  2905.   if (IS_CUSTOM_ELEMENT(old_element))
  2906.     CheckElementChangeByPlayer(old_jx, old_jy, old_element,
  2907.                    CE_LEFT_BY_PLAYER,
  2908.                    player->index_bit, leave_side);
  2909.  
  2910.   CheckTriggeredElementChangeByPlayer(old_jx, old_jy, old_element,
  2911.                       CE_OTHER_GETS_LEFT,
  2912.                       player->index_bit, leave_side);
  2913. #endif
  2914.  
  2915.   Feld[jx][jy] = el_player;
  2916.   InitPlayerField(jx, jy, el_player, TRUE);
  2917.  
  2918.   if (!ELEM_IS_PLAYER(element))    /* player may be set on walkable element */
  2919.   {
  2920.     Feld[jx][jy] = element;
  2921.     InitField(jx, jy, FALSE);
  2922.   }
  2923.  
  2924. #if 1
  2925.   if (player == local_player)    /* only visually relocate local player */
  2926.     DrawRelocatePlayer(player);
  2927. #endif
  2928.  
  2929. #if 1
  2930.   TestIfHeroTouchesBadThing(jx, jy);
  2931.   TestIfPlayerTouchesCustomElement(jx, jy);
  2932. #endif
  2933.  
  2934. #if 0
  2935.   printf("::: %d,%d: %d\n", jx, jy-1, Changed[jx][jy-1]);
  2936. #endif
  2937.  
  2938. #if 0
  2939. #if 0
  2940.   /* needed to allow change of walkable custom element by entering player */
  2941.   if (!(Changed[jx][jy] & CH_EVENT_BIT(CE_ENTERED_BY_PLAYER)))
  2942.     Changed[jx][jy] = 0;    /* allow another change (but prevent loop) */
  2943. #else
  2944.   /* needed to allow change of walkable custom element by entering player */
  2945.   Changed[jx][jy] = 0;        /* allow another change */
  2946. #endif
  2947. #endif
  2948.  
  2949. #if 0
  2950.   printf("::: player entering %d, %d from %s ...\n", jx, jy,
  2951.      enter_side == MV_LEFT  ? "left" :
  2952.      enter_side == MV_RIGHT ? "right" :
  2953.      enter_side == MV_UP    ? "top" :
  2954.      enter_side == MV_DOWN  ? "bottom" : "oops! no idea!");
  2955. #endif
  2956.  
  2957. #if 1
  2958.   if (IS_CUSTOM_ELEMENT(element))
  2959.     CheckElementChangeByPlayer(jx, jy, element, CE_ENTERED_BY_PLAYER,
  2960.                    player->index_bit, enter_side);
  2961.  
  2962.   CheckTriggeredElementChangeByPlayer(jx, jy, element,
  2963.                       CE_OTHER_GETS_ENTERED,
  2964.                       player->index_bit, enter_side);
  2965. #endif
  2966. }
  2967.  
  2968. void Explode(int ex, int ey, int phase, int mode)
  2969. {
  2970.   int x, y;
  2971. #if 0
  2972.   int num_phase = 9;
  2973. #endif
  2974.  
  2975.   /* !!! eliminate this variable !!! */
  2976.   int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
  2977.  
  2978. #if 1
  2979.   int last_phase;
  2980. #else
  2981.   int last_phase = num_phase * delay;
  2982.   int half_phase = (num_phase / 2) * delay;
  2983.   int first_phase_after_start = EX_PHASE_START + 1;
  2984. #endif
  2985.   int border_element;
  2986.  
  2987.   if (game.explosions_delayed)
  2988.   {
  2989.     ExplodeField[ex][ey] = mode;
  2990.     return;
  2991.   }
  2992.  
  2993.   if (phase == EX_PHASE_START)        /* initialize 'Store[][]' field */
  2994.   {
  2995.     int center_element = Feld[ex][ey];
  2996.  
  2997. #if 0
  2998.     printf("::: start explosion %d,%d [%d]\n", ex, ey, FrameCounter);
  2999. #endif
  3000.  
  3001. #if 0
  3002.     /* --- This is only really needed (and now handled) in "Impact()". --- */
  3003.     /* do not explode moving elements that left the explode field in time */
  3004.     if (game.engine_version >= VERSION_IDENT(2,2,0,7) &&
  3005.     center_element == EL_EMPTY &&
  3006.     (mode == EX_TYPE_NORMAL || mode == EX_TYPE_CENTER))
  3007.       return;
  3008. #endif
  3009.  
  3010.     if (mode == EX_TYPE_NORMAL || mode == EX_TYPE_CENTER)
  3011.       PlayLevelSoundAction(ex, ey, ACTION_EXPLODING);
  3012.  
  3013.     /* remove things displayed in background while burning dynamite */
  3014.     if (Back[ex][ey] != EL_EMPTY && !IS_INDESTRUCTIBLE(Back[ex][ey]))
  3015.       Back[ex][ey] = 0;
  3016.  
  3017.     if (IS_MOVING(ex, ey) || IS_BLOCKED(ex, ey))
  3018.     {
  3019.       /* put moving element to center field (and let it explode there) */
  3020.       center_element = MovingOrBlocked2Element(ex, ey);
  3021.       RemoveMovingField(ex, ey);
  3022.       Feld[ex][ey] = center_element;
  3023.     }
  3024.  
  3025. #if 1
  3026.  
  3027. #if 1
  3028.     last_phase = element_info[center_element].explosion_delay + 1;
  3029. #else
  3030.     last_phase = element_info[center_element].explosion_delay;
  3031. #endif
  3032.  
  3033. #if 0
  3034.     printf("::: %d -> %d\n", center_element, last_phase);
  3035. #endif
  3036. #endif
  3037.  
  3038.     for (y = ey - 1; y <= ey + 1; y++) for (x = ex - 1; x <= ex + 1; x++)
  3039.     {
  3040.       int xx = x - ex + 1;
  3041.       int yy = y - ey + 1;
  3042.       int element;
  3043.  
  3044. #if 1
  3045. #if 1
  3046.       if (!IN_LEV_FIELD(x, y) ||
  3047.       (mode & EX_TYPE_SINGLE_TILE && (x != ex || y != ey)) ||
  3048.       (mode == EX_TYPE_CROSS      && (x != ex && y != ey)))
  3049.     continue;
  3050. #else
  3051.       if (!IN_LEV_FIELD(x, y) ||
  3052.       (mode != EX_TYPE_NORMAL && (x != ex || y != ey)))
  3053.     continue;
  3054. #endif
  3055. #else
  3056.       if (!IN_LEV_FIELD(x, y) ||
  3057.       ((mode != EX_TYPE_NORMAL ||
  3058.         center_element == EL_AMOEBA_TO_DIAMOND) &&
  3059.        (x != ex || y != ey)))
  3060.     continue;
  3061. #endif
  3062.  
  3063.       element = Feld[x][y];
  3064.  
  3065.       if (IS_MOVING(x, y) || IS_BLOCKED(x, y))
  3066.       {
  3067.     element = MovingOrBlocked2Element(x, y);
  3068.  
  3069.     if (!IS_EXPLOSION_PROOF(element))
  3070.       RemoveMovingField(x, y);
  3071.       }
  3072.  
  3073. #if 1
  3074.  
  3075. #if 0
  3076.       if (IS_EXPLOSION_PROOF(element))
  3077.     continue;
  3078. #else
  3079.       /* indestructible elements can only explode in center (but not flames) */
  3080. #if 1
  3081.       if ((IS_EXPLOSION_PROOF(element) && (x != ex || y != ey ||
  3082.                        mode == EX_TYPE_BORDER)) ||
  3083.       element == EL_FLAMES)
  3084.     continue;
  3085. #else
  3086.       if ((IS_EXPLOSION_PROOF(element) && (x != ex || y != ey)) ||
  3087.       element == EL_FLAMES)
  3088.     continue;
  3089. #endif
  3090. #endif
  3091.  
  3092. #else
  3093.       if ((IS_INDESTRUCTIBLE(element) &&
  3094.        (game.engine_version < VERSION_IDENT(2,2,0,0) ||
  3095.         (!IS_WALKABLE_OVER(element) && !IS_WALKABLE_UNDER(element)))) ||
  3096.       element == EL_FLAMES)
  3097.     continue;
  3098. #endif
  3099.  
  3100. #if 1
  3101.       if (IS_PLAYER(x, y) && SHIELD_ON(PLAYERINFO(x, y)) &&
  3102.       (game.engine_version < VERSION_IDENT(3,1,0,0) ||
  3103.        (x == ex && y == ey && mode != EX_TYPE_BORDER)))
  3104. #else
  3105.       if (IS_PLAYER(x, y) && SHIELD_ON(PLAYERINFO(x, y)))
  3106. #endif
  3107.       {
  3108.     if (IS_ACTIVE_BOMB(element))
  3109.     {
  3110.       /* re-activate things under the bomb like gate or penguin */
  3111. #if 1
  3112.       Feld[x][y] = (Back[x][y] ? Back[x][y] : EL_EMPTY);
  3113.       Back[x][y] = 0;
  3114. #else
  3115.       Feld[x][y] = (Store[x][y] ? Store[x][y] : EL_EMPTY);
  3116.       Store[x][y] = 0;
  3117. #endif
  3118.  
  3119. #if 0
  3120.     printf("::: %d,%d: %d %s [%d, %d]\n", x, y, Feld[x][y],
  3121.            element_info[Feld[x][y]].token_name,
  3122.            Store[x][y], Store2[x][y]);
  3123. #endif
  3124.     }
  3125.  
  3126.     continue;
  3127.       }
  3128.  
  3129.       /* save walkable background elements while explosion on same tile */
  3130. #if 0
  3131.       if (IS_INDESTRUCTIBLE(element))
  3132.     Back[x][y] = element;
  3133. #else
  3134. #if 1
  3135. #if 1
  3136.       if (IS_WALKABLE(element) && IS_INDESTRUCTIBLE(element) &&
  3137.       (x != ex || y != ey || mode == EX_TYPE_BORDER))
  3138.     Back[x][y] = element;
  3139. #else
  3140.       if (IS_WALKABLE(element) && IS_INDESTRUCTIBLE(element) &&
  3141.       (x != ex || y != ey))
  3142.     Back[x][y] = element;
  3143. #endif
  3144. #else
  3145.       if (IS_WALKABLE(element) && IS_INDESTRUCTIBLE(element))
  3146.     Back[x][y] = element;
  3147. #endif
  3148. #endif
  3149.  
  3150.       /* ignite explodable elements reached by other explosion */
  3151.       if (element == EL_EXPLOSION)
  3152.     element = Store2[x][y];
  3153.  
  3154. #if 1
  3155.       if (AmoebaNr[x][y] &&
  3156.       (element == EL_AMOEBA_FULL ||
  3157.        element == EL_BD_AMOEBA ||
  3158.        element == EL_AMOEBA_GROWING))
  3159.       {
  3160.     AmoebaCnt[AmoebaNr[x][y]]--;
  3161.     AmoebaCnt2[AmoebaNr[x][y]]--;
  3162.       }
  3163.  
  3164.       RemoveField(x, y);
  3165. #endif
  3166.  
  3167.       if (IS_PLAYER(ex, ey) && !PLAYER_EXPLOSION_PROTECTED(ex, ey))
  3168.       {
  3169.     switch(StorePlayer[ex][ey])
  3170.     {
  3171.       case EL_PLAYER_2:
  3172.         Store[x][y] = EL_PLAYER_IS_EXPLODING_2;
  3173.         break;
  3174.       case EL_PLAYER_3:
  3175.         Store[x][y] = EL_PLAYER_IS_EXPLODING_3;
  3176.         break;
  3177.       case EL_PLAYER_4:
  3178.         Store[x][y] = EL_PLAYER_IS_EXPLODING_4;
  3179.         break;
  3180.       case EL_PLAYER_1:
  3181.       default:
  3182.         Store[x][y] = EL_PLAYER_IS_EXPLODING_1;
  3183.         break;
  3184.     }
  3185.  
  3186. #if 1
  3187.     if (PLAYERINFO(ex, ey)->use_murphy_graphic)
  3188.       Store[x][y] = EL_EMPTY;
  3189. #else
  3190.     if (game.emulation == EMU_SUPAPLEX)
  3191.       Store[x][y] = EL_EMPTY;
  3192. #endif
  3193.       }
  3194.       else if (center_element == EL_MOLE)
  3195.     Store[x][y] = EL_EMERALD_RED;
  3196.       else if (center_element == EL_PENGUIN)
  3197.     Store[x][y] = EL_EMERALD_PURPLE;
  3198.       else if (center_element == EL_BUG)
  3199.     Store[x][y] = ((x == ex && y == ey) ? EL_DIAMOND : EL_EMERALD);
  3200.       else if (center_element == EL_BD_BUTTERFLY)
  3201.     Store[x][y] = EL_BD_DIAMOND;
  3202.       else if (center_element == EL_SP_ELECTRON)
  3203.     Store[x][y] = EL_SP_INFOTRON;
  3204.       else if (center_element == EL_AMOEBA_TO_DIAMOND)
  3205.     Store[x][y] = level.amoeba_content;
  3206.       else if (center_element == EL_YAMYAM)
  3207.     Store[x][y] = level.yamyam_content[game.yamyam_content_nr][xx][yy];
  3208.       else if (IS_CUSTOM_ELEMENT(center_element) &&
  3209.            element_info[center_element].content[xx][yy] != EL_EMPTY)
  3210.     Store[x][y] = element_info[center_element].content[xx][yy];
  3211.       else if (element == EL_WALL_EMERALD)
  3212.     Store[x][y] = EL_EMERALD;
  3213.       else if (element == EL_WALL_DIAMOND)
  3214.     Store[x][y] = EL_DIAMOND;
  3215.       else if (element == EL_WALL_BD_DIAMOND)
  3216.     Store[x][y] = EL_BD_DIAMOND;
  3217.       else if (element == EL_WALL_EMERALD_YELLOW)
  3218.     Store[x][y] = EL_EMERALD_YELLOW;
  3219.       else if (element == EL_WALL_EMERALD_RED)
  3220.     Store[x][y] = EL_EMERALD_RED;
  3221.       else if (element == EL_WALL_EMERALD_PURPLE)
  3222.     Store[x][y] = EL_EMERALD_PURPLE;
  3223.       else if (element == EL_WALL_PEARL)
  3224.     Store[x][y] = EL_PEARL;
  3225.       else if (element == EL_WALL_CRYSTAL)
  3226.     Store[x][y] = EL_CRYSTAL;
  3227.       else if (IS_CUSTOM_ELEMENT(element) && !CAN_EXPLODE(element))
  3228.     Store[x][y] = element_info[element].content[1][1];
  3229.       else
  3230.     Store[x][y] = EL_EMPTY;
  3231.  
  3232.       if (x != ex || y != ey || mode == EX_TYPE_BORDER ||
  3233.       center_element == EL_AMOEBA_TO_DIAMOND)
  3234.     Store2[x][y] = element;
  3235.  
  3236. #if 0
  3237.       printf("::: %d,%d: %d %s\n", x, y, Store2[x][y],
  3238.          element_info[Store2[x][y]].token_name);
  3239. #endif
  3240.  
  3241. #if 0
  3242.       if (AmoebaNr[x][y] &&
  3243.       (element == EL_AMOEBA_FULL ||
  3244.        element == EL_BD_AMOEBA ||
  3245.        element == EL_AMOEBA_GROWING))
  3246.       {
  3247.     AmoebaCnt[AmoebaNr[x][y]]--;
  3248.     AmoebaCnt2[AmoebaNr[x][y]]--;
  3249.       }
  3250.  
  3251. #if 1
  3252.       RemoveField(x, y);
  3253. #else
  3254.       MovDir[x][y] = MovPos[x][y] = 0;
  3255.       GfxDir[x][y] = MovDir[x][y];
  3256.       AmoebaNr[x][y] = 0;
  3257. #endif
  3258. #endif
  3259.  
  3260.       Feld[x][y] = EL_EXPLOSION;
  3261. #if 1
  3262.       GfxElement[x][y] = center_element;
  3263. #else
  3264.       GfxElement[x][y] = EL_UNDEFINED;
  3265. #endif
  3266.  
  3267.       ExplodePhase[x][y] = 1;
  3268. #if 1
  3269.       ExplodeDelay[x][y] = last_phase;
  3270. #endif
  3271.  
  3272. #if 0
  3273. #if 1
  3274.       GfxFrame[x][y] = 0;    /* animation does not start until next frame */
  3275. #else
  3276.       GfxFrame[x][y] = -1;    /* animation does not start until next frame */
  3277. #endif
  3278. #endif
  3279.  
  3280.       Stop[x][y] = TRUE;
  3281.     }
  3282.  
  3283.     if (center_element == EL_YAMYAM)
  3284.       game.yamyam_content_nr =
  3285.     (game.yamyam_content_nr + 1) % level.num_yamyam_contents;
  3286.  
  3287. #if 0
  3288.   printf("::: %d,%d: %d %s [%d]\n", ex + 1, ey, Feld[ex + 1][ey],
  3289.      element_info[Feld[ex + 1][ey]].token_name, Store2[ex + 1][ey]);
  3290. #endif
  3291.  
  3292.     return;
  3293.   }
  3294.  
  3295.   if (Stop[ex][ey])
  3296.     return;
  3297.  
  3298.   x = ex;
  3299.   y = ey;
  3300.  
  3301. #if 1
  3302.   if (phase == 1)
  3303.     GfxFrame[x][y] = 0;        /* restart explosion animation */
  3304. #endif
  3305.  
  3306. #if 0
  3307.   printf(":X: phase == %d [%d]\n", phase, GfxFrame[x][y]);
  3308. #endif
  3309.  
  3310. #if 1
  3311.   last_phase = ExplodeDelay[x][y];
  3312. #endif
  3313.  
  3314.   ExplodePhase[x][y] = (phase < last_phase ? phase + 1 : 0);
  3315.  
  3316. #ifdef DEBUG
  3317.  
  3318.   /* activate this even in non-DEBUG version until cause for crash in
  3319.      getGraphicAnimationFrame() (see below) is found and eliminated */
  3320. #endif
  3321. #if 1
  3322.  
  3323.   if (GfxElement[x][y] == EL_UNDEFINED)
  3324.   {
  3325.     printf("\n\n");
  3326.     printf("Explode(): x = %d, y = %d: GfxElement == EL_UNDEFINED\n", x, y);
  3327.     printf("Explode(): This should never happen!\n");
  3328.     printf("\n\n");
  3329.  
  3330.     GfxElement[x][y] = EL_EMPTY;
  3331.   }
  3332. #endif
  3333.  
  3334. #if 1
  3335.  
  3336.   border_element = Store2[x][y];
  3337. #if 1
  3338.   if (IS_PLAYER(x, y) && !PLAYER_EXPLOSION_PROTECTED(x, y))
  3339.     border_element = StorePlayer[x][y];
  3340. #else
  3341.   if (IS_PLAYER(x, y))
  3342.     border_element = StorePlayer[x][y];
  3343. #endif
  3344.  
  3345. #if 0
  3346.   printf("::: %d,%d: %d %s [%d]\n", x, y, border_element,
  3347.      element_info[border_element].token_name, Store2[x][y]);
  3348. #endif
  3349.  
  3350. #if 0
  3351.   printf("::: phase == %d\n", phase);
  3352. #endif
  3353.  
  3354.   if (phase == element_info[border_element].ignition_delay ||
  3355.       phase == last_phase)
  3356.   {
  3357.     boolean border_explosion = FALSE;
  3358.  
  3359. #if 1
  3360. #if 1
  3361.     if (IS_PLAYER(x, y) && PLAYERINFO(x, y)->present &&
  3362.     !PLAYER_EXPLOSION_PROTECTED(x, y))
  3363. #else
  3364.     if (IS_PLAYER(x, y) && PLAYERINFO(x, y)->present)
  3365. #endif
  3366. #else
  3367.     if (IS_PLAYER(x, y))
  3368. #endif
  3369.     {
  3370.       KillHeroUnlessExplosionProtected(x, y);
  3371.       border_explosion = TRUE;
  3372.  
  3373. #if 0
  3374.       if (phase == last_phase)
  3375.     printf("::: IS_PLAYER\n");
  3376. #endif
  3377.     }
  3378.     else if (CAN_EXPLODE_BY_EXPLOSION(border_element))
  3379.     {
  3380. #if 0
  3381.       printf("::: %d,%d: %d %s\n", x, y, border_element,
  3382.          element_info[border_element].token_name);
  3383. #endif
  3384.  
  3385.       Feld[x][y] = Store2[x][y];
  3386.       Store2[x][y] = 0;
  3387.       Bang(x, y);
  3388.       border_explosion = TRUE;
  3389.  
  3390. #if 0
  3391.       if (phase == last_phase)
  3392.     printf("::: CAN_EXPLODE_BY_EXPLOSION\n");
  3393. #endif
  3394.     }
  3395.     else if (border_element == EL_AMOEBA_TO_DIAMOND)
  3396.     {
  3397.       AmoebeUmwandeln(x, y);
  3398.       Store2[x][y] = 0;
  3399.       border_explosion = TRUE;
  3400.  
  3401. #if 0
  3402.       if (phase == last_phase)
  3403.     printf("::: EL_AMOEBA_TO_DIAMOND [%d, %d] [%d]\n",
  3404.            element_info[border_element].explosion_delay,
  3405.            element_info[border_element].ignition_delay,
  3406.            phase);
  3407. #endif
  3408.     }
  3409.  
  3410. #if 1
  3411.     /* if an element just explodes due to another explosion (chain-reaction),
  3412.        do not immediately end the new explosion when it was the last frame of
  3413.        the explosion (as it would be done in the following "if"-statement!) */
  3414.     if (border_explosion && phase == last_phase)
  3415.       return;
  3416. #endif
  3417.   }
  3418.  
  3419. #else
  3420.  
  3421.   if (phase == first_phase_after_start)
  3422.   {
  3423.     int element = Store2[x][y];
  3424.  
  3425.     if (element == EL_BLACK_ORB)
  3426.     {
  3427.       Feld[x][y] = Store2[x][y];
  3428.       Store2[x][y] = 0;
  3429.       Bang(x, y);
  3430.     }
  3431.   }
  3432.   else if (phase == half_phase)
  3433.   {
  3434.     int element = Store2[x][y];
  3435.  
  3436.     if (IS_PLAYER(x, y))
  3437.       KillHeroUnlessExplosionProtected(x, y);
  3438.     else if (CAN_EXPLODE_BY_EXPLOSION(element))
  3439.     {
  3440.       Feld[x][y] = Store2[x][y];
  3441.       Store2[x][y] = 0;
  3442.       Bang(x, y);
  3443.     }
  3444.     else if (element == EL_AMOEBA_TO_DIAMOND)
  3445.       AmoebeUmwandeln(x, y);
  3446.   }
  3447. #endif
  3448.  
  3449.   if (phase == last_phase)
  3450.   {
  3451.     int element;
  3452.  
  3453. #if 0
  3454.   printf("::: done: phase == %d\n", phase);
  3455. #endif
  3456.  
  3457. #if 0
  3458.     printf("::: explosion %d,%d done [%d]\n", x, y, FrameCounter);
  3459. #endif
  3460.  
  3461.     element = Feld[x][y] = Store[x][y];
  3462.     Store[x][y] = Store2[x][y] = 0;
  3463.     GfxElement[x][y] = EL_UNDEFINED;
  3464.  
  3465.     /* player can escape from explosions and might therefore be still alive */
  3466.     if (element >= EL_PLAYER_IS_EXPLODING_1 &&
  3467.     element <= EL_PLAYER_IS_EXPLODING_4)
  3468.       Feld[x][y] = (stored_player[element - EL_PLAYER_IS_EXPLODING_1].active ?
  3469.             EL_EMPTY :
  3470.             element == EL_PLAYER_IS_EXPLODING_1 ? EL_EMERALD_YELLOW :
  3471.             element == EL_PLAYER_IS_EXPLODING_2 ? EL_EMERALD_RED :
  3472.             element == EL_PLAYER_IS_EXPLODING_3 ? EL_EMERALD :
  3473.             EL_EMERALD_PURPLE);
  3474.  
  3475.     /* restore probably existing indestructible background element */
  3476.     if (Back[x][y] && IS_INDESTRUCTIBLE(Back[x][y]))
  3477.       element = Feld[x][y] = Back[x][y];
  3478.     Back[x][y] = 0;
  3479.  
  3480.     MovDir[x][y] = MovPos[x][y] = MovDelay[x][y] = 0;
  3481.     GfxDir[x][y] = MV_NO_MOVING;
  3482.     ChangeDelay[x][y] = 0;
  3483.     ChangePage[x][y] = -1;
  3484.  
  3485. #if 1
  3486.     InitField_WithBug2(x, y, FALSE);
  3487. #else
  3488.     InitField(x, y, FALSE);
  3489. #if 1
  3490.     /* !!! not needed !!! */
  3491. #if 1
  3492.     if (game.engine_version < VERSION_IDENT(3,1,0,0) &&
  3493.     CAN_MOVE(Feld[x][y]) && Feld[x][y] != EL_MOLE)
  3494.       InitMovDir(x, y);
  3495. #else
  3496.     if (CAN_MOVE(element))
  3497.       InitMovDir(x, y);
  3498. #endif
  3499. #endif
  3500. #endif
  3501.     DrawLevelField(x, y);
  3502.  
  3503.     TestIfElementTouchesCustomElement(x, y);
  3504.  
  3505.     if (GFX_CRUMBLED(element))
  3506.       DrawLevelFieldCrumbledSandNeighbours(x, y);
  3507.  
  3508.     if (IS_PLAYER(x, y) && !PLAYERINFO(x, y)->present)
  3509.       StorePlayer[x][y] = 0;
  3510.  
  3511.     if (ELEM_IS_PLAYER(element))
  3512.       RelocatePlayer(x, y, element);
  3513.   }
  3514. #if 1
  3515.   else if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
  3516. #else
  3517.   else if (phase >= delay && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
  3518. #endif
  3519.   {
  3520. #if 1
  3521.     int graphic = el_act2img(GfxElement[x][y], ACTION_EXPLODING);
  3522. #else
  3523.     int stored = Store[x][y];
  3524.     int graphic = (game.emulation != EMU_SUPAPLEX ? IMG_EXPLOSION :
  3525.            stored == EL_SP_INFOTRON ? IMG_SP_EXPLOSION_INFOTRON :
  3526.            IMG_SP_EXPLOSION);
  3527. #endif
  3528. #if 1
  3529.     int frame = getGraphicAnimationFrame(graphic, GfxFrame[x][y]);
  3530. #else
  3531.     int frame = getGraphicAnimationFrame(graphic, phase - delay);
  3532. #endif
  3533.  
  3534. #if 0
  3535.   printf("::: phase == %d [%d]\n", phase, GfxFrame[x][y]);
  3536. #endif
  3537.  
  3538. #if 0
  3539.     printf("::: %d / %d [%d - %d]\n",
  3540.        GfxFrame[x][y], phase - delay, phase, delay);
  3541. #endif
  3542.  
  3543. #if 0
  3544.     printf("::: %d ['%s'] -> %d\n", GfxElement[x][y],
  3545.        element_info[GfxElement[x][y]].token_name,
  3546.        graphic);
  3547. #endif
  3548.  
  3549.     if (phase == delay)
  3550.       DrawLevelFieldCrumbledSand(x, y);
  3551.  
  3552.     if (IS_WALKABLE_OVER(Back[x][y]) && Back[x][y] != EL_EMPTY)
  3553.     {
  3554.       DrawLevelElement(x, y, Back[x][y]);
  3555.       DrawGraphicThruMask(SCREENX(x), SCREENY(y), graphic, frame);
  3556.     }
  3557.     else if (IS_WALKABLE_UNDER(Back[x][y]))
  3558.     {
  3559.       DrawGraphic(SCREENX(x), SCREENY(y), graphic, frame);
  3560.       DrawLevelElementThruMask(x, y, Back[x][y]);
  3561.     }
  3562.     else if (!IS_WALKABLE_INSIDE(Back[x][y]))
  3563.       DrawGraphic(SCREENX(x), SCREENY(y), graphic, frame);
  3564.   }
  3565. }
  3566.  
  3567. void DynaExplode(int ex, int ey)
  3568. {
  3569.   int i, j;
  3570.   int dynabomb_element = Feld[ex][ey];
  3571.   int dynabomb_size = 1;
  3572.   boolean dynabomb_xl = FALSE;
  3573.   struct PlayerInfo *player;
  3574.   static int xy[4][2] =
  3575.   {
  3576.     { 0, -1 },
  3577.     { -1, 0 },
  3578.     { +1, 0 },
  3579.     { 0, +1 }
  3580.   };
  3581.  
  3582.   if (IS_ACTIVE_BOMB(dynabomb_element))
  3583.   {
  3584.     player = &stored_player[dynabomb_element - EL_DYNABOMB_PLAYER_1_ACTIVE];
  3585.     dynabomb_size = player->dynabomb_size;
  3586.     dynabomb_xl = player->dynabomb_xl;
  3587.     player->dynabombs_left++;
  3588.   }
  3589.  
  3590.   Explode(ex, ey, EX_PHASE_START, EX_TYPE_CENTER);
  3591.  
  3592.   for (i = 0; i < NUM_DIRECTIONS; i++)
  3593.   {
  3594.     for (j = 1; j <= dynabomb_size; j++)
  3595.     {
  3596.       int x = ex + j * xy[i][0];
  3597.       int y = ey + j * xy[i][1];
  3598.       int element;
  3599.  
  3600.       if (!IN_LEV_FIELD(x, y) || IS_INDESTRUCTIBLE(Feld[x][y]))
  3601.     break;
  3602.  
  3603.       element = Feld[x][y];
  3604.  
  3605.       /* do not restart explosions of fields with active bombs */
  3606.       if (element == EL_EXPLOSION && IS_ACTIVE_BOMB(Store2[x][y]))
  3607.     continue;
  3608.  
  3609.       Explode(x, y, EX_PHASE_START, EX_TYPE_BORDER);
  3610.  
  3611. #if 1
  3612. #if 1
  3613.       if (element != EL_EMPTY && element != EL_EXPLOSION &&
  3614.       !IS_DIGGABLE(element) && !dynabomb_xl)
  3615.     break;
  3616. #else
  3617.       if (element != EL_EMPTY && element != EL_EXPLOSION &&
  3618.       !CAN_GROW_INTO(element) && !dynabomb_xl)
  3619.     break;
  3620. #endif
  3621. #else
  3622.       /* !!! extend EL_SAND to anything diggable (but maybe not SP_BASE) !!! */
  3623.       if (element != EL_EMPTY && element != EL_EXPLOSION &&
  3624.       element != EL_SAND && !dynabomb_xl)
  3625.     break;
  3626. #endif
  3627.     }
  3628.   }
  3629. }
  3630.  
  3631. void Bang(int x, int y)
  3632. {
  3633. #if 1
  3634.   int element = MovingOrBlocked2Element(x, y);
  3635. #else
  3636.   int element = Feld[x][y];
  3637. #endif
  3638.  
  3639. #if 1
  3640.   if (IS_PLAYER(x, y) && !PLAYER_EXPLOSION_PROTECTED(x, y))
  3641. #else
  3642.   if (IS_PLAYER(x, y))
  3643. #endif
  3644.   {
  3645.     struct PlayerInfo *player = PLAYERINFO(x, y);
  3646.  
  3647.     element = Feld[x][y] = (player->use_murphy_graphic ? EL_SP_MURPHY :
  3648.                 player->element_nr);
  3649.   }
  3650.  
  3651. #if 0
  3652. #if 1
  3653.   PlayLevelSoundAction(x, y, ACTION_EXPLODING);
  3654. #else
  3655.   if (game.emulation == EMU_SUPAPLEX)
  3656.     PlayLevelSound(x, y, SND_SP_ELEMENT_EXPLODING);
  3657.   else
  3658.     PlayLevelSound(x, y, SND_ELEMENT_EXPLODING);
  3659. #endif
  3660. #endif
  3661.  
  3662. #if 0
  3663.   if (IS_PLAYER(x, y))    /* remove objects that might cause smaller explosion */
  3664.     element = EL_EMPTY;
  3665. #endif
  3666.  
  3667.   switch(element)
  3668.   {
  3669.     case EL_BUG:
  3670.     case EL_SPACESHIP:
  3671.     case EL_BD_BUTTERFLY:
  3672.     case EL_BD_FIREFLY:
  3673.     case EL_YAMYAM:
  3674.     case EL_DARK_YAMYAM:
  3675.     case EL_ROBOT:
  3676.     case EL_PACMAN:
  3677.     case EL_MOLE:
  3678.       RaiseScoreElement(element);
  3679.       Explode(x, y, EX_PHASE_START, EX_TYPE_NORMAL);
  3680.       break;
  3681.     case EL_DYNABOMB_PLAYER_1_ACTIVE:
  3682.     case EL_DYNABOMB_PLAYER_2_ACTIVE:
  3683.     case EL_DYNABOMB_PLAYER_3_ACTIVE:
  3684.     case EL_DYNABOMB_PLAYER_4_ACTIVE:
  3685.     case EL_DYNABOMB_INCREASE_NUMBER:
  3686.     case EL_DYNABOMB_INCREASE_SIZE:
  3687.     case EL_DYNABOMB_INCREASE_POWER:
  3688.       DynaExplode(x, y);
  3689.       break;
  3690.     case EL_PENGUIN:
  3691.     case EL_LAMP:
  3692.     case EL_LAMP_ACTIVE:
  3693. #if 1
  3694.     case EL_AMOEBA_TO_DIAMOND:
  3695. #endif
  3696.       if (IS_PLAYER(x, y))
  3697.     Explode(x, y, EX_PHASE_START, EX_TYPE_NORMAL);
  3698.       else
  3699.     Explode(x, y, EX_PHASE_START, EX_TYPE_CENTER);
  3700.       break;
  3701.     default:
  3702. #if 1
  3703.       if (element_info[element].explosion_type == EXPLODES_CROSS)
  3704. #else
  3705.       if (CAN_EXPLODE_CROSS(element))
  3706. #endif
  3707. #if 1
  3708.     Explode(x, y, EX_PHASE_START, EX_TYPE_CROSS);
  3709. #else
  3710.     DynaExplode(x, y);
  3711. #endif
  3712. #if 1
  3713.       else if (element_info[element].explosion_type == EXPLODES_1X1)
  3714. #else
  3715.       else if (CAN_EXPLODE_1X1(element))
  3716. #endif
  3717.     Explode(x, y, EX_PHASE_START, EX_TYPE_CENTER);
  3718.       else
  3719.     Explode(x, y, EX_PHASE_START, EX_TYPE_NORMAL);
  3720.       break;
  3721.   }
  3722.  
  3723.   CheckTriggeredElementChange(x, y, element, CE_OTHER_IS_EXPLODING);
  3724. }
  3725.  
  3726. void SplashAcid(int x, int y)
  3727. {
  3728. #if 1
  3729.   if (IN_LEV_FIELD(x - 1, y - 1) && IS_FREE(x - 1, y - 1) &&
  3730.       (!IN_LEV_FIELD(x - 1, y - 2) ||
  3731.        !CAN_FALL(MovingOrBlocked2Element(x - 1, y - 2))))
  3732.     Feld[x - 1][y - 1] = EL_ACID_SPLASH_LEFT;
  3733.  
  3734.   if (IN_LEV_FIELD(x + 1, y - 1) && IS_FREE(x + 1, y - 1) &&
  3735.       (!IN_LEV_FIELD(x + 1, y - 2) ||
  3736.        !CAN_FALL(MovingOrBlocked2Element(x + 1, y - 2))))
  3737.     Feld[x + 1][y - 1] = EL_ACID_SPLASH_RIGHT;
  3738.  
  3739.   PlayLevelSound(x, y, SND_ACID_SPLASHING);
  3740. #else
  3741.   /* input: position of element entering acid (obsolete) */
  3742.  
  3743.   int element = Feld[x][y];
  3744.  
  3745.   if (!IN_LEV_FIELD(x, y + 1) || Feld[x][y + 1] != EL_ACID)
  3746.     return;
  3747.  
  3748.   if (element != EL_ACID_SPLASH_LEFT &&
  3749.       element != EL_ACID_SPLASH_RIGHT)
  3750.   {
  3751.     PlayLevelSound(x, y, SND_ACID_SPLASHING);
  3752.  
  3753.     if (IN_LEV_FIELD(x - 1, y) && IS_FREE(x - 1, y) &&
  3754.     (!IN_LEV_FIELD(x - 1, y - 1) ||
  3755.      !CAN_FALL(MovingOrBlocked2Element(x - 1, y - 1))))
  3756.       Feld[x - 1][y] = EL_ACID_SPLASH_LEFT;
  3757.  
  3758.     if (IN_LEV_FIELD(x + 1, y) && IS_FREE(x + 1, y) &&
  3759.     (!IN_LEV_FIELD(x + 1, y - 1) ||
  3760.      !CAN_FALL(MovingOrBlocked2Element(x + 1, y - 1))))
  3761.       Feld[x + 1][y] = EL_ACID_SPLASH_RIGHT;
  3762.   }
  3763. #endif
  3764. }
  3765.  
  3766. static void InitBeltMovement()
  3767. {
  3768.   static int belt_base_element[4] =
  3769.   {
  3770.     EL_CONVEYOR_BELT_1_LEFT,
  3771.     EL_CONVEYOR_BELT_2_LEFT,
  3772.     EL_CONVEYOR_BELT_3_LEFT,
  3773.     EL_CONVEYOR_BELT_4_LEFT
  3774.   };
  3775.   static int belt_base_active_element[4] =
  3776.   {
  3777.     EL_CONVEYOR_BELT_1_LEFT_ACTIVE,
  3778.     EL_CONVEYOR_BELT_2_LEFT_ACTIVE,
  3779.     EL_CONVEYOR_BELT_3_LEFT_ACTIVE,
  3780.     EL_CONVEYOR_BELT_4_LEFT_ACTIVE
  3781.   };
  3782.  
  3783.   int x, y, i, j;
  3784.  
  3785.   /* set frame order for belt animation graphic according to belt direction */
  3786.   for (i = 0; i < NUM_BELTS; i++)
  3787.   {
  3788.     int belt_nr = i;
  3789.  
  3790.     for (j = 0; j < NUM_BELT_PARTS; j++)
  3791.     {
  3792.       int element = belt_base_active_element[belt_nr] + j;
  3793.       int graphic = el2img(element);
  3794.  
  3795.       if (game.belt_dir[i] == MV_LEFT)
  3796.     graphic_info[graphic].anim_mode &= ~ANIM_REVERSE;
  3797.       else
  3798.     graphic_info[graphic].anim_mode |=  ANIM_REVERSE;
  3799.     }
  3800.   }
  3801.  
  3802.   for (y = 0; y < lev_fieldy; y++)
  3803.   {
  3804.     for (x = 0; x < lev_fieldx; x++)
  3805.     {
  3806.       int element = Feld[x][y];
  3807.  
  3808.       for (i = 0; i < NUM_BELTS; i++)
  3809.       {
  3810.     if (IS_BELT(element) && game.belt_dir[i] != MV_NO_MOVING)
  3811.     {
  3812.       int e_belt_nr = getBeltNrFromBeltElement(element);
  3813.       int belt_nr = i;
  3814.  
  3815.       if (e_belt_nr == belt_nr)
  3816.       {
  3817.         int belt_part = Feld[x][y] - belt_base_element[belt_nr];
  3818.  
  3819.         Feld[x][y] = belt_base_active_element[belt_nr] + belt_part;
  3820.       }
  3821.     }
  3822.       }
  3823.     }
  3824.   }
  3825. }
  3826.  
  3827. static void ToggleBeltSwitch(int x, int y)
  3828. {
  3829.   static int belt_base_element[4] =
  3830.   {
  3831.     EL_CONVEYOR_BELT_1_LEFT,
  3832.     EL_CONVEYOR_BELT_2_LEFT,
  3833.     EL_CONVEYOR_BELT_3_LEFT,
  3834.     EL_CONVEYOR_BELT_4_LEFT
  3835.   };
  3836.   static int belt_base_active_element[4] =
  3837.   {
  3838.     EL_CONVEYOR_BELT_1_LEFT_ACTIVE,
  3839.     EL_CONVEYOR_BELT_2_LEFT_ACTIVE,
  3840.     EL_CONVEYOR_BELT_3_LEFT_ACTIVE,
  3841.     EL_CONVEYOR_BELT_4_LEFT_ACTIVE
  3842.   };
  3843.   static int belt_base_switch_element[4] =
  3844.   {
  3845.     EL_CONVEYOR_BELT_1_SWITCH_LEFT,
  3846.     EL_CONVEYOR_BELT_2_SWITCH_LEFT,
  3847.     EL_CONVEYOR_BELT_3_SWITCH_LEFT,
  3848.     EL_CONVEYOR_BELT_4_SWITCH_LEFT
  3849.   };
  3850.   static int belt_move_dir[4] =
  3851.   {
  3852.     MV_LEFT,
  3853.     MV_NO_MOVING,
  3854.     MV_RIGHT,
  3855.     MV_NO_MOVING,
  3856.   };
  3857.  
  3858.   int element = Feld[x][y];
  3859.   int belt_nr = getBeltNrFromBeltSwitchElement(element);
  3860.   int belt_dir_nr = (game.belt_dir_nr[belt_nr] + 1) % 4;
  3861.   int belt_dir = belt_move_dir[belt_dir_nr];
  3862.   int xx, yy, i;
  3863.  
  3864.   if (!IS_BELT_SWITCH(element))
  3865.     return;
  3866.  
  3867.   game.belt_dir_nr[belt_nr] = belt_dir_nr;
  3868.   game.belt_dir[belt_nr] = belt_dir;
  3869.  
  3870.   if (belt_dir_nr == 3)
  3871.     belt_dir_nr = 1;
  3872.  
  3873.   /* set frame order for belt animation graphic according to belt direction */
  3874.   for (i = 0; i < NUM_BELT_PARTS; i++)
  3875.   {
  3876.     int element = belt_base_active_element[belt_nr] + i;
  3877.     int graphic = el2img(element);
  3878.  
  3879.     if (belt_dir == MV_LEFT)
  3880.       graphic_info[graphic].anim_mode &= ~ANIM_REVERSE;
  3881.     else
  3882.       graphic_info[graphic].anim_mode |=  ANIM_REVERSE;
  3883.   }
  3884.  
  3885.   for (yy = 0; yy < lev_fieldy; yy++)
  3886.   {
  3887.     for (xx = 0; xx < lev_fieldx; xx++)
  3888.     {
  3889.       int element = Feld[xx][yy];
  3890.  
  3891.       if (IS_BELT_SWITCH(element))
  3892.       {
  3893.     int e_belt_nr = getBeltNrFromBeltSwitchElement(element);
  3894.  
  3895.     if (e_belt_nr == belt_nr)
  3896.     {
  3897.       Feld[xx][yy] = belt_base_switch_element[belt_nr] + belt_dir_nr;
  3898.       DrawLevelField(xx, yy);
  3899.     }
  3900.       }
  3901.       else if (IS_BELT(element) && belt_dir != MV_NO_MOVING)
  3902.       {
  3903.     int e_belt_nr = getBeltNrFromBeltElement(element);
  3904.  
  3905.     if (e_belt_nr == belt_nr)
  3906.     {
  3907.       int belt_part = Feld[xx][yy] - belt_base_element[belt_nr];
  3908.  
  3909.       Feld[xx][yy] = belt_base_active_element[belt_nr] + belt_part;
  3910.       DrawLevelField(xx, yy);
  3911.     }
  3912.       }
  3913.       else if (IS_BELT_ACTIVE(element) && belt_dir == MV_NO_MOVING)
  3914.       {
  3915.     int e_belt_nr = getBeltNrFromBeltActiveElement(element);
  3916.  
  3917.     if (e_belt_nr == belt_nr)
  3918.     {
  3919.       int belt_part = Feld[xx][yy] - belt_base_active_element[belt_nr];
  3920.  
  3921.       Feld[xx][yy] = belt_base_element[belt_nr] + belt_part;
  3922.       DrawLevelField(xx, yy);
  3923.     }
  3924.       }
  3925.     }
  3926.   }
  3927. }
  3928.  
  3929. static void ToggleSwitchgateSwitch(int x, int y)
  3930. {
  3931.   int xx, yy;
  3932.  
  3933.   game.switchgate_pos = !game.switchgate_pos;
  3934.  
  3935.   for (yy = 0; yy < lev_fieldy; yy++)
  3936.   {
  3937.     for (xx = 0; xx < lev_fieldx; xx++)
  3938.     {
  3939.       int element = Feld[xx][yy];
  3940.  
  3941.       if (element == EL_SWITCHGATE_SWITCH_UP ||
  3942.       element == EL_SWITCHGATE_SWITCH_DOWN)
  3943.       {
  3944.     Feld[xx][yy] = EL_SWITCHGATE_SWITCH_UP + game.switchgate_pos;
  3945.     DrawLevelField(xx, yy);
  3946.       }
  3947.       else if (element == EL_SWITCHGATE_OPEN ||
  3948.            element == EL_SWITCHGATE_OPENING)
  3949.       {
  3950.     Feld[xx][yy] = EL_SWITCHGATE_CLOSING;
  3951. #if 1
  3952.     PlayLevelSoundAction(xx, yy, ACTION_CLOSING);
  3953. #else
  3954.     PlayLevelSound(xx, yy, SND_SWITCHGATE_CLOSING);
  3955. #endif
  3956.       }
  3957.       else if (element == EL_SWITCHGATE_CLOSED ||
  3958.            element == EL_SWITCHGATE_CLOSING)
  3959.       {
  3960.     Feld[xx][yy] = EL_SWITCHGATE_OPENING;
  3961. #if 1
  3962.     PlayLevelSoundAction(xx, yy, ACTION_OPENING);
  3963. #else
  3964.     PlayLevelSound(xx, yy, SND_SWITCHGATE_OPENING);
  3965. #endif
  3966.       }
  3967.     }
  3968.   }
  3969. }
  3970.  
  3971. static int getInvisibleActiveFromInvisibleElement(int element)
  3972. {
  3973.   return (element == EL_INVISIBLE_STEELWALL ? EL_INVISIBLE_STEELWALL_ACTIVE :
  3974.       element == EL_INVISIBLE_WALL      ? EL_INVISIBLE_WALL_ACTIVE :
  3975.       element == EL_INVISIBLE_SAND      ? EL_INVISIBLE_SAND_ACTIVE :
  3976.       element);
  3977. }
  3978.  
  3979. static int getInvisibleFromInvisibleActiveElement(int element)
  3980. {
  3981.   return (element == EL_INVISIBLE_STEELWALL_ACTIVE ? EL_INVISIBLE_STEELWALL :
  3982.       element == EL_INVISIBLE_WALL_ACTIVE      ? EL_INVISIBLE_WALL :
  3983.       element == EL_INVISIBLE_SAND_ACTIVE      ? EL_INVISIBLE_SAND :
  3984.       element);
  3985. }
  3986.  
  3987. static void RedrawAllLightSwitchesAndInvisibleElements()
  3988. {
  3989.   int x, y;
  3990.  
  3991.   for (y = 0; y < lev_fieldy; y++)
  3992.   {
  3993.     for (x = 0; x < lev_fieldx; x++)
  3994.     {
  3995.       int element = Feld[x][y];
  3996.  
  3997.       if (element == EL_LIGHT_SWITCH &&
  3998.       game.light_time_left > 0)
  3999.       {
  4000.     Feld[x][y] = EL_LIGHT_SWITCH_ACTIVE;
  4001.     DrawLevelField(x, y);
  4002.       }
  4003.       else if (element == EL_LIGHT_SWITCH_ACTIVE &&
  4004.            game.light_time_left == 0)
  4005.       {
  4006.     Feld[x][y] = EL_LIGHT_SWITCH;
  4007.     DrawLevelField(x, y);
  4008.       }
  4009.       else if (element == EL_INVISIBLE_STEELWALL ||
  4010.            element == EL_INVISIBLE_WALL ||
  4011.            element == EL_INVISIBLE_SAND)
  4012.       {
  4013.     if (game.light_time_left > 0)
  4014.       Feld[x][y] = getInvisibleActiveFromInvisibleElement(element);
  4015.  
  4016.     DrawLevelField(x, y);
  4017.       }
  4018.       else if (element == EL_INVISIBLE_STEELWALL_ACTIVE ||
  4019.            element == EL_INVISIBLE_WALL_ACTIVE ||
  4020.            element == EL_INVISIBLE_SAND_ACTIVE)
  4021.       {
  4022.     if (game.light_time_left == 0)
  4023.       Feld[x][y] = getInvisibleFromInvisibleActiveElement(element);
  4024.  
  4025.     DrawLevelField(x, y);
  4026.       }
  4027.     }
  4028.   }
  4029. }
  4030.  
  4031. static void ToggleLightSwitch(int x, int y)
  4032. {
  4033.   int element = Feld[x][y];
  4034.  
  4035.   game.light_time_left =
  4036.     (element == EL_LIGHT_SWITCH ?
  4037.      level.time_light * FRAMES_PER_SECOND : 0);
  4038.  
  4039.   RedrawAllLightSwitchesAndInvisibleElements();
  4040. }
  4041.  
  4042. static void ActivateTimegateSwitch(int x, int y)
  4043. {
  4044.   int xx, yy;
  4045.  
  4046.   game.timegate_time_left = level.time_timegate * FRAMES_PER_SECOND;
  4047.  
  4048.   for (yy = 0; yy < lev_fieldy; yy++)
  4049.   {
  4050.     for (xx = 0; xx < lev_fieldx; xx++)
  4051.     {
  4052.       int element = Feld[xx][yy];
  4053.  
  4054.       if (element == EL_TIMEGATE_CLOSED ||
  4055.       element == EL_TIMEGATE_CLOSING)
  4056.       {
  4057.     Feld[xx][yy] = EL_TIMEGATE_OPENING;
  4058.     PlayLevelSound(xx, yy, SND_TIMEGATE_OPENING);
  4059.       }
  4060.  
  4061.       /*
  4062.       else if (element == EL_TIMEGATE_SWITCH_ACTIVE)
  4063.       {
  4064.     Feld[xx][yy] = EL_TIMEGATE_SWITCH;
  4065.     DrawLevelField(xx, yy);
  4066.       }
  4067.       */
  4068.  
  4069.     }
  4070.   }
  4071.  
  4072.   Feld[x][y] = EL_TIMEGATE_SWITCH_ACTIVE;
  4073. }
  4074.  
  4075. inline static int getElementMoveStepsize(int x, int y)
  4076. {
  4077.   int element = Feld[x][y];
  4078.   int direction = MovDir[x][y];
  4079.   int dx = (direction == MV_LEFT ? -1 : direction == MV_RIGHT ? +1 : 0);
  4080.   int dy = (direction == MV_UP   ? -1 : direction == MV_DOWN  ? +1 : 0);
  4081.   int horiz_move = (dx != 0);
  4082.   int sign = (horiz_move ? dx : dy);
  4083.   int step = sign * element_info[element].move_stepsize;
  4084.  
  4085.   /* special values for move stepsize for spring and things on conveyor belt */
  4086.   if (horiz_move)
  4087.   {
  4088. #if 0
  4089.     if (element == EL_SPRING)
  4090.       step = sign * MOVE_STEPSIZE_NORMAL * 2;
  4091.     else if (CAN_FALL(element) && !CAN_MOVE(element) &&
  4092.          y < lev_fieldy - 1 && IS_BELT_ACTIVE(Feld[x][y + 1]))
  4093.       step = sign * MOVE_STEPSIZE_NORMAL / 2;
  4094. #else
  4095.     if (CAN_FALL(element) &&
  4096.     y < lev_fieldy - 1 && IS_BELT_ACTIVE(Feld[x][y + 1]))
  4097.       step = sign * MOVE_STEPSIZE_NORMAL / 2;
  4098.     else if (element == EL_SPRING)
  4099.       step = sign * MOVE_STEPSIZE_NORMAL * 2;
  4100. #endif
  4101.   }
  4102.  
  4103.   return step;
  4104. }
  4105.  
  4106. void Impact(int x, int y)
  4107. {
  4108.   boolean lastline = (y == lev_fieldy-1);
  4109.   boolean object_hit = FALSE;
  4110.   boolean impact = (lastline || object_hit);
  4111.   int element = Feld[x][y];
  4112.   int smashed = EL_STEELWALL;
  4113.  
  4114.   if (!lastline)    /* check if element below was hit */
  4115.   {
  4116.     if (Feld[x][y + 1] == EL_PLAYER_IS_LEAVING)
  4117.       return;
  4118.  
  4119.     object_hit = (!IS_FREE(x, y + 1) && (!IS_MOVING(x, y + 1) ||
  4120.                      MovDir[x][y + 1] != MV_DOWN ||
  4121.                      MovPos[x][y + 1] <= TILEY / 2));
  4122.  
  4123. #if 0
  4124.     object_hit = !IS_FREE(x, y + 1);
  4125. #endif
  4126.  
  4127.     /* do not smash moving elements that left the smashed field in time */
  4128.     if (game.engine_version >= VERSION_IDENT(2,2,0,7) && IS_MOVING(x, y + 1) &&
  4129.     ABS(MovPos[x][y + 1] + getElementMoveStepsize(x, y + 1)) >= TILEX)
  4130.       object_hit = FALSE;
  4131.  
  4132.     if (object_hit)
  4133.       smashed = MovingOrBlocked2Element(x, y + 1);
  4134.  
  4135.     impact = (lastline || object_hit);
  4136.   }
  4137.  
  4138.   if (!lastline && smashed == EL_ACID)    /* element falls into acid */
  4139.   {
  4140.     SplashAcid(x, y + 1);
  4141.     return;
  4142.   }
  4143.  
  4144.   /* !!! not sufficient for all cases -- see EL_PEARL below !!! */
  4145.   /* only reset graphic animation if graphic really changes after impact */
  4146.   if (impact &&
  4147.       el_act_dir2img(element, GfxAction[x][y], MV_DOWN) != el2img(element))
  4148.   {
  4149.     ResetGfxAnimation(x, y);
  4150.     DrawLevelField(x, y);
  4151.   }
  4152.  
  4153.   if (impact && CAN_EXPLODE_IMPACT(element))
  4154.   {
  4155.     Bang(x, y);
  4156.     return;
  4157.   }
  4158.   else if (impact && element == EL_PEARL)
  4159.   {
  4160.     ResetGfxAnimation(x, y);
  4161.  
  4162.     Feld[x][y] = EL_PEARL_BREAKING;
  4163.     PlayLevelSound(x, y, SND_PEARL_BREAKING);
  4164.     return;
  4165.   }
  4166.   else if (impact && CheckElementChange(x, y, element, smashed, CE_IMPACT))
  4167.   {
  4168.     PlayLevelSoundElementAction(x, y, element, ACTION_IMPACT);
  4169.  
  4170.     return;
  4171.   }
  4172.  
  4173.   if (impact && element == EL_AMOEBA_DROP)
  4174.   {
  4175.     if (object_hit && IS_PLAYER(x, y + 1))
  4176.       KillHeroUnlessEnemyProtected(x, y + 1);
  4177.     else if (object_hit && smashed == EL_PENGUIN)
  4178.       Bang(x, y + 1);
  4179.     else
  4180.     {
  4181.       Feld[x][y] = EL_AMOEBA_GROWING;
  4182.       Store[x][y] = EL_AMOEBA_WET;
  4183.  
  4184.       ResetRandomAnimationValue(x, y);
  4185.     }
  4186.     return;
  4187.   }
  4188.  
  4189.   if (object_hit)        /* check which object was hit */
  4190.   {
  4191.     if (CAN_PASS_MAGIC_WALL(element) && 
  4192.     (smashed == EL_MAGIC_WALL ||
  4193.      smashed == EL_BD_MAGIC_WALL))
  4194.     {
  4195.       int xx, yy;
  4196.       int activated_magic_wall =
  4197.     (smashed == EL_MAGIC_WALL ? EL_MAGIC_WALL_ACTIVE :
  4198.      EL_BD_MAGIC_WALL_ACTIVE);
  4199.  
  4200.       /* activate magic wall / mill */
  4201.       for (yy = 0; yy < lev_fieldy; yy++)
  4202.     for (xx = 0; xx < lev_fieldx; xx++)
  4203.       if (Feld[xx][yy] == smashed)
  4204.         Feld[xx][yy] = activated_magic_wall;
  4205.  
  4206.       game.magic_wall_time_left = level.time_magic_wall * FRAMES_PER_SECOND;
  4207.       game.magic_wall_active = TRUE;
  4208.  
  4209.       PlayLevelSound(x, y, (smashed == EL_MAGIC_WALL ?
  4210.                 SND_MAGIC_WALL_ACTIVATING :
  4211.                 SND_BD_MAGIC_WALL_ACTIVATING));
  4212.     }
  4213.  
  4214.     if (IS_PLAYER(x, y + 1))
  4215.     {
  4216.       if (CAN_SMASH_PLAYER(element))
  4217.       {
  4218.     KillHeroUnlessEnemyProtected(x, y + 1);
  4219.     return;
  4220.       }
  4221.     }
  4222.     else if (smashed == EL_PENGUIN)
  4223.     {
  4224.       if (CAN_SMASH_PLAYER(element))
  4225.       {
  4226.     Bang(x, y + 1);
  4227.     return;
  4228.       }
  4229.     }
  4230.     else if (element == EL_BD_DIAMOND)
  4231.     {
  4232.       if (IS_CLASSIC_ENEMY(smashed) && IS_BD_ELEMENT(smashed))
  4233.       {
  4234.     Bang(x, y + 1);
  4235.     return;
  4236.       }
  4237.     }
  4238.     else if (((element == EL_SP_INFOTRON ||
  4239.            element == EL_SP_ZONK) &&
  4240.           (smashed == EL_SP_SNIKSNAK ||
  4241.            smashed == EL_SP_ELECTRON ||
  4242.            smashed == EL_SP_DISK_ORANGE)) ||
  4243.          (element == EL_SP_INFOTRON &&
  4244.           smashed == EL_SP_DISK_YELLOW))
  4245.     {
  4246.       Bang(x, y + 1);
  4247.       return;
  4248.     }
  4249. #if 0
  4250.     else if (CAN_SMASH_ENEMIES(element) && IS_CLASSIC_ENEMY(smashed))
  4251.     {
  4252.       Bang(x, y + 1);
  4253.       return;
  4254.     }
  4255. #endif
  4256.     else if (CAN_SMASH_EVERYTHING(element))
  4257.     {
  4258.       if (IS_CLASSIC_ENEMY(smashed) ||
  4259.       CAN_EXPLODE_SMASHED(smashed))
  4260.       {
  4261.     Bang(x, y + 1);
  4262.     return;
  4263.       }
  4264.       else if (!IS_MOVING(x, y + 1) && !IS_BLOCKED(x, y + 1))
  4265.       {
  4266.     if (smashed == EL_LAMP ||
  4267.         smashed == EL_LAMP_ACTIVE)
  4268.     {
  4269.       Bang(x, y + 1);
  4270.       return;
  4271.     }
  4272.     else if (smashed == EL_NUT)
  4273.     {
  4274.       Feld[x][y + 1] = EL_NUT_BREAKING;
  4275.       PlayLevelSound(x, y, SND_NUT_BREAKING);
  4276.       RaiseScoreElement(EL_NUT);
  4277.       return;
  4278.     }
  4279.     else if (smashed == EL_PEARL)
  4280.     {
  4281.       ResetGfxAnimation(x, y);
  4282.  
  4283.       Feld[x][y + 1] = EL_PEARL_BREAKING;
  4284.       PlayLevelSound(x, y, SND_PEARL_BREAKING);
  4285.       return;
  4286.     }
  4287.     else if (smashed == EL_DIAMOND)
  4288.     {
  4289.       Feld[x][y + 1] = EL_DIAMOND_BREAKING;
  4290.       PlayLevelSound(x, y, SND_DIAMOND_BREAKING);
  4291.       return;
  4292.     }
  4293.     else if (IS_BELT_SWITCH(smashed))
  4294.     {
  4295.       ToggleBeltSwitch(x, y + 1);
  4296.     }
  4297.     else if (smashed == EL_SWITCHGATE_SWITCH_UP ||
  4298.          smashed == EL_SWITCHGATE_SWITCH_DOWN)
  4299.     {
  4300.       ToggleSwitchgateSwitch(x, y + 1);
  4301.     }
  4302.     else if (smashed == EL_LIGHT_SWITCH ||
  4303.          smashed == EL_LIGHT_SWITCH_ACTIVE)
  4304.     {
  4305.       ToggleLightSwitch(x, y + 1);
  4306.     }
  4307.     else
  4308.     {
  4309. #if 0
  4310.       TestIfElementSmashesCustomElement(x, y, MV_DOWN);
  4311. #endif
  4312.  
  4313.       CheckElementChange(x, y + 1, smashed, element, CE_SMASHED);
  4314.  
  4315. #if 1
  4316.       /* !!! TEST ONLY !!! */
  4317.       CheckElementChangeBySide(x, y + 1, smashed, element,
  4318.                    CE_SWITCHED, CH_SIDE_TOP);
  4319.       CheckTriggeredElementChangeBySide(x, y + 1, smashed,
  4320.                         CE_OTHER_IS_SWITCHING,CH_SIDE_TOP);
  4321. #else
  4322.       CheckTriggeredElementChangeBySide(x, y + 1, smashed,
  4323.                         CE_OTHER_IS_SWITCHING,CH_SIDE_TOP);
  4324.       CheckElementChangeBySide(x, y + 1, smashed, element,
  4325.                    CE_SWITCHED, CH_SIDE_TOP);
  4326. #endif
  4327.     }
  4328.       }
  4329.       else
  4330.       {
  4331.     CheckElementChange(x, y + 1, smashed, element, CE_SMASHED);
  4332.       }
  4333.     }
  4334.   }
  4335.  
  4336.   /* play sound of magic wall / mill */
  4337.   if (!lastline &&
  4338.       (Feld[x][y + 1] == EL_MAGIC_WALL_ACTIVE ||
  4339.        Feld[x][y + 1] == EL_BD_MAGIC_WALL_ACTIVE))
  4340.   {
  4341.     if (Feld[x][y + 1] == EL_MAGIC_WALL_ACTIVE)
  4342.       PlayLevelSound(x, y, SND_MAGIC_WALL_FILLING);
  4343.     else if (Feld[x][y + 1] == EL_BD_MAGIC_WALL_ACTIVE)
  4344.       PlayLevelSound(x, y, SND_BD_MAGIC_WALL_FILLING);
  4345.  
  4346.     return;
  4347.   }
  4348.  
  4349.   /* play sound of object that hits the ground */
  4350.   if (lastline || object_hit)
  4351.     PlayLevelSoundElementAction(x, y, element, ACTION_IMPACT);
  4352. }
  4353.  
  4354. inline static void TurnRoundExt(int x, int y)
  4355. {
  4356.   static struct
  4357.   {
  4358.     int x, y;
  4359.   } move_xy[] =
  4360.   {
  4361.     {  0,  0 },
  4362.     { -1,  0 },
  4363.     { +1,  0 },
  4364.     {  0,  0 },
  4365.     {  0, -1 },
  4366.     {  0,  0 }, { 0, 0 }, { 0, 0 },
  4367.     {  0, +1 }
  4368.   };
  4369.   static struct
  4370.   {
  4371.     int left, right, back;
  4372.   } turn[] =
  4373.   {
  4374.     { 0,    0,        0     },
  4375.     { MV_DOWN,    MV_UP,        MV_RIGHT },
  4376.     { MV_UP,    MV_DOWN,    MV_LEFT     },
  4377.     { 0,    0,        0     },
  4378.     { MV_LEFT,    MV_RIGHT,    MV_DOWN     },
  4379.     { 0,    0,        0     },
  4380.     { 0,    0,        0     },
  4381.     { 0,    0,        0     },
  4382.     { MV_RIGHT,    MV_LEFT,    MV_UP     }
  4383.   };
  4384.  
  4385.   int element = Feld[x][y];
  4386.   int move_pattern = element_info[element].move_pattern;
  4387.  
  4388.   int old_move_dir = MovDir[x][y];
  4389.   int left_dir  = turn[old_move_dir].left;
  4390.   int right_dir = turn[old_move_dir].right;
  4391.   int back_dir  = turn[old_move_dir].back;
  4392.  
  4393.   int left_dx  = move_xy[left_dir].x,     left_dy  = move_xy[left_dir].y;
  4394.   int right_dx = move_xy[right_dir].x,    right_dy = move_xy[right_dir].y;
  4395.   int move_dx  = move_xy[old_move_dir].x, move_dy  = move_xy[old_move_dir].y;
  4396.   int back_dx  = move_xy[back_dir].x,     back_dy  = move_xy[back_dir].y;
  4397.  
  4398.   int left_x  = x + left_dx,  left_y  = y + left_dy;
  4399.   int right_x = x + right_dx, right_y = y + right_dy;
  4400.   int move_x  = x + move_dx,  move_y  = y + move_dy;
  4401.  
  4402.   int xx, yy;
  4403.  
  4404.   if (element == EL_BUG || element == EL_BD_BUTTERFLY)
  4405.   {
  4406.     TestIfBadThingTouchesOtherBadThing(x, y);
  4407.  
  4408.     if (ENEMY_CAN_ENTER_FIELD(element, right_x, right_y))
  4409.       MovDir[x][y] = right_dir;
  4410.     else if (!ENEMY_CAN_ENTER_FIELD(element, move_x, move_y))
  4411.       MovDir[x][y] = left_dir;
  4412.  
  4413.     if (element == EL_BUG && MovDir[x][y] != old_move_dir)
  4414.       MovDelay[x][y] = 9;
  4415.     else if (element == EL_BD_BUTTERFLY)     /* && MovDir[x][y] == left_dir) */
  4416.       MovDelay[x][y] = 1;
  4417.   }
  4418. #if 0
  4419.   else if (element == EL_SPACESHIP || element == EL_BD_FIREFLY ||
  4420.        element == EL_SP_SNIKSNAK || element == EL_SP_ELECTRON)
  4421.   {
  4422.     TestIfBadThingTouchesOtherBadThing(x, y);
  4423.  
  4424.     if (ENEMY_CAN_ENTER_FIELD(element, left_x, left_y))
  4425.       MovDir[x][y] = left_dir;
  4426.     else if (!ENEMY_CAN_ENTER_FIELD(element, move_x, move_y))
  4427.       MovDir[x][y] = right_dir;
  4428.  
  4429.     if ((element == EL_SPACESHIP ||
  4430.      element == EL_SP_SNIKSNAK ||
  4431.      element == EL_SP_ELECTRON)
  4432.     && MovDir[x][y] != old_move_dir)
  4433.       MovDelay[x][y] = 9;
  4434.     else if (element == EL_BD_FIREFLY)        /* && MovDir[x][y] == right_dir) */
  4435.       MovDelay[x][y] = 1;
  4436.   }
  4437. #else
  4438.   else if (element == EL_SPACESHIP || element == EL_BD_FIREFLY)
  4439.   {
  4440.     TestIfBadThingTouchesOtherBadThing(x, y);
  4441.  
  4442.     if (ENEMY_CAN_ENTER_FIELD(element, left_x, left_y))
  4443.       MovDir[x][y] = left_dir;
  4444.     else if (!ENEMY_CAN_ENTER_FIELD(element, move_x, move_y))
  4445.       MovDir[x][y] = right_dir;
  4446.  
  4447.     if (element == EL_SPACESHIP    && MovDir[x][y] != old_move_dir)
  4448.       MovDelay[x][y] = 9;
  4449.     else if (element == EL_BD_FIREFLY)        /* && MovDir[x][y] == right_dir) */
  4450.       MovDelay[x][y] = 1;
  4451.   }
  4452.   else if (element == EL_SP_SNIKSNAK || element == EL_SP_ELECTRON)
  4453.   {
  4454.     TestIfBadThingTouchesOtherBadThing(x, y);
  4455.  
  4456.     if (ELEMENT_CAN_ENTER_FIELD_BASE_4(element, left_x, left_y, 0))
  4457.       MovDir[x][y] = left_dir;
  4458.     else if (!ELEMENT_CAN_ENTER_FIELD_BASE_4(element, move_x, move_y, 0))
  4459.       MovDir[x][y] = right_dir;
  4460.  
  4461.     if (MovDir[x][y] != old_move_dir)
  4462.       MovDelay[x][y] = 9;
  4463.   }
  4464. #endif
  4465.   else if (element == EL_YAMYAM)
  4466.   {
  4467.     boolean can_turn_left  = YAMYAM_CAN_ENTER_FIELD(element, left_x, left_y);
  4468.     boolean can_turn_right = YAMYAM_CAN_ENTER_FIELD(element, right_x, right_y);
  4469.  
  4470.     if (can_turn_left && can_turn_right)
  4471.       MovDir[x][y] = (RND(3) ? (RND(2) ? left_dir : right_dir) : back_dir);
  4472.     else if (can_turn_left)
  4473.       MovDir[x][y] = (RND(2) ? left_dir : back_dir);
  4474.     else if (can_turn_right)
  4475.       MovDir[x][y] = (RND(2) ? right_dir : back_dir);
  4476.     else
  4477.       MovDir[x][y] = back_dir;
  4478.  
  4479.     MovDelay[x][y] = 16 + 16 * RND(3);
  4480.   }
  4481.   else if (element == EL_DARK_YAMYAM)
  4482.   {
  4483.     boolean can_turn_left  = DARK_YAMYAM_CAN_ENTER_FIELD(element,
  4484.                              left_x, left_y);
  4485.     boolean can_turn_right = DARK_YAMYAM_CAN_ENTER_FIELD(element,
  4486.                              right_x, right_y);
  4487.  
  4488.     if (can_turn_left && can_turn_right)
  4489.       MovDir[x][y] = (RND(3) ? (RND(2) ? left_dir : right_dir) : back_dir);
  4490.     else if (can_turn_left)
  4491.       MovDir[x][y] = (RND(2) ? left_dir : back_dir);
  4492.     else if (can_turn_right)
  4493.       MovDir[x][y] = (RND(2) ? right_dir : back_dir);
  4494.     else
  4495.       MovDir[x][y] = back_dir;
  4496.  
  4497.     MovDelay[x][y] = 16 + 16 * RND(3);
  4498.   }
  4499.   else if (element == EL_PACMAN)
  4500.   {
  4501.     boolean can_turn_left  = PACMAN_CAN_ENTER_FIELD(element, left_x, left_y);
  4502.     boolean can_turn_right = PACMAN_CAN_ENTER_FIELD(element, right_x, right_y);
  4503.  
  4504.     if (can_turn_left && can_turn_right)
  4505.       MovDir[x][y] = (RND(3) ? (RND(2) ? left_dir : right_dir) : back_dir);
  4506.     else if (can_turn_left)
  4507.       MovDir[x][y] = (RND(2) ? left_dir : back_dir);
  4508.     else if (can_turn_right)
  4509.       MovDir[x][y] = (RND(2) ? right_dir : back_dir);
  4510.     else
  4511.       MovDir[x][y] = back_dir;
  4512.  
  4513.     MovDelay[x][y] = 6 + RND(40);
  4514.   }
  4515.   else if (element == EL_PIG)
  4516.   {
  4517.     boolean can_turn_left  = PIG_CAN_ENTER_FIELD(element, left_x, left_y);
  4518.     boolean can_turn_right = PIG_CAN_ENTER_FIELD(element, right_x, right_y);
  4519.     boolean can_move_on    = PIG_CAN_ENTER_FIELD(element, move_x, move_y);
  4520.     boolean should_turn_left, should_turn_right, should_move_on;
  4521.     int rnd_value = 24;
  4522.     int rnd = RND(rnd_value);
  4523.  
  4524.     should_turn_left = (can_turn_left &&
  4525.             (!can_move_on ||
  4526.              IN_LEV_FIELD_AND_NOT_FREE(x + back_dx + left_dx,
  4527.                            y + back_dy + left_dy)));
  4528.     should_turn_right = (can_turn_right &&
  4529.              (!can_move_on ||
  4530.               IN_LEV_FIELD_AND_NOT_FREE(x + back_dx + right_dx,
  4531.                             y + back_dy + right_dy)));
  4532.     should_move_on = (can_move_on &&
  4533.               (!can_turn_left ||
  4534.                !can_turn_right ||
  4535.                IN_LEV_FIELD_AND_NOT_FREE(x + move_dx + left_dx,
  4536.                          y + move_dy + left_dy) ||
  4537.                IN_LEV_FIELD_AND_NOT_FREE(x + move_dx + right_dx,
  4538.                          y + move_dy + right_dy)));
  4539.  
  4540.     if (should_turn_left || should_turn_right || should_move_on)
  4541.     {
  4542.       if (should_turn_left && should_turn_right && should_move_on)
  4543.     MovDir[x][y] = (rnd < rnd_value / 3     ? left_dir :
  4544.             rnd < 2 * rnd_value / 3 ? right_dir :
  4545.             old_move_dir);
  4546.       else if (should_turn_left && should_turn_right)
  4547.     MovDir[x][y] = (rnd < rnd_value / 2 ? left_dir : right_dir);
  4548.       else if (should_turn_left && should_move_on)
  4549.     MovDir[x][y] = (rnd < rnd_value / 2 ? left_dir : old_move_dir);
  4550.       else if (should_turn_right && should_move_on)
  4551.     MovDir[x][y] = (rnd < rnd_value / 2 ? right_dir : old_move_dir);
  4552.       else if (should_turn_left)
  4553.     MovDir[x][y] = left_dir;
  4554.       else if (should_turn_right)
  4555.     MovDir[x][y] = right_dir;
  4556.       else if (should_move_on)
  4557.     MovDir[x][y] = old_move_dir;
  4558.     }
  4559.     else if (can_move_on && rnd > rnd_value / 8)
  4560.       MovDir[x][y] = old_move_dir;
  4561.     else if (can_turn_left && can_turn_right)
  4562.       MovDir[x][y] = (rnd < rnd_value / 2 ? left_dir : right_dir);
  4563.     else if (can_turn_left && rnd > rnd_value / 8)
  4564.       MovDir[x][y] = left_dir;
  4565.     else if (can_turn_right && rnd > rnd_value/8)
  4566.       MovDir[x][y] = right_dir;
  4567.     else
  4568.       MovDir[x][y] = back_dir;
  4569.  
  4570.     xx = x + move_xy[MovDir[x][y]].x;
  4571.     yy = y + move_xy[MovDir[x][y]].y;
  4572.  
  4573.     if (!IS_FREE(xx, yy) && !IS_FOOD_PIG(Feld[xx][yy]))
  4574.       MovDir[x][y] = old_move_dir;
  4575.  
  4576.     MovDelay[x][y] = 0;
  4577.   }
  4578.   else if (element == EL_DRAGON)
  4579.   {
  4580.     boolean can_turn_left  = DRAGON_CAN_ENTER_FIELD(element, left_x, left_y);
  4581.     boolean can_turn_right = DRAGON_CAN_ENTER_FIELD(element, right_x, right_y);
  4582.     boolean can_move_on    = DRAGON_CAN_ENTER_FIELD(element, move_x, move_y);
  4583.     int rnd_value = 24;
  4584.     int rnd = RND(rnd_value);
  4585.  
  4586. #if 0
  4587.     if (FrameCounter < 1 && x == 0 && y == 29)
  4588.       printf(":2: %d/%d: %d [%d]\n", x, y, MovDir[x][y], FrameCounter);
  4589. #endif
  4590.  
  4591.     if (can_move_on && rnd > rnd_value / 8)
  4592.       MovDir[x][y] = old_move_dir;
  4593.     else if (can_turn_left && can_turn_right)
  4594.       MovDir[x][y] = (rnd < rnd_value / 2 ? left_dir : right_dir);
  4595.     else if (can_turn_left && rnd > rnd_value / 8)
  4596.       MovDir[x][y] = left_dir;
  4597.     else if (can_turn_right && rnd > rnd_value / 8)
  4598.       MovDir[x][y] = right_dir;
  4599.     else
  4600.       MovDir[x][y] = back_dir;
  4601.  
  4602.     xx = x + move_xy[MovDir[x][y]].x;
  4603.     yy = y + move_xy[MovDir[x][y]].y;
  4604.  
  4605. #if 0
  4606.     if (FrameCounter < 1 && x == 0 && y == 29)
  4607.       printf(":3: %d/%d: %d (%d/%d: %d) [%d]\n", x, y, MovDir[x][y],
  4608.          xx, yy, Feld[xx][yy],
  4609.          FrameCounter);
  4610. #endif
  4611.  
  4612. #if 1
  4613.     if (!IN_LEV_FIELD_AND_IS_FREE(xx, yy))
  4614.       MovDir[x][y] = old_move_dir;
  4615. #else
  4616.     if (!IS_FREE(xx, yy))
  4617.       MovDir[x][y] = old_move_dir;
  4618. #endif
  4619.  
  4620. #if 0
  4621.     if (FrameCounter < 1 && x == 0 && y == 29)
  4622.       printf(":4: %d/%d: %d [%d]\n", x, y, MovDir[x][y], FrameCounter);
  4623. #endif
  4624.  
  4625.     MovDelay[x][y] = 0;
  4626.   }
  4627.   else if (element == EL_MOLE)
  4628.   {
  4629.     boolean can_move_on =
  4630.       (MOLE_CAN_ENTER_FIELD(element, move_x, move_y,
  4631.                 IS_AMOEBOID(Feld[move_x][move_y]) ||
  4632.                 Feld[move_x][move_y] == EL_AMOEBA_SHRINKING));
  4633.     if (!can_move_on)
  4634.     {
  4635.       boolean can_turn_left =
  4636.     (MOLE_CAN_ENTER_FIELD(element, left_x, left_y,
  4637.                   IS_AMOEBOID(Feld[left_x][left_y])));
  4638.  
  4639.       boolean can_turn_right =
  4640.     (MOLE_CAN_ENTER_FIELD(element, right_x, right_y,
  4641.                   IS_AMOEBOID(Feld[right_x][right_y])));
  4642.  
  4643.       if (can_turn_left && can_turn_right)
  4644.     MovDir[x][y] = (RND(2) ? left_dir : right_dir);
  4645.       else if (can_turn_left)
  4646.     MovDir[x][y] = left_dir;
  4647.       else
  4648.     MovDir[x][y] = right_dir;
  4649.     }
  4650.  
  4651.     if (MovDir[x][y] != old_move_dir)
  4652.       MovDelay[x][y] = 9;
  4653.   }
  4654.   else if (element == EL_BALLOON)
  4655.   {
  4656.     MovDir[x][y] = game.balloon_dir;
  4657.     MovDelay[x][y] = 0;
  4658.   }
  4659.   else if (element == EL_SPRING)
  4660.   {
  4661. #if 0
  4662.     if (MovDir[x][y] & MV_HORIZONTAL &&
  4663.     !SPRING_CAN_ENTER_FIELD(element, move_x, move_y))
  4664.       MovDir[x][y] = MV_NO_MOVING;
  4665. #else
  4666.     if (MovDir[x][y] & MV_HORIZONTAL &&
  4667.     (!SPRING_CAN_ENTER_FIELD(element, move_x, move_y) ||
  4668.      SPRING_CAN_ENTER_FIELD(element, x, y + 1)))
  4669.       MovDir[x][y] = MV_NO_MOVING;
  4670. #endif
  4671.  
  4672.     MovDelay[x][y] = 0;
  4673.   }
  4674.   else if (element == EL_ROBOT ||
  4675.        element == EL_SATELLITE ||
  4676.        element == EL_PENGUIN)
  4677.   {
  4678.     int attr_x = -1, attr_y = -1;
  4679.  
  4680.     if (AllPlayersGone)
  4681.     {
  4682.       attr_x = ExitX;
  4683.       attr_y = ExitY;
  4684.     }
  4685.     else
  4686.     {
  4687.       int i;
  4688.  
  4689.       for (i = 0; i < MAX_PLAYERS; i++)
  4690.       {
  4691.     struct PlayerInfo *player = &stored_player[i];
  4692.     int jx = player->jx, jy = player->jy;
  4693.  
  4694.     if (!player->active)
  4695.       continue;
  4696.  
  4697.     if (attr_x == -1 ||
  4698.         ABS(jx - x) + ABS(jy - y) < ABS(attr_x - x) + ABS(attr_y - y))
  4699.     {
  4700.       attr_x = jx;
  4701.       attr_y = jy;
  4702.     }
  4703.       }
  4704.     }
  4705.  
  4706. #if 1
  4707.     if (element == EL_ROBOT && ZX >= 0 && ZY >= 0 &&
  4708.     (Feld[ZX][ZY] == EL_ROBOT_WHEEL_ACTIVE ||
  4709.      game.engine_version < VERSION_IDENT(3,1,0,0)))
  4710. #else
  4711.     if (element == EL_ROBOT && ZX >= 0 && ZY >= 0)
  4712. #endif
  4713.     {
  4714.       attr_x = ZX;
  4715.       attr_y = ZY;
  4716.     }
  4717.  
  4718.     if (element == EL_PENGUIN)
  4719.     {
  4720.       int i;
  4721.       static int xy[4][2] =
  4722.       {
  4723.     { 0, -1 },
  4724.     { -1, 0 },
  4725.     { +1, 0 },
  4726.     { 0, +1 }
  4727.       };
  4728.  
  4729.       for (i = 0; i < NUM_DIRECTIONS; i++)
  4730.       {
  4731.         int ex = x + xy[i][0];
  4732.         int ey = y + xy[i][1];
  4733.  
  4734.         if (IN_LEV_FIELD(ex, ey) && Feld[ex][ey] == EL_EXIT_OPEN)
  4735.     {
  4736.       attr_x = ex;
  4737.        attr_y = ey;
  4738.       break;
  4739.     }
  4740.       }
  4741.     }
  4742.  
  4743.     MovDir[x][y] = MV_NO_MOVING;
  4744.     if (attr_x < x)
  4745.       MovDir[x][y] |= (AllPlayersGone ? MV_RIGHT : MV_LEFT);
  4746.     else if (attr_x > x)
  4747.       MovDir[x][y] |= (AllPlayersGone ? MV_LEFT : MV_RIGHT);
  4748.     if (attr_y < y)
  4749.       MovDir[x][y] |= (AllPlayersGone ? MV_DOWN : MV_UP);
  4750.     else if (attr_y > y)
  4751.       MovDir[x][y] |= (AllPlayersGone ? MV_UP : MV_DOWN);
  4752.  
  4753.     if (element == EL_ROBOT)
  4754.     {
  4755.       int newx, newy;
  4756.  
  4757.       if (MovDir[x][y] & MV_HORIZONTAL && MovDir[x][y] & MV_VERTICAL)
  4758.     MovDir[x][y] &= (RND(2) ? MV_HORIZONTAL : MV_VERTICAL);
  4759.       Moving2Blocked(x, y, &newx, &newy);
  4760.  
  4761.       if (IN_LEV_FIELD(newx, newy) && IS_FREE_OR_PLAYER(newx, newy))
  4762.     MovDelay[x][y] = 8 + 8 * !RND(3);
  4763.       else
  4764.     MovDelay[x][y] = 16;
  4765.     }
  4766.     else if (element == EL_PENGUIN)
  4767.     {
  4768.       int newx, newy;
  4769.  
  4770.       MovDelay[x][y] = 1;
  4771.  
  4772.       if (MovDir[x][y] & MV_HORIZONTAL && MovDir[x][y] & MV_VERTICAL)
  4773.       {
  4774.     boolean first_horiz = RND(2);
  4775.     int new_move_dir = MovDir[x][y];
  4776.  
  4777.     MovDir[x][y] =
  4778.       new_move_dir & (first_horiz ? MV_HORIZONTAL : MV_VERTICAL);
  4779.     Moving2Blocked(x, y, &newx, &newy);
  4780.  
  4781.     if (PENGUIN_CAN_ENTER_FIELD(EL_PENGUIN, newx, newy))
  4782.       return;
  4783.  
  4784.     MovDir[x][y] =
  4785.       new_move_dir & (!first_horiz ? MV_HORIZONTAL : MV_VERTICAL);
  4786.     Moving2Blocked(x, y, &newx, &newy);
  4787.  
  4788.     if (PENGUIN_CAN_ENTER_FIELD(EL_PENGUIN, newx, newy))
  4789.       return;
  4790.  
  4791.     MovDir[x][y] = old_move_dir;
  4792.     return;
  4793.       }
  4794.     }
  4795.     else    /* (element == EL_SATELLITE) */
  4796.     {
  4797.       int newx, newy;
  4798.  
  4799.       MovDelay[x][y] = 1;
  4800.  
  4801.       if (MovDir[x][y] & MV_HORIZONTAL && MovDir[x][y] & MV_VERTICAL)
  4802.       {
  4803.     boolean first_horiz = RND(2);
  4804.     int new_move_dir = MovDir[x][y];
  4805.  
  4806.     MovDir[x][y] =
  4807.       new_move_dir & (first_horiz ? MV_HORIZONTAL : MV_VERTICAL);
  4808.     Moving2Blocked(x, y, &newx, &newy);
  4809.  
  4810.     if (SATELLITE_CAN_ENTER_FIELD(newx, newy))
  4811.       return;
  4812.  
  4813.     MovDir[x][y] =
  4814.       new_move_dir & (!first_horiz ? MV_HORIZONTAL : MV_VERTICAL);
  4815.     Moving2Blocked(x, y, &newx, &newy);
  4816.  
  4817.     if (SATELLITE_CAN_ENTER_FIELD(newx, newy))
  4818.       return;
  4819.  
  4820.     MovDir[x][y] = old_move_dir;
  4821.     return;
  4822.       }
  4823.     }
  4824.   }
  4825.   else if (move_pattern == MV_TURNING_LEFT ||
  4826.        move_pattern == MV_TURNING_RIGHT ||
  4827.        move_pattern == MV_TURNING_LEFT_RIGHT ||
  4828.        move_pattern == MV_TURNING_RIGHT_LEFT ||
  4829.        move_pattern == MV_TURNING_RANDOM ||
  4830.        move_pattern == MV_ALL_DIRECTIONS)
  4831.   {
  4832.     boolean can_turn_left =
  4833.       CUSTOM_ELEMENT_CAN_ENTER_FIELD(element, left_x, left_y);
  4834.     boolean can_turn_right =
  4835.       CUSTOM_ELEMENT_CAN_ENTER_FIELD(element, right_x,right_y);
  4836.  
  4837.     if (move_pattern == MV_TURNING_LEFT)
  4838.       MovDir[x][y] = left_dir;
  4839.     else if (move_pattern == MV_TURNING_RIGHT)
  4840.       MovDir[x][y] = right_dir;
  4841.     else if (move_pattern == MV_TURNING_LEFT_RIGHT)
  4842.       MovDir[x][y] = (can_turn_left || !can_turn_right ? left_dir : right_dir);
  4843.     else if (move_pattern == MV_TURNING_RIGHT_LEFT)
  4844.       MovDir[x][y] = (can_turn_right || !can_turn_left ? right_dir : left_dir);
  4845.     else if (move_pattern == MV_TURNING_RANDOM)
  4846.       MovDir[x][y] = (can_turn_left && !can_turn_right ? left_dir :
  4847.               can_turn_right && !can_turn_left ? right_dir :
  4848.               RND(2) ? left_dir : right_dir);
  4849.     else if (can_turn_left && can_turn_right)
  4850.       MovDir[x][y] = (RND(3) ? (RND(2) ? left_dir : right_dir) : back_dir);
  4851.     else if (can_turn_left)
  4852.       MovDir[x][y] = (RND(2) ? left_dir : back_dir);
  4853.     else if (can_turn_right)
  4854.       MovDir[x][y] = (RND(2) ? right_dir : back_dir);
  4855.     else
  4856.       MovDir[x][y] = back_dir;
  4857.  
  4858.     MovDelay[x][y] = GET_NEW_MOVE_DELAY(element);
  4859.   }
  4860.   else if (move_pattern == MV_HORIZONTAL ||
  4861.        move_pattern == MV_VERTICAL)
  4862.   {
  4863.     if (move_pattern & old_move_dir)
  4864.       MovDir[x][y] = back_dir;
  4865.     else if (move_pattern == MV_HORIZONTAL)
  4866.       MovDir[x][y] = (RND(2) ? MV_LEFT : MV_RIGHT);
  4867.     else if (move_pattern == MV_VERTICAL)
  4868.       MovDir[x][y] = (RND(2) ? MV_UP : MV_DOWN);
  4869.  
  4870.     MovDelay[x][y] = GET_NEW_MOVE_DELAY(element);
  4871.   }
  4872.   else if (move_pattern & MV_ANY_DIRECTION)
  4873.   {
  4874.     MovDir[x][y] = move_pattern;
  4875.     MovDelay[x][y] = GET_NEW_MOVE_DELAY(element);
  4876.   }
  4877.   else if (move_pattern == MV_ALONG_LEFT_SIDE)
  4878.   {
  4879.     if (CUSTOM_ELEMENT_CAN_ENTER_FIELD(element, left_x, left_y))
  4880.       MovDir[x][y] = left_dir;
  4881.     else if (!CUSTOM_ELEMENT_CAN_ENTER_FIELD(element, move_x, move_y))
  4882.       MovDir[x][y] = right_dir;
  4883.  
  4884.     if (MovDir[x][y] != old_move_dir)
  4885.       MovDelay[x][y] = GET_NEW_MOVE_DELAY(element);
  4886.   }
  4887.   else if (move_pattern == MV_ALONG_RIGHT_SIDE)
  4888.   {
  4889.     if (CUSTOM_ELEMENT_CAN_ENTER_FIELD(element, right_x, right_y))
  4890.       MovDir[x][y] = right_dir;
  4891.     else if (!CUSTOM_ELEMENT_CAN_ENTER_FIELD(element, move_x, move_y))
  4892.       MovDir[x][y] = left_dir;
  4893.  
  4894.     if (MovDir[x][y] != old_move_dir)
  4895.       MovDelay[x][y] = GET_NEW_MOVE_DELAY(element);
  4896.   }
  4897.   else if (move_pattern == MV_TOWARDS_PLAYER ||
  4898.        move_pattern == MV_AWAY_FROM_PLAYER)
  4899.   {
  4900.     int attr_x = -1, attr_y = -1;
  4901.     int newx, newy;
  4902.     boolean move_away = (move_pattern == MV_AWAY_FROM_PLAYER);
  4903.  
  4904.     if (AllPlayersGone)
  4905.     {
  4906.       attr_x = ExitX;
  4907.       attr_y = ExitY;
  4908.     }
  4909.     else
  4910.     {
  4911.       int i;
  4912.  
  4913.       for (i = 0; i < MAX_PLAYERS; i++)
  4914.       {
  4915.     struct PlayerInfo *player = &stored_player[i];
  4916.     int jx = player->jx, jy = player->jy;
  4917.  
  4918.     if (!player->active)
  4919.       continue;
  4920.  
  4921.     if (attr_x == -1 ||
  4922.         ABS(jx - x) + ABS(jy - y) < ABS(attr_x - x) + ABS(attr_y - y))
  4923.     {
  4924.       attr_x = jx;
  4925.       attr_y = jy;
  4926.     }
  4927.       }
  4928.     }
  4929.  
  4930.     MovDir[x][y] = MV_NO_MOVING;
  4931.     if (attr_x < x)
  4932.       MovDir[x][y] |= (move_away ? MV_RIGHT : MV_LEFT);
  4933.     else if (attr_x > x)
  4934.       MovDir[x][y] |= (move_away ? MV_LEFT : MV_RIGHT);
  4935.     if (attr_y < y)
  4936.       MovDir[x][y] |= (move_away ? MV_DOWN : MV_UP);
  4937.     else if (attr_y > y)
  4938.       MovDir[x][y] |= (move_away ? MV_UP : MV_DOWN);
  4939.  
  4940.     MovDelay[x][y] = GET_NEW_MOVE_DELAY(element);
  4941.  
  4942.     if (MovDir[x][y] & MV_HORIZONTAL && MovDir[x][y] & MV_VERTICAL)
  4943.     {
  4944.       boolean first_horiz = RND(2);
  4945.       int new_move_dir = MovDir[x][y];
  4946.  
  4947.       MovDir[x][y] =
  4948.     new_move_dir & (first_horiz ? MV_HORIZONTAL : MV_VERTICAL);
  4949.       Moving2Blocked(x, y, &newx, &newy);
  4950.  
  4951.       if (CUSTOM_ELEMENT_CAN_ENTER_FIELD(element, newx, newy))
  4952.     return;
  4953.  
  4954.       MovDir[x][y] =
  4955.     new_move_dir & (!first_horiz ? MV_HORIZONTAL : MV_VERTICAL);
  4956.       Moving2Blocked(x, y, &newx, &newy);
  4957.  
  4958.       if (CUSTOM_ELEMENT_CAN_ENTER_FIELD(element, newx, newy))
  4959.     return;
  4960.  
  4961.       MovDir[x][y] = old_move_dir;
  4962.     }
  4963.   }
  4964.   else if (move_pattern == MV_WHEN_PUSHED ||
  4965.        move_pattern == MV_WHEN_DROPPED)
  4966.   {
  4967.     if (!CUSTOM_ELEMENT_CAN_ENTER_FIELD(element, move_x, move_y))
  4968.       MovDir[x][y] = MV_NO_MOVING;
  4969.  
  4970.     MovDelay[x][y] = 0;
  4971.   }
  4972.   else if (move_pattern & MV_MAZE_RUNNER_STYLE)
  4973.   {
  4974.     static int test_xy[7][2] =
  4975.     {
  4976.       { 0, -1 },
  4977.       { -1, 0 },
  4978.       { +1, 0 },
  4979.       { 0, +1 },
  4980.       { 0, -1 },
  4981.       { -1, 0 },
  4982.       { +1, 0 },
  4983.     };
  4984.     static int test_dir[7] =
  4985.     {
  4986.       MV_UP,
  4987.       MV_LEFT,
  4988.       MV_RIGHT,
  4989.       MV_DOWN,
  4990.       MV_UP,
  4991.       MV_LEFT,
  4992.       MV_RIGHT,
  4993.     };
  4994.     boolean hunter_mode = (move_pattern == MV_MAZE_HUNTER);
  4995.     int move_preference = -1000000;    /* start with very low preference */
  4996.     int new_move_dir = MV_NO_MOVING;
  4997.     int start_test = RND(4);
  4998.     int i;
  4999.  
  5000.     for (i = 0; i < NUM_DIRECTIONS; i++)
  5001.     {
  5002.       int move_dir = test_dir[start_test + i];
  5003.       int move_dir_preference;
  5004.  
  5005.       xx = x + test_xy[start_test + i][0];
  5006.       yy = y + test_xy[start_test + i][1];
  5007.  
  5008.       if (hunter_mode && IN_LEV_FIELD(xx, yy) &&
  5009.       (IS_PLAYER(xx, yy) || Feld[xx][yy] == EL_PLAYER_IS_LEAVING))
  5010.       {
  5011.     new_move_dir = move_dir;
  5012.  
  5013.     break;
  5014.       }
  5015.  
  5016.       if (!CUSTOM_ELEMENT_CAN_ENTER_FIELD(element, xx, yy))
  5017.     continue;
  5018.  
  5019.       move_dir_preference = -1 * RunnerVisit[xx][yy];
  5020.       if (hunter_mode && PlayerVisit[xx][yy] > 0)
  5021.     move_dir_preference = PlayerVisit[xx][yy];
  5022.  
  5023.       if (move_dir_preference > move_preference)
  5024.       {
  5025.     /* prefer field that has not been visited for the longest time */
  5026.     move_preference = move_dir_preference;
  5027.     new_move_dir = move_dir;
  5028.       }
  5029.       else if (move_dir_preference == move_preference &&
  5030.            move_dir == old_move_dir)
  5031.       {
  5032.     /* prefer last direction when all directions are preferred equally */
  5033.     move_preference = move_dir_preference;
  5034.     new_move_dir = move_dir;
  5035.       }
  5036.     }
  5037.  
  5038.     MovDir[x][y] = new_move_dir;
  5039.     if (old_move_dir != new_move_dir)
  5040.       MovDelay[x][y] = 9;
  5041.   }
  5042. }
  5043.  
  5044. static void TurnRound(int x, int y)
  5045. {
  5046.   int direction = MovDir[x][y];
  5047.  
  5048. #if 0
  5049.   GfxDir[x][y] = MovDir[x][y];
  5050. #endif
  5051.  
  5052.   TurnRoundExt(x, y);
  5053.  
  5054. #if 1
  5055.   GfxDir[x][y] = MovDir[x][y];
  5056. #endif
  5057.  
  5058.   if (direction != MovDir[x][y])
  5059.     GfxFrame[x][y] = 0;
  5060.  
  5061. #if 1
  5062.   if (MovDelay[x][y])
  5063.     GfxAction[x][y] = ACTION_TURNING_FROM_LEFT + MV_DIR_BIT(direction);
  5064. #else
  5065.   if (MovDelay[x][y])
  5066.     GfxAction[x][y] = ACTION_WAITING;
  5067. #endif
  5068. }
  5069.  
  5070. static boolean JustBeingPushed(int x, int y)
  5071. {
  5072.   int i;
  5073.  
  5074.   for (i = 0; i < MAX_PLAYERS; i++)
  5075.   {
  5076.     struct PlayerInfo *player = &stored_player[i];
  5077.  
  5078.     if (player->active && player->is_pushing && player->MovPos)
  5079.     {
  5080.       int next_jx = player->jx + (player->jx - player->last_jx);
  5081.       int next_jy = player->jy + (player->jy - player->last_jy);
  5082.  
  5083.       if (x == next_jx && y == next_jy)
  5084.     return TRUE;
  5085.     }
  5086.   }
  5087.  
  5088.   return FALSE;
  5089. }
  5090.  
  5091. void StartMoving(int x, int y)
  5092. {
  5093. #if 0
  5094.   boolean use_spring_bug = (game.engine_version < VERSION_IDENT(2,2,0,0));
  5095. #endif
  5096.   boolean started_moving = FALSE;    /* some elements can fall _and_ move */
  5097.   int element = Feld[x][y];
  5098.  
  5099.   if (Stop[x][y])
  5100.     return;
  5101.  
  5102. #if 1
  5103.   if (MovDelay[x][y] == 0)
  5104.     GfxAction[x][y] = ACTION_DEFAULT;
  5105. #else
  5106.   /* !!! this should be handled more generic (not only for mole) !!! */
  5107.   if (element != EL_MOLE && GfxAction[x][y] != ACTION_DIGGING)
  5108.     GfxAction[x][y] = ACTION_DEFAULT;
  5109. #endif
  5110.  
  5111.   if (CAN_FALL(element) && y < lev_fieldy - 1)
  5112.   {
  5113.     if ((x > 0              && IS_PLAYER(x - 1, y)) ||
  5114.     (x < lev_fieldx - 1 && IS_PLAYER(x + 1, y)))
  5115.       if (JustBeingPushed(x, y))
  5116.     return;
  5117.  
  5118.     if (element == EL_QUICKSAND_FULL)
  5119.     {
  5120.       if (IS_FREE(x, y + 1))
  5121.       {
  5122.     InitMovingField(x, y, MV_DOWN);
  5123.     started_moving = TRUE;
  5124.  
  5125.     Feld[x][y] = EL_QUICKSAND_EMPTYING;
  5126.     Store[x][y] = EL_ROCK;
  5127. #if 1
  5128.     PlayLevelSoundAction(x, y, ACTION_EMPTYING);
  5129. #else
  5130.     PlayLevelSound(x, y, SND_QUICKSAND_EMPTYING);
  5131. #endif
  5132.       }
  5133.       else if (Feld[x][y + 1] == EL_QUICKSAND_EMPTY)
  5134.       {
  5135.     if (!MovDelay[x][y])
  5136.       MovDelay[x][y] = TILEY + 1;
  5137.  
  5138.     if (MovDelay[x][y])
  5139.     {
  5140.       MovDelay[x][y]--;
  5141.       if (MovDelay[x][y])
  5142.         return;
  5143.     }
  5144.  
  5145.     Feld[x][y] = EL_QUICKSAND_EMPTY;
  5146.     Feld[x][y + 1] = EL_QUICKSAND_FULL;
  5147.     Store[x][y + 1] = Store[x][y];
  5148.     Store[x][y] = 0;
  5149. #if 1
  5150.     PlayLevelSoundAction(x, y, ACTION_FILLING);
  5151. #else
  5152.     PlayLevelSound(x, y, SND_QUICKSAND_FILLING);
  5153. #endif
  5154.       }
  5155.     }
  5156.     else if ((element == EL_ROCK || element == EL_BD_ROCK) &&
  5157.          Feld[x][y + 1] == EL_QUICKSAND_EMPTY)
  5158.     {
  5159.       InitMovingField(x, y, MV_DOWN);
  5160.       started_moving = TRUE;
  5161.  
  5162.       Feld[x][y] = EL_QUICKSAND_FILLING;
  5163.       Store[x][y] = element;
  5164. #if 1
  5165.       PlayLevelSoundAction(x, y, ACTION_FILLING);
  5166. #else
  5167.       PlayLevelSound(x, y, SND_QUICKSAND_FILLING);
  5168. #endif
  5169.     }
  5170.     else if (element == EL_MAGIC_WALL_FULL)
  5171.     {
  5172.       if (IS_FREE(x, y + 1))
  5173.       {
  5174.     InitMovingField(x, y, MV_DOWN);
  5175.     started_moving = TRUE;
  5176.  
  5177.     Feld[x][y] = EL_MAGIC_WALL_EMPTYING;
  5178.     Store[x][y] = EL_CHANGED(Store[x][y]);
  5179.       }
  5180.       else if (Feld[x][y + 1] == EL_MAGIC_WALL_ACTIVE)
  5181.       {
  5182.     if (!MovDelay[x][y])
  5183.       MovDelay[x][y] = TILEY/4 + 1;
  5184.  
  5185.     if (MovDelay[x][y])
  5186.     {
  5187.       MovDelay[x][y]--;
  5188.       if (MovDelay[x][y])
  5189.         return;
  5190.     }
  5191.  
  5192.     Feld[x][y] = EL_MAGIC_WALL_ACTIVE;
  5193.     Feld[x][y + 1] = EL_MAGIC_WALL_FULL;
  5194.     Store[x][y + 1] = EL_CHANGED(Store[x][y]);
  5195.     Store[x][y] = 0;
  5196.       }
  5197.     }
  5198.     else if (element == EL_BD_MAGIC_WALL_FULL)
  5199.     {
  5200.       if (IS_FREE(x, y + 1))
  5201.       {
  5202.     InitMovingField(x, y, MV_DOWN);
  5203.     started_moving = TRUE;
  5204.  
  5205.     Feld[x][y] = EL_BD_MAGIC_WALL_EMPTYING;
  5206.     Store[x][y] = EL_CHANGED2(Store[x][y]);
  5207.       }
  5208.       else if (Feld[x][y + 1] == EL_BD_MAGIC_WALL_ACTIVE)
  5209.       {
  5210.     if (!MovDelay[x][y])
  5211.       MovDelay[x][y] = TILEY/4 + 1;
  5212.  
  5213.     if (MovDelay[x][y])
  5214.     {
  5215.       MovDelay[x][y]--;
  5216.       if (MovDelay[x][y])
  5217.         return;
  5218.     }
  5219.  
  5220.     Feld[x][y] = EL_BD_MAGIC_WALL_ACTIVE;
  5221.     Feld[x][y + 1] = EL_BD_MAGIC_WALL_FULL;
  5222.     Store[x][y + 1] = EL_CHANGED2(Store[x][y]);
  5223.     Store[x][y] = 0;
  5224.       }
  5225.     }
  5226.     else if (CAN_PASS_MAGIC_WALL(element) &&
  5227.          (Feld[x][y + 1] == EL_MAGIC_WALL_ACTIVE ||
  5228.           Feld[x][y + 1] == EL_BD_MAGIC_WALL_ACTIVE))
  5229.     {
  5230.       InitMovingField(x, y, MV_DOWN);
  5231.       started_moving = TRUE;
  5232.  
  5233.       Feld[x][y] =
  5234.     (Feld[x][y + 1] == EL_MAGIC_WALL_ACTIVE ? EL_MAGIC_WALL_FILLING :
  5235.      EL_BD_MAGIC_WALL_FILLING);
  5236.       Store[x][y] = element;
  5237.     }
  5238. #if 0
  5239.     else if (CAN_SMASH(element) && Feld[x][y + 1] == EL_ACID)
  5240. #else
  5241.     else if (CAN_FALL(element) && Feld[x][y + 1] == EL_ACID)
  5242. #endif
  5243.     {
  5244.       SplashAcid(x, y + 1);
  5245.  
  5246.       InitMovingField(x, y, MV_DOWN);
  5247.       started_moving = TRUE;
  5248.  
  5249.       Store[x][y] = EL_ACID;
  5250. #if 0
  5251.       /* !!! TEST !!! better use "_FALLING" etc. !!! */
  5252.       GfxAction[x][y + 1] = ACTION_ACTIVE;
  5253. #endif
  5254.     }
  5255. #if 1
  5256.     else if ((game.engine_version >= VERSION_IDENT(3,1,0,0) &&
  5257.           CheckCollision[x][y] && !IS_FREE(x, y + 1)) ||
  5258.  
  5259.          (game.engine_version >= VERSION_IDENT(3,0,7,0) &&
  5260.           CAN_SMASH(element) && WasJustFalling[x][y] &&
  5261.           (Feld[x][y + 1] == EL_BLOCKED || IS_PLAYER(x, y + 1))) ||
  5262.  
  5263.          (game.engine_version < VERSION_IDENT(2,2,0,7) &&
  5264.           CAN_SMASH(element) && WasJustMoving[x][y] && !Pushed[x][y + 1] &&
  5265.           (Feld[x][y + 1] == EL_BLOCKED)))
  5266.  
  5267. #else
  5268. #if 1
  5269.     else if (game.engine_version < VERSION_IDENT(2,2,0,7) &&
  5270.          CAN_SMASH(element) && Feld[x][y + 1] == EL_BLOCKED &&
  5271.          WasJustMoving[x][y] && !Pushed[x][y + 1])
  5272. #else
  5273.     else if (CAN_SMASH(element) && Feld[x][y + 1] == EL_BLOCKED &&
  5274.          WasJustMoving[x][y])
  5275. #endif
  5276. #endif
  5277.  
  5278.     {
  5279.       /* this is needed for a special case not covered by calling "Impact()"
  5280.      from "ContinueMoving()": if an element moves to a tile directly below
  5281.      another element which was just falling on that tile (which was empty
  5282.      in the previous frame), the falling element above would just stop
  5283.      instead of smashing the element below (in previous version, the above
  5284.      element was just checked for "moving" instead of "falling", resulting
  5285.      in incorrect smashes caused by horizontal movement of the above
  5286.      element; also, the case of the player being the element to smash was
  5287.      simply not covered here... :-/ ) */
  5288.  
  5289. #if 0
  5290.       WasJustMoving[x][y] = 0;
  5291.       WasJustFalling[x][y] = 0;
  5292. #endif
  5293.  
  5294.       CheckCollision[x][y] = 0;
  5295.  
  5296.       Impact(x, y);
  5297.     }
  5298.     else if (IS_FREE(x, y + 1) && element == EL_SPRING && level.use_spring_bug)
  5299.     {
  5300.       if (MovDir[x][y] == MV_NO_MOVING)
  5301.       {
  5302.     InitMovingField(x, y, MV_DOWN);
  5303.     started_moving = TRUE;
  5304.       }
  5305.     }
  5306.     else if (IS_FREE(x, y + 1) || Feld[x][y + 1] == EL_DIAMOND_BREAKING)
  5307.     {
  5308.       if (WasJustFalling[x][y])    /* prevent animation from being restarted */
  5309.     MovDir[x][y] = MV_DOWN;
  5310.  
  5311.       InitMovingField(x, y, MV_DOWN);
  5312.       started_moving = TRUE;
  5313.     }
  5314.     else if (element == EL_AMOEBA_DROP)
  5315.     {
  5316.       Feld[x][y] = EL_AMOEBA_GROWING;
  5317.       Store[x][y] = EL_AMOEBA_WET;
  5318.     }
  5319.     /* Store[x][y + 1] must be zero, because:
  5320.        (EL_QUICKSAND_FULL -> EL_ROCK): Store[x][y + 1] == EL_QUICKSAND_EMPTY
  5321.     */
  5322. #if 0
  5323. #if OLD_GAME_BEHAVIOUR
  5324.     else if (IS_SLIPPERY(Feld[x][y + 1]) && !Store[x][y + 1])
  5325. #else
  5326.     else if (IS_SLIPPERY(Feld[x][y + 1]) && !Store[x][y + 1] &&
  5327.          !IS_FALLING(x, y + 1) && !WasJustMoving[x][y + 1] &&
  5328.          element != EL_DX_SUPABOMB)
  5329. #endif
  5330. #else
  5331.     else if (((IS_SLIPPERY(Feld[x][y + 1]) && !IS_PLAYER(x, y + 1)) ||
  5332.           (IS_EM_SLIPPERY_WALL(Feld[x][y + 1]) && IS_GEM(element))) &&
  5333.          !IS_FALLING(x, y + 1) && !WasJustMoving[x][y + 1] &&
  5334.          element != EL_DX_SUPABOMB && element != EL_SP_DISK_ORANGE)
  5335. #endif
  5336.     {
  5337.       boolean can_fall_left  = (x > 0 && IS_FREE(x - 1, y) &&
  5338.                 (IS_FREE(x - 1, y + 1) ||
  5339.                  Feld[x - 1][y + 1] == EL_ACID));
  5340.       boolean can_fall_right = (x < lev_fieldx - 1 && IS_FREE(x + 1, y) &&
  5341.                 (IS_FREE(x + 1, y + 1) ||
  5342.                  Feld[x + 1][y + 1] == EL_ACID));
  5343.       boolean can_fall_any  = (can_fall_left || can_fall_right);
  5344.       boolean can_fall_both = (can_fall_left && can_fall_right);
  5345.  
  5346.       if (can_fall_any && IS_CUSTOM_ELEMENT(Feld[x][y + 1]))
  5347.       {
  5348.     int slippery_type = element_info[Feld[x][y + 1]].slippery_type;
  5349.  
  5350.     if (slippery_type == SLIPPERY_ONLY_LEFT)
  5351.       can_fall_right = FALSE;
  5352.     else if (slippery_type == SLIPPERY_ONLY_RIGHT)
  5353.       can_fall_left = FALSE;
  5354.     else if (slippery_type == SLIPPERY_ANY_LEFT_RIGHT && can_fall_both)
  5355.       can_fall_right = FALSE;
  5356.     else if (slippery_type == SLIPPERY_ANY_RIGHT_LEFT && can_fall_both)
  5357.       can_fall_left = FALSE;
  5358.  
  5359.     can_fall_any  = (can_fall_left || can_fall_right);
  5360.     can_fall_both = (can_fall_left && can_fall_right);
  5361.       }
  5362.  
  5363.       if (can_fall_any)
  5364.       {
  5365.     if (can_fall_both &&
  5366.         (game.emulation != EMU_BOULDERDASH &&
  5367.          element != EL_BD_ROCK && element != EL_BD_DIAMOND))
  5368.       can_fall_left = !(can_fall_right = RND(2));
  5369.  
  5370.     InitMovingField(x, y, can_fall_left ? MV_LEFT : MV_RIGHT);
  5371.     started_moving = TRUE;
  5372.       }
  5373.     }
  5374. #if 0
  5375.     else if (IS_BELT_ACTIVE(Feld[x][y + 1]) && !CAN_MOVE(element))
  5376. #else
  5377.     else if (IS_BELT_ACTIVE(Feld[x][y + 1]))
  5378. #endif
  5379.     {
  5380.       boolean left_is_free  = (x > 0 && IS_FREE(x - 1, y));
  5381.       boolean right_is_free = (x < lev_fieldx - 1 && IS_FREE(x + 1, y));
  5382.       int belt_nr = getBeltNrFromBeltActiveElement(Feld[x][y + 1]);
  5383.       int belt_dir = game.belt_dir[belt_nr];
  5384.  
  5385.       if ((belt_dir == MV_LEFT  && left_is_free) ||
  5386.       (belt_dir == MV_RIGHT && right_is_free))
  5387.       {
  5388. #if 1
  5389.     int nextx = (belt_dir == MV_LEFT ? x - 1 : x + 1);
  5390. #endif
  5391.  
  5392.     InitMovingField(x, y, belt_dir);
  5393.     started_moving = TRUE;
  5394.  
  5395. #if 1
  5396.     Pushed[x][y] = TRUE;
  5397.     Pushed[nextx][y] = TRUE;
  5398. #endif
  5399.  
  5400.     GfxAction[x][y] = ACTION_DEFAULT;
  5401.       }
  5402.       else
  5403.       {
  5404.     MovDir[x][y] = 0;    /* if element was moving, stop it */
  5405.       }
  5406.     }
  5407.   }
  5408.  
  5409.   /* not "else if" because of elements that can fall and move (EL_SPRING) */
  5410. #if 0
  5411.   if (CAN_MOVE(element) && !started_moving && MovDir[x][y] != MV_NO_MOVING)
  5412. #else
  5413.   if (CAN_MOVE(element) && !started_moving)
  5414. #endif
  5415.   {
  5416.     int move_pattern = element_info[element].move_pattern;
  5417.     int newx, newy;
  5418.  
  5419. #if 0
  5420. #if DEBUG
  5421.     if (MovDir[x][y] == MV_NO_MOVING)
  5422.     {
  5423.       printf("StartMoving(): %d,%d: element %d ['%s'] not moving\n",
  5424.          x, y, element, element_info[element].token_name);
  5425.       printf("StartMoving(): This should never happen!\n");
  5426.     }
  5427. #endif
  5428. #endif
  5429.  
  5430.     Moving2Blocked(x, y, &newx, &newy);
  5431.  
  5432. #if 1
  5433.     if (IS_PUSHABLE(element) && JustBeingPushed(x, y))
  5434.       return;
  5435. #else
  5436.     if ((element == EL_SATELLITE ||
  5437.      element == EL_BALLOON ||
  5438.      element == EL_SPRING)
  5439.     && JustBeingPushed(x, y))
  5440.       return;
  5441. #endif
  5442.  
  5443. #if 1
  5444.  
  5445. #if 1
  5446.     if (game.engine_version >= VERSION_IDENT(3,1,0,0) &&
  5447.     CheckCollision[x][y] && !IN_LEV_FIELD_AND_IS_FREE(newx, newy))
  5448. #else
  5449.     if (game.engine_version >= VERSION_IDENT(3,1,0,0) &&
  5450.     WasJustMoving[x][y] && IN_LEV_FIELD(newx, newy) &&
  5451.     (Feld[newx][newy] == EL_BLOCKED || IS_PLAYER(newx, newy)))
  5452. #endif
  5453.     {
  5454. #if 0
  5455.       printf("::: element %d '%s' WasJustMoving %d [%d, %d, %d, %d]\n",
  5456.          element, element_info[element].token_name,
  5457.          WasJustMoving[x][y],
  5458.          HAS_ANY_CHANGE_EVENT(element, CE_HITTING_SOMETHING),
  5459.          HAS_ANY_CHANGE_EVENT(element, CE_HIT_BY_SOMETHING),
  5460.          HAS_ANY_CHANGE_EVENT(element, CE_OTHER_IS_HITTING),
  5461.          HAS_ANY_CHANGE_EVENT(element, CE_OTHER_GETS_HIT));
  5462. #endif
  5463.  
  5464. #if 1
  5465.       WasJustMoving[x][y] = 0;
  5466. #endif
  5467.  
  5468.       CheckCollision[x][y] = 0;
  5469.  
  5470.       TestIfElementHitsCustomElement(x, y, MovDir[x][y]);
  5471.  
  5472. #if 0
  5473.       if (Feld[x][y] != element)    /* element has changed */
  5474.       {
  5475.     element = Feld[x][y];
  5476.     move_pattern = element_info[element].move_pattern;
  5477.  
  5478.     if (!CAN_MOVE(element))
  5479.       return;
  5480.       }
  5481. #else
  5482.       if (Feld[x][y] != element)    /* element has changed */
  5483.     return;
  5484. #endif
  5485.     }
  5486. #endif
  5487.  
  5488. #if 0
  5489. #if 0
  5490.     if (element == EL_SPRING && MovDir[x][y] == MV_DOWN)
  5491.       Feld[x][y + 1] = EL_EMPTY;    /* was set to EL_BLOCKED above */
  5492. #else
  5493.     if (element == EL_SPRING && MovDir[x][y] != MV_NO_MOVING)
  5494.     {
  5495.       Moving2Blocked(x, y, &newx, &newy);
  5496.       if (Feld[newx][newy] == EL_BLOCKED)
  5497.     Feld[newx][newy] = EL_EMPTY;    /* was set to EL_BLOCKED above */
  5498.     }
  5499. #endif
  5500. #endif
  5501.  
  5502. #if 0
  5503.     if (FrameCounter < 1 && x == 0 && y == 29)
  5504.       printf(":1: %d/%d: %d [%d]\n", x, y, MovDir[x][y], FrameCounter);
  5505. #endif
  5506.  
  5507.     if (!MovDelay[x][y])    /* start new movement phase */
  5508.     {
  5509.       /* all objects that can change their move direction after each step
  5510.      (YAMYAM, DARK_YAMYAM and PACMAN go straight until they hit a wall */
  5511.  
  5512.       if (element != EL_YAMYAM &&
  5513.       element != EL_DARK_YAMYAM &&
  5514.       element != EL_PACMAN &&
  5515.       !(move_pattern & MV_ANY_DIRECTION) &&
  5516.       move_pattern != MV_TURNING_LEFT &&
  5517.       move_pattern != MV_TURNING_RIGHT &&
  5518.       move_pattern != MV_TURNING_LEFT_RIGHT &&
  5519.       move_pattern != MV_TURNING_RIGHT_LEFT &&
  5520.       move_pattern != MV_TURNING_RANDOM)
  5521.       {
  5522.     TurnRound(x, y);
  5523.  
  5524. #if 0
  5525.     if (FrameCounter < 1 && x == 0 && y == 29)
  5526.       printf(":9: %d: %d [%d]\n", y, MovDir[x][y], FrameCounter);
  5527. #endif
  5528.  
  5529.     if (MovDelay[x][y] && (element == EL_BUG ||
  5530.                    element == EL_SPACESHIP ||
  5531.                    element == EL_SP_SNIKSNAK ||
  5532.                    element == EL_SP_ELECTRON ||
  5533.                    element == EL_MOLE))
  5534.       DrawLevelField(x, y);
  5535.       }
  5536.     }
  5537.  
  5538.     if (MovDelay[x][y])        /* wait some time before next movement */
  5539.     {
  5540.       MovDelay[x][y]--;
  5541.  
  5542. #if 0
  5543.       if (element == EL_YAMYAM)
  5544.       {
  5545.     printf("::: %d\n",
  5546.            el_act_dir2img(EL_YAMYAM, ACTION_WAITING, MV_LEFT));
  5547.     DrawLevelElementAnimation(x, y, element);
  5548.       }
  5549. #endif
  5550.  
  5551.       if (MovDelay[x][y])    /* element still has to wait some time */
  5552.       {
  5553. #if 0
  5554.     /* !!! PLACE THIS SOMEWHERE AFTER "TurnRound()" !!! */
  5555.     ResetGfxAnimation(x, y);
  5556. #endif
  5557.  
  5558. #if 0
  5559.     if (GfxAction[x][y] != ACTION_WAITING)
  5560.       printf("::: %d: %d != ACTION_WAITING\n", element, GfxAction[x][y]);
  5561.  
  5562.     GfxAction[x][y] = ACTION_WAITING;
  5563. #endif
  5564.       }
  5565.  
  5566.       if (element == EL_ROBOT ||
  5567. #if 0
  5568.       element == EL_PACMAN ||
  5569. #endif
  5570.       element == EL_YAMYAM ||
  5571.       element == EL_DARK_YAMYAM)
  5572.       {
  5573. #if 0
  5574.     DrawLevelElementAnimation(x, y, element);
  5575. #else
  5576.     DrawLevelElementAnimationIfNeeded(x, y, element);
  5577. #endif
  5578.     PlayLevelSoundAction(x, y, ACTION_WAITING);
  5579.       }
  5580.       else if (element == EL_SP_ELECTRON)
  5581.     DrawLevelElementAnimationIfNeeded(x, y, element);
  5582.       else if (element == EL_DRAGON)
  5583.       {
  5584.     int i;
  5585.     int dir = MovDir[x][y];
  5586.     int dx = (dir == MV_LEFT ? -1 : dir == MV_RIGHT ? +1 : 0);
  5587.     int dy = (dir == MV_UP   ? -1 : dir == MV_DOWN  ? +1 : 0);
  5588.     int graphic = (dir == MV_LEFT    ? IMG_FLAMES_1_LEFT :
  5589.                dir == MV_RIGHT    ? IMG_FLAMES_1_RIGHT :
  5590.                dir == MV_UP    ? IMG_FLAMES_1_UP :
  5591.                dir == MV_DOWN    ? IMG_FLAMES_1_DOWN : IMG_EMPTY);
  5592.     int frame = getGraphicAnimationFrame(graphic, GfxFrame[x][y]);
  5593.  
  5594. #if 0
  5595.     printf("::: %d, %d\n", GfxAction[x][y], GfxFrame[x][y]);
  5596. #endif
  5597.  
  5598.     GfxAction[x][y] = ACTION_ATTACKING;
  5599.  
  5600.     if (IS_PLAYER(x, y))
  5601.       DrawPlayerField(x, y);
  5602.     else
  5603.       DrawLevelField(x, y);
  5604.  
  5605.     PlayLevelSoundActionIfLoop(x, y, ACTION_ATTACKING);
  5606.  
  5607.     for (i = 1; i <= 3; i++)
  5608.     {
  5609.       int xx = x + i * dx;
  5610.       int yy = y + i * dy;
  5611.       int sx = SCREENX(xx);
  5612.       int sy = SCREENY(yy);
  5613.       int flame_graphic = graphic + (i - 1);
  5614.  
  5615.       if (!IN_LEV_FIELD(xx, yy) || IS_DRAGONFIRE_PROOF(Feld[xx][yy]))
  5616.         break;
  5617.  
  5618.       if (MovDelay[x][y])
  5619.       {
  5620.         int flamed = MovingOrBlocked2Element(xx, yy);
  5621.  
  5622.         /* !!! */
  5623. #if 0
  5624.         if (IS_CLASSIC_ENEMY(flamed) || CAN_EXPLODE_BY_DRAGONFIRE(flamed))
  5625.           Bang(xx, yy);
  5626.         else if (IS_MOVING(xx, yy) || IS_BLOCKED(xx, yy))
  5627.           RemoveMovingField(xx, yy);
  5628.         else
  5629.           RemoveField(xx, yy);
  5630. #else
  5631.         if (IS_CLASSIC_ENEMY(flamed) || CAN_EXPLODE_BY_DRAGONFIRE(flamed))
  5632.           Bang(xx, yy);
  5633.         else
  5634.           RemoveMovingField(xx, yy);
  5635. #endif
  5636.  
  5637. #if 0
  5638.         if (ChangeDelay[xx][yy])
  5639.           printf("::: !!! [%d]\n", (IS_MOVING(xx, yy) ||
  5640.                     Feld[xx][yy] == EL_BLOCKED));
  5641. #endif
  5642.  
  5643. #if 1
  5644.         ChangeDelay[xx][yy] = 0;
  5645. #endif
  5646.         Feld[xx][yy] = EL_FLAMES;
  5647.         if (IN_SCR_FIELD(sx, sy))
  5648.         {
  5649.           DrawLevelFieldCrumbledSand(xx, yy);
  5650.           DrawGraphic(sx, sy, flame_graphic, frame);
  5651.         }
  5652.       }
  5653.       else
  5654.       {
  5655.         if (Feld[xx][yy] == EL_FLAMES)
  5656.           Feld[xx][yy] = EL_EMPTY;
  5657.         DrawLevelField(xx, yy);
  5658.       }
  5659.     }
  5660.       }
  5661.  
  5662.       if (MovDelay[x][y])    /* element still has to wait some time */
  5663.       {
  5664.     PlayLevelSoundAction(x, y, ACTION_WAITING);
  5665.  
  5666.     return;
  5667.       }
  5668.  
  5669. #if 0
  5670.       /* special case of "moving" animation of waiting elements (FIX THIS !!!);
  5671.      for all other elements GfxAction will be set by InitMovingField() */
  5672.       if (element == EL_BD_BUTTERFLY || element == EL_BD_FIREFLY)
  5673.     GfxAction[x][y] = ACTION_MOVING;
  5674. #endif
  5675.     }
  5676.  
  5677.     /* now make next step */
  5678.  
  5679.     Moving2Blocked(x, y, &newx, &newy);    /* get next screen position */
  5680.  
  5681.     if (DONT_COLLIDE_WITH(element) &&
  5682.     IN_LEV_FIELD(newx, newy) && IS_PLAYER(newx, newy) &&
  5683.     !PLAYER_ENEMY_PROTECTED(newx, newy))
  5684.     {
  5685. #if 1
  5686.       TestIfBadThingRunsIntoHero(x, y, MovDir[x][y]);
  5687.  
  5688.       return;
  5689. #else
  5690.       /* player killed by element which is deadly when colliding with */
  5691.       MovDir[x][y] = 0;
  5692.       KillHero(PLAYERINFO(newx, newy));
  5693.       return;
  5694. #endif
  5695.  
  5696.     }
  5697. #if 1
  5698. #if 1
  5699.     else if (CAN_MOVE_INTO_ACID(element) &&
  5700.          IN_LEV_FIELD(newx, newy) && Feld[newx][newy] == EL_ACID &&
  5701.          (MovDir[x][y] == MV_DOWN ||
  5702.           game.engine_version >= VERSION_IDENT(3,1,0,0)))
  5703. #else
  5704.     else if (CAN_MOVE_INTO_ACID(element) && MovDir[x][y] == MV_DOWN &&
  5705.          IN_LEV_FIELD(newx, newy) && Feld[newx][newy] == EL_ACID)
  5706. #endif
  5707. #else
  5708.  
  5709.     else if ((element == EL_PENGUIN ||
  5710.           element == EL_ROBOT ||
  5711.           element == EL_SATELLITE ||
  5712.           element == EL_BALLOON ||
  5713.           IS_CUSTOM_ELEMENT(element)) &&
  5714.          IN_LEV_FIELD(newx, newy) &&
  5715.          MovDir[x][y] == MV_DOWN && Feld[newx][newy] == EL_ACID)
  5716. #endif
  5717.     {
  5718.       SplashAcid(newx, newy);
  5719.       Store[x][y] = EL_ACID;
  5720.     }
  5721.     else if (element == EL_PENGUIN && IN_LEV_FIELD(newx, newy))
  5722.     {
  5723.       if (Feld[newx][newy] == EL_EXIT_OPEN)
  5724.       {
  5725. #if 1
  5726.     RemoveField(x, y);
  5727.     DrawLevelField(x, y);
  5728. #else
  5729.     Feld[x][y] = EL_EMPTY;
  5730.     DrawLevelField(x, y);
  5731. #endif
  5732.  
  5733.     PlayLevelSound(newx, newy, SND_PENGUIN_PASSING);
  5734.     if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
  5735.       DrawGraphicThruMask(SCREENX(newx),SCREENY(newy), el2img(element), 0);
  5736.  
  5737.     local_player->friends_still_needed--;
  5738.     if (!local_player->friends_still_needed &&
  5739.         !local_player->GameOver && AllPlayersGone)
  5740.       local_player->LevelSolved = local_player->GameOver = TRUE;
  5741.  
  5742.     return;
  5743.       }
  5744.       else if (IS_FOOD_PENGUIN(Feld[newx][newy]))
  5745.       {
  5746.     if (DigField(local_player, x, y, newx, newy, 0,0, DF_DIG) == MF_MOVING)
  5747.       DrawLevelField(newx, newy);
  5748.     else
  5749.       GfxDir[x][y] = MovDir[x][y] = MV_NO_MOVING;
  5750.       }
  5751.       else if (!IS_FREE(newx, newy))
  5752.       {
  5753.     GfxAction[x][y] = ACTION_WAITING;
  5754.  
  5755.     if (IS_PLAYER(x, y))
  5756.       DrawPlayerField(x, y);
  5757.     else
  5758.       DrawLevelField(x, y);
  5759.  
  5760.     return;
  5761.       }
  5762.     }
  5763.     else if (element == EL_PIG && IN_LEV_FIELD(newx, newy))
  5764.     {
  5765.       if (IS_FOOD_PIG(Feld[newx][newy]))
  5766.       {
  5767.     if (IS_MOVING(newx, newy))
  5768.       RemoveMovingField(newx, newy);
  5769.     else
  5770.     {
  5771.       Feld[newx][newy] = EL_EMPTY;
  5772.       DrawLevelField(newx, newy);
  5773.     }
  5774.  
  5775.     PlayLevelSound(x, y, SND_PIG_DIGGING);
  5776.       }
  5777.       else if (!IS_FREE(newx, newy))
  5778.       {
  5779.     if (IS_PLAYER(x, y))
  5780.       DrawPlayerField(x, y);
  5781.     else
  5782.       DrawLevelField(x, y);
  5783.  
  5784.     return;
  5785.       }
  5786.     }
  5787.  
  5788. #if 1
  5789.  
  5790.     /*
  5791.     else if (move_pattern & MV_MAZE_RUNNER_STYLE && IN_LEV_FIELD(newx, newy))
  5792.     */
  5793.  
  5794.     else if (IS_CUSTOM_ELEMENT(element) &&
  5795.          CUSTOM_ELEMENT_CAN_ENTER_FIELD(element, newx, newy)
  5796.  
  5797. #if 0
  5798.  &&
  5799.          !IS_FREE(newx, newy)
  5800. #endif
  5801.  
  5802. )
  5803.     {
  5804.       int new_element = Feld[newx][newy];
  5805.  
  5806. #if 0
  5807.       printf("::: '%s' digs '%s' [%d]\n",
  5808.          element_info[element].token_name,
  5809.          element_info[Feld[newx][newy]].token_name,
  5810.          StorePlayer[newx][newy]);
  5811. #endif
  5812.  
  5813.       if (!IS_FREE(newx, newy))
  5814.       {
  5815.     int action = (IS_DIGGABLE(new_element) ? ACTION_DIGGING :
  5816.               IS_COLLECTIBLE(new_element) ? ACTION_COLLECTING :
  5817.               ACTION_BREAKING);
  5818.  
  5819.     /* no element can dig solid indestructible elements */
  5820.     if (IS_INDESTRUCTIBLE(new_element) &&
  5821.         !IS_DIGGABLE(new_element) &&
  5822.         !IS_COLLECTIBLE(new_element))
  5823.       return;
  5824.  
  5825.     if (AmoebaNr[newx][newy] &&
  5826.         (new_element == EL_AMOEBA_FULL ||
  5827.          new_element == EL_BD_AMOEBA ||
  5828.          new_element == EL_AMOEBA_GROWING))
  5829.     {
  5830.       AmoebaCnt[AmoebaNr[newx][newy]]--;
  5831.       AmoebaCnt2[AmoebaNr[newx][newy]]--;
  5832.     }
  5833.  
  5834.     if (IS_MOVING(newx, newy))
  5835.       RemoveMovingField(newx, newy);
  5836.     else
  5837.     {
  5838.       RemoveField(newx, newy);
  5839.       DrawLevelField(newx, newy);
  5840.     }
  5841.  
  5842.     /* if digged element was about to explode, prevent the explosion */
  5843.     ExplodeField[newx][newy] = EX_TYPE_NONE;
  5844.  
  5845.     PlayLevelSoundAction(x, y, action);
  5846.       }
  5847.  
  5848. #if 1
  5849. #if 1
  5850.       Store[newx][newy] = EL_EMPTY;
  5851.       if (IS_EQUAL_OR_IN_GROUP(new_element, MOVE_ENTER_EL(element)))
  5852.     Store[newx][newy] = element_info[element].move_leave_element;
  5853. #else
  5854.       Store[newx][newy] = EL_EMPTY;
  5855.       if (IS_EQUAL_OR_IN_GROUP(new_element, MOVE_ENTER_EL(element)) ||
  5856.       element_info[element].move_leave_type == LEAVE_TYPE_UNLIMITED)
  5857.     Store[newx][newy] = element_info[element].move_leave_element;
  5858. #endif
  5859. #else
  5860.       if (IS_EQUAL_OR_IN_GROUP(new_element, MOVE_ENTER_EL(element)))
  5861.     element_info[element].can_leave_element = TRUE;
  5862. #endif
  5863.  
  5864.       if (move_pattern & MV_MAZE_RUNNER_STYLE)
  5865.       {
  5866.     RunnerVisit[x][y] = FrameCounter;
  5867.     PlayerVisit[x][y] /= 8;        /* expire player visit path */
  5868.       }
  5869.     }
  5870.  
  5871. #endif
  5872.  
  5873.     else if (element == EL_DRAGON && IN_LEV_FIELD(newx, newy))
  5874.     {
  5875.       if (!IS_FREE(newx, newy))
  5876.       {
  5877.     if (IS_PLAYER(x, y))
  5878.       DrawPlayerField(x, y);
  5879.     else
  5880.       DrawLevelField(x, y);
  5881.  
  5882.     return;
  5883.       }
  5884.       else
  5885.       {
  5886.     boolean wanna_flame = !RND(10);
  5887.     int dx = newx - x, dy = newy - y;
  5888.     int newx1 = newx + 1 * dx, newy1 = newy + 1 * dy;
  5889.     int newx2 = newx + 2 * dx, newy2 = newy + 2 * dy;
  5890.     int element1 = (IN_LEV_FIELD(newx1, newy1) ?
  5891.             MovingOrBlocked2Element(newx1, newy1) : EL_STEELWALL);
  5892.     int element2 = (IN_LEV_FIELD(newx2, newy2) ?
  5893.             MovingOrBlocked2Element(newx2, newy2) : EL_STEELWALL);
  5894.  
  5895.     if ((wanna_flame ||
  5896.          IS_CLASSIC_ENEMY(element1) ||
  5897.          IS_CLASSIC_ENEMY(element2)) &&
  5898.         element1 != EL_DRAGON && element2 != EL_DRAGON &&
  5899.         element1 != EL_FLAMES && element2 != EL_FLAMES)
  5900.     {
  5901. #if 1
  5902.       ResetGfxAnimation(x, y);
  5903.       GfxAction[x][y] = ACTION_ATTACKING;
  5904. #endif
  5905.  
  5906.       if (IS_PLAYER(x, y))
  5907.         DrawPlayerField(x, y);
  5908.       else
  5909.         DrawLevelField(x, y);
  5910.  
  5911.       PlayLevelSound(x, y, SND_DRAGON_ATTACKING);
  5912.  
  5913.       MovDelay[x][y] = 50;
  5914.  
  5915.       /* !!! */
  5916. #if 0
  5917.       RemoveField(newx, newy);
  5918. #endif
  5919.       Feld[newx][newy] = EL_FLAMES;
  5920.       if (IN_LEV_FIELD(newx1, newy1) && Feld[newx1][newy1] == EL_EMPTY)
  5921.       {
  5922. #if 0
  5923.         RemoveField(newx1, newy1);
  5924. #endif
  5925.         Feld[newx1][newy1] = EL_FLAMES;
  5926.       }
  5927.       if (IN_LEV_FIELD(newx2, newy2) && Feld[newx2][newy2] == EL_EMPTY)
  5928.       {
  5929. #if 0
  5930.         RemoveField(newx2, newy2);
  5931. #endif
  5932.         Feld[newx2][newy2] = EL_FLAMES;
  5933.       }
  5934.  
  5935.       return;
  5936.     }
  5937.       }
  5938.     }
  5939.     else if (element == EL_YAMYAM && IN_LEV_FIELD(newx, newy) &&
  5940.          Feld[newx][newy] == EL_DIAMOND)
  5941.     {
  5942.       if (IS_MOVING(newx, newy))
  5943.     RemoveMovingField(newx, newy);
  5944.       else
  5945.       {
  5946.     Feld[newx][newy] = EL_EMPTY;
  5947.     DrawLevelField(newx, newy);
  5948.       }
  5949.  
  5950.       PlayLevelSound(x, y, SND_YAMYAM_DIGGING);
  5951.     }
  5952.     else if (element == EL_DARK_YAMYAM && IN_LEV_FIELD(newx, newy) &&
  5953.          IS_FOOD_DARK_YAMYAM(Feld[newx][newy]))
  5954.     {
  5955.       if (AmoebaNr[newx][newy])
  5956.       {
  5957.     AmoebaCnt2[AmoebaNr[newx][newy]]--;
  5958.     if (Feld[newx][newy] == EL_AMOEBA_FULL ||
  5959.         Feld[newx][newy] == EL_BD_AMOEBA)
  5960.       AmoebaCnt[AmoebaNr[newx][newy]]--;
  5961.       }
  5962.  
  5963. #if 0
  5964.       /* !!! test !!! */
  5965.       if (IS_MOVING(newx, newy) || IS_BLOCKED(newx, newy))
  5966. #else
  5967.       if (IS_MOVING(newx, newy))
  5968. #endif
  5969.       {
  5970.     RemoveMovingField(newx, newy);
  5971.       }
  5972.       else
  5973.       {
  5974.     Feld[newx][newy] = EL_EMPTY;
  5975.     DrawLevelField(newx, newy);
  5976.       }
  5977.  
  5978.       PlayLevelSound(x, y, SND_DARK_YAMYAM_DIGGING);
  5979.     }
  5980.     else if ((element == EL_PACMAN || element == EL_MOLE)
  5981.          && IN_LEV_FIELD(newx, newy) && IS_AMOEBOID(Feld[newx][newy]))
  5982.     {
  5983.       if (AmoebaNr[newx][newy])
  5984.       {
  5985.     AmoebaCnt2[AmoebaNr[newx][newy]]--;
  5986.     if (Feld[newx][newy] == EL_AMOEBA_FULL ||
  5987.         Feld[newx][newy] == EL_BD_AMOEBA)
  5988.       AmoebaCnt[AmoebaNr[newx][newy]]--;
  5989.       }
  5990.  
  5991.       if (element == EL_MOLE)
  5992.       {
  5993.     Feld[newx][newy] = EL_AMOEBA_SHRINKING;
  5994.     PlayLevelSound(x, y, SND_MOLE_DIGGING);
  5995.  
  5996.     ResetGfxAnimation(x, y);
  5997.     GfxAction[x][y] = ACTION_DIGGING;
  5998.     DrawLevelField(x, y);
  5999.  
  6000.     MovDelay[newx][newy] = 0;    /* start amoeba shrinking delay */
  6001.  
  6002.     return;                /* wait for shrinking amoeba */
  6003.       }
  6004.       else    /* element == EL_PACMAN */
  6005.       {
  6006.     Feld[newx][newy] = EL_EMPTY;
  6007.     DrawLevelField(newx, newy);
  6008.     PlayLevelSound(x, y, SND_PACMAN_DIGGING);
  6009.       }
  6010.     }
  6011.     else if (element == EL_MOLE && IN_LEV_FIELD(newx, newy) &&
  6012.          (Feld[newx][newy] == EL_AMOEBA_SHRINKING ||
  6013.           (Feld[newx][newy] == EL_EMPTY && Stop[newx][newy])))
  6014.     {
  6015.       /* wait for shrinking amoeba to completely disappear */
  6016.       return;
  6017.     }
  6018.     else if (!IN_LEV_FIELD(newx, newy) || !IS_FREE(newx, newy))
  6019.     {
  6020.       /* object was running against a wall */
  6021.  
  6022.       TurnRound(x, y);
  6023.  
  6024. #if 0
  6025.       if (move_pattern & MV_ANY_DIRECTION &&
  6026.       move_pattern == MovDir[x][y])
  6027.       {
  6028.     int blocking_element =
  6029.       (IN_LEV_FIELD(newx, newy) ? Feld[newx][newy] : BorderElement);
  6030.  
  6031. #if 0
  6032.     printf("::: '%s' is blocked by '%s'! [%d,%d -> %d,%d]\n",
  6033.            element_info[element].token_name,
  6034.            element_info[blocking_element].token_name,
  6035.            x, y, newx, newy);
  6036. #endif
  6037.  
  6038.     CheckElementChangeBySide(x, y, element, blocking_element, CE_BLOCKED,
  6039.                  MovDir[x][y]);
  6040.  
  6041.     element = Feld[x][y];    /* element might have changed */
  6042.       }
  6043. #endif
  6044.  
  6045. #if 1
  6046.       if (GFX_ELEMENT(element) != EL_SAND)     /* !!! FIX THIS (crumble) !!! */
  6047.     DrawLevelElementAnimation(x, y, element);
  6048. #else
  6049.       if (element == EL_BUG ||
  6050.       element == EL_SPACESHIP ||
  6051.       element == EL_SP_SNIKSNAK)
  6052.     DrawLevelField(x, y);
  6053.       else if (element == EL_MOLE)
  6054.     DrawLevelField(x, y);
  6055.       else if (element == EL_BD_BUTTERFLY ||
  6056.            element == EL_BD_FIREFLY)
  6057.     DrawLevelElementAnimationIfNeeded(x, y, element);
  6058.       else if (element == EL_SATELLITE)
  6059.     DrawLevelElementAnimationIfNeeded(x, y, element);
  6060.       else if (element == EL_SP_ELECTRON)
  6061.     DrawLevelElementAnimationIfNeeded(x, y, element);
  6062. #endif
  6063.  
  6064.       if (DONT_TOUCH(element))
  6065.     TestIfBadThingTouchesHero(x, y);
  6066.  
  6067. #if 0
  6068.       PlayLevelSoundAction(x, y, ACTION_WAITING);
  6069. #endif
  6070.  
  6071.       return;
  6072.     }
  6073.  
  6074.     InitMovingField(x, y, MovDir[x][y]);
  6075.  
  6076.     PlayLevelSoundAction(x, y, ACTION_MOVING);
  6077.   }
  6078.  
  6079.   if (MovDir[x][y])
  6080.     ContinueMoving(x, y);
  6081. }
  6082.  
  6083. void ContinueMoving(int x, int y)
  6084. {
  6085.   int element = Feld[x][y];
  6086.   int stored = Store[x][y];
  6087.   struct ElementInfo *ei = &element_info[element];
  6088.   int direction = MovDir[x][y];
  6089.   int dx = (direction == MV_LEFT ? -1 : direction == MV_RIGHT ? +1 : 0);
  6090.   int dy = (direction == MV_UP   ? -1 : direction == MV_DOWN  ? +1 : 0);
  6091.   int newx = x + dx, newy = y + dy;
  6092. #if 0
  6093.   int nextx = newx + dx, nexty = newy + dy;
  6094. #endif
  6095. #if 1
  6096.   boolean pushed_by_player   = (Pushed[x][y] && IS_PLAYER(x, y));
  6097.   boolean pushed_by_conveyor = (Pushed[x][y] && !IS_PLAYER(x, y));
  6098. #else
  6099.   boolean pushed_by_player = Pushed[x][y];
  6100. #endif
  6101.  
  6102.   MovPos[x][y] += getElementMoveStepsize(x, y);
  6103.  
  6104. #if 0
  6105.   if (pushed_by_player && IS_PLAYER(x, y))
  6106.   {
  6107.     /* special case: moving object pushed by player */
  6108.     MovPos[x][y] = SIGN(MovPos[x][y]) * (TILEX - ABS(PLAYERINFO(x,y)->MovPos));
  6109.   }
  6110. #else
  6111.   if (pushed_by_player)    /* special case: moving object pushed by player */
  6112.     MovPos[x][y] = SIGN(MovPos[x][y]) * (TILEX - ABS(PLAYERINFO(x,y)->MovPos));
  6113. #endif
  6114.  
  6115.   if (ABS(MovPos[x][y]) < TILEX)
  6116.   {
  6117.     DrawLevelField(x, y);
  6118.  
  6119.     return;    /* element is still moving */
  6120.   }
  6121.  
  6122.   /* element reached destination field */
  6123.  
  6124.   Feld[x][y] = EL_EMPTY;
  6125.   Feld[newx][newy] = element;
  6126.   MovPos[x][y] = 0;    /* force "not moving" for "crumbled sand" */
  6127.  
  6128. #if 1
  6129.   if (Store[x][y] == EL_ACID)    /* element is moving into acid pool */
  6130.   {
  6131.     element = Feld[newx][newy] = EL_ACID;
  6132.   }
  6133. #endif
  6134.   else if (element == EL_MOLE)
  6135.   {
  6136.     Feld[x][y] = EL_SAND;
  6137.  
  6138.     DrawLevelFieldCrumbledSandNeighbours(x, y);
  6139.   }
  6140.   else if (element == EL_QUICKSAND_FILLING)
  6141.   {
  6142.     element = Feld[newx][newy] = get_next_element(element);
  6143.     Store[newx][newy] = Store[x][y];
  6144.   }
  6145.   else if (element == EL_QUICKSAND_EMPTYING)
  6146.   {
  6147.     Feld[x][y] = get_next_element(element);
  6148.     element = Feld[newx][newy] = Store[x][y];
  6149.   }
  6150.   else if (element == EL_MAGIC_WALL_FILLING)
  6151.   {
  6152.     element = Feld[newx][newy] = get_next_element(element);
  6153.     if (!game.magic_wall_active)
  6154.       element = Feld[newx][newy] = EL_MAGIC_WALL_DEAD;
  6155.     Store[newx][newy] = Store[x][y];
  6156.   }
  6157.   else if (element == EL_MAGIC_WALL_EMPTYING)
  6158.   {
  6159.     Feld[x][y] = get_next_element(element);
  6160.     if (!game.magic_wall_active)
  6161.       Feld[x][y] = EL_MAGIC_WALL_DEAD;
  6162.     element = Feld[newx][newy] = Store[x][y];
  6163.   }
  6164.   else if (element == EL_BD_MAGIC_WALL_FILLING)
  6165.   {
  6166.     element = Feld[newx][newy] = get_next_element(element);
  6167.     if (!game.magic_wall_active)
  6168.       element = Feld[newx][newy] = EL_BD_MAGIC_WALL_DEAD;
  6169.     Store[newx][newy] = Store[x][y];
  6170.   }
  6171.   else if (element == EL_BD_MAGIC_WALL_EMPTYING)
  6172.   {
  6173.     Feld[x][y] = get_next_element(element);
  6174.     if (!game.magic_wall_active)
  6175.       Feld[x][y] = EL_BD_MAGIC_WALL_DEAD;
  6176.     element = Feld[newx][newy] = Store[x][y];
  6177.   }
  6178.   else if (element == EL_AMOEBA_DROPPING)
  6179.   {
  6180.     Feld[x][y] = get_next_element(element);
  6181.     element = Feld[newx][newy] = Store[x][y];
  6182.   }
  6183.   else if (element == EL_SOKOBAN_OBJECT)
  6184.   {
  6185.     if (Back[x][y])
  6186.       Feld[x][y] = Back[x][y];
  6187.  
  6188.     if (Back[newx][newy])
  6189.       Feld[newx][newy] = EL_SOKOBAN_FIELD_FULL;
  6190.  
  6191.     Back[x][y] = Back[newx][newy] = 0;
  6192.   }
  6193. #if 0
  6194.   else if (Store[x][y] == EL_ACID)
  6195.   {
  6196.     element = Feld[newx][newy] = EL_ACID;
  6197.   }
  6198. #endif
  6199. #if 0
  6200.   else if (IS_CUSTOM_ELEMENT(element) && !IS_PLAYER(x, y) &&
  6201.        ei->move_leave_element != EL_EMPTY &&
  6202.        (ei->move_leave_type == LEAVE_TYPE_UNLIMITED ||
  6203.         Store[x][y] != EL_EMPTY))
  6204.   {
  6205.     /* some elements can leave other elements behind after moving */
  6206.  
  6207.     Feld[x][y] = ei->move_leave_element;
  6208.     InitField(x, y, FALSE);
  6209.  
  6210.     if (GFX_CRUMBLED(Feld[x][y]))
  6211.       DrawLevelFieldCrumbledSandNeighbours(x, y);
  6212.   }
  6213. #endif
  6214.  
  6215.   Store[x][y] = EL_EMPTY;
  6216.   MovPos[x][y] = MovDir[x][y] = MovDelay[x][y] = 0;
  6217.   MovDelay[newx][newy] = 0;
  6218.  
  6219.   if (CAN_CHANGE(element))
  6220.   {
  6221.     /* copy element change control values to new field */
  6222.     ChangeDelay[newx][newy] = ChangeDelay[x][y];
  6223.     ChangePage[newx][newy]  = ChangePage[x][y];
  6224.     Changed[newx][newy]     = Changed[x][y];
  6225.     ChangeEvent[newx][newy] = ChangeEvent[x][y];
  6226.   }
  6227.  
  6228.   ChangeDelay[x][y] = 0;
  6229.   ChangePage[x][y] = -1;
  6230.   Changed[x][y] = CE_BITMASK_DEFAULT;
  6231.   ChangeEvent[x][y] = CE_BITMASK_DEFAULT;
  6232.  
  6233.   /* copy animation control values to new field */
  6234.   GfxFrame[newx][newy]  = GfxFrame[x][y];
  6235.   GfxRandom[newx][newy] = GfxRandom[x][y];    /* keep same random value */
  6236.   GfxAction[newx][newy] = GfxAction[x][y];    /* keep action one frame  */
  6237.   GfxDir[newx][newy]    = GfxDir[x][y];        /* keep element direction */
  6238.  
  6239.   Pushed[x][y] = Pushed[newx][newy] = FALSE;
  6240.  
  6241.   ResetGfxAnimation(x, y);    /* reset animation values for old field */
  6242.  
  6243. #if 1
  6244.   /* some elements can leave other elements behind after moving */
  6245. #if 1
  6246.   if (IS_CUSTOM_ELEMENT(element) && ei->move_leave_element != EL_EMPTY &&
  6247.       (ei->move_leave_type == LEAVE_TYPE_UNLIMITED || stored != EL_EMPTY) &&
  6248.       (!IS_PLAYER(x, y) || IS_WALKABLE(ei->move_leave_element)))
  6249. #else
  6250.   if (IS_CUSTOM_ELEMENT(element) && ei->move_leave_element != EL_EMPTY &&
  6251.       (ei->move_leave_type == LEAVE_TYPE_UNLIMITED || stored != EL_EMPTY) &&
  6252.       !IS_PLAYER(x, y))
  6253. #endif
  6254.   {
  6255.     int move_leave_element = ei->move_leave_element;
  6256.  
  6257.     Feld[x][y] = move_leave_element;
  6258.     InitField(x, y, FALSE);
  6259.  
  6260.     if (GFX_CRUMBLED(Feld[x][y]))
  6261.       DrawLevelFieldCrumbledSandNeighbours(x, y);
  6262.  
  6263.     if (ELEM_IS_PLAYER(move_leave_element))
  6264.       RelocatePlayer(x, y, move_leave_element);
  6265.   }
  6266. #endif
  6267.  
  6268. #if 0
  6269.   /* some elements can leave other elements behind after moving */
  6270.   if (IS_CUSTOM_ELEMENT(element) && !IS_PLAYER(x, y) &&
  6271.       ei->move_leave_element != EL_EMPTY &&
  6272.       (ei->move_leave_type == LEAVE_TYPE_UNLIMITED ||
  6273.        ei->can_leave_element_last))
  6274.   {
  6275.     Feld[x][y] = ei->move_leave_element;
  6276.     InitField(x, y, FALSE);
  6277.  
  6278.     if (GFX_CRUMBLED(Feld[x][y]))
  6279.       DrawLevelFieldCrumbledSandNeighbours(x, y);
  6280.   }
  6281.  
  6282.   ei->can_leave_element_last = ei->can_leave_element;
  6283.   ei->can_leave_element = FALSE;
  6284. #endif
  6285.  
  6286. #if 0
  6287.   /* 2.1.1 (does not work correctly for spring) */
  6288.   if (!CAN_MOVE(element))
  6289.     MovDir[newx][newy] = 0;
  6290. #else
  6291.  
  6292. #if 0
  6293.   /* (does not work for falling objects that slide horizontally) */
  6294.   if (CAN_FALL(element) && MovDir[newx][newy] == MV_DOWN)
  6295.     MovDir[newx][newy] = 0;
  6296. #else
  6297.   /*
  6298.   if (!CAN_MOVE(element) ||
  6299.       (element == EL_SPRING && MovDir[newx][newy] == MV_DOWN))
  6300.     MovDir[newx][newy] = 0;
  6301.   */
  6302.  
  6303. #if 0
  6304.   if (!CAN_MOVE(element) ||
  6305.       (CAN_FALL(element) && direction == MV_DOWN))
  6306.     GfxDir[x][y] = MovDir[newx][newy] = 0;
  6307. #else
  6308.   if (!CAN_MOVE(element) ||
  6309.       (CAN_FALL(element) && direction == MV_DOWN &&
  6310.        (element == EL_SPRING ||
  6311.     element_info[element].move_pattern == MV_WHEN_PUSHED ||
  6312.     element_info[element].move_pattern == MV_WHEN_DROPPED)))
  6313.     GfxDir[x][y] = MovDir[newx][newy] = 0;
  6314. #endif
  6315.  
  6316. #endif
  6317. #endif
  6318.  
  6319.   DrawLevelField(x, y);
  6320.   DrawLevelField(newx, newy);
  6321.  
  6322.   Stop[newx][newy] = TRUE;    /* ignore this element until the next frame */
  6323.  
  6324.   /* prevent pushed element from moving on in pushed direction */
  6325.   if (pushed_by_player && CAN_MOVE(element) &&
  6326.       element_info[element].move_pattern & MV_ANY_DIRECTION &&
  6327.       !(element_info[element].move_pattern & direction))
  6328.     TurnRound(newx, newy);
  6329.  
  6330. #if 1
  6331.   /* prevent elements on conveyor belt from moving on in last direction */
  6332.   if (pushed_by_conveyor && CAN_FALL(element) &&
  6333.       direction & MV_HORIZONTAL)
  6334.   {
  6335. #if 0
  6336.     if (CAN_MOVE(element))
  6337.       InitMovDir(newx, newy);
  6338.     else
  6339.       MovDir[newx][newy] = 0;
  6340. #else
  6341.     MovDir[newx][newy] = 0;
  6342. #endif
  6343.   }
  6344. #endif
  6345.  
  6346.   if (!pushed_by_player)
  6347.   {
  6348.     int nextx = newx + dx, nexty = newy + dy;
  6349.     boolean check_collision_again = IN_LEV_FIELD_AND_IS_FREE(nextx, nexty);
  6350.  
  6351.     WasJustMoving[newx][newy] = 3;
  6352.  
  6353.     if (CAN_FALL(element) && direction == MV_DOWN)
  6354.       WasJustFalling[newx][newy] = 3;
  6355.  
  6356.     if ((!CAN_FALL(element) || direction == MV_DOWN) && check_collision_again)
  6357.       CheckCollision[newx][newy] = 2;
  6358.   }
  6359.  
  6360.   if (DONT_TOUCH(element))    /* object may be nasty to player or others */
  6361.   {
  6362.     TestIfBadThingTouchesHero(newx, newy);
  6363.     TestIfBadThingTouchesFriend(newx, newy);
  6364.  
  6365.     if (!IS_CUSTOM_ELEMENT(element))
  6366.       TestIfBadThingTouchesOtherBadThing(newx, newy);
  6367.   }
  6368.   else if (element == EL_PENGUIN)
  6369.     TestIfFriendTouchesBadThing(newx, newy);
  6370.  
  6371.   if (CAN_FALL(element) && direction == MV_DOWN &&
  6372.       (newy == lev_fieldy - 1 || !IS_FREE(x, newy + 1)))
  6373.     Impact(x, newy);
  6374.  
  6375. #if 1
  6376.   if (pushed_by_player)
  6377.   {
  6378. #if 1
  6379.     int dig_side = MV_DIR_OPPOSITE(direction);
  6380. #else
  6381.     static int trigger_sides[4] =
  6382.     {
  6383.       CH_SIDE_RIGHT,    /* moving left  */
  6384.       CH_SIDE_LEFT,    /* moving right */
  6385.       CH_SIDE_BOTTOM,    /* moving up    */
  6386.       CH_SIDE_TOP,    /* moving down  */
  6387.     };
  6388.     int dig_side = trigger_sides[MV_DIR_BIT(direction)];
  6389. #endif
  6390.     struct PlayerInfo *player = PLAYERINFO(x, y);
  6391.  
  6392.     CheckElementChangeByPlayer(newx, newy, element, CE_PUSHED_BY_PLAYER,
  6393.                    player->index_bit, dig_side);
  6394.     CheckTriggeredElementChangeByPlayer(newx,newy,element,CE_OTHER_GETS_PUSHED,
  6395.                     player->index_bit, dig_side);
  6396.   }
  6397. #endif
  6398.  
  6399. #if 1
  6400.   TestIfElementTouchesCustomElement(x, y);    /* empty or new element */
  6401. #endif
  6402.  
  6403. #if 0
  6404.   if (ChangePage[newx][newy] != -1)            /* delayed change */
  6405.     ChangeElement(newx, newy, ChangePage[newx][newy]);
  6406. #endif
  6407.  
  6408. #if 1
  6409.  
  6410.   TestIfElementHitsCustomElement(newx, newy, direction);
  6411.  
  6412. #else
  6413.  
  6414.   if (!IN_LEV_FIELD(nextx, nexty) || !IS_FREE(nextx, nexty))
  6415.   {
  6416.     int hitting_element = Feld[newx][newy];
  6417.  
  6418.     /* !!! fix side (direction) orientation here and elsewhere !!! */
  6419.     CheckElementChangeBySide(newx, newy, hitting_element, CE_HITTING_SOMETHING,
  6420.                  direction);
  6421.  
  6422. #if 0
  6423.     if (IN_LEV_FIELD(nextx, nexty))
  6424.     {
  6425.       int opposite_direction = MV_DIR_OPPOSITE(direction);
  6426.       int hitting_side = direction;
  6427.       int touched_side = opposite_direction;
  6428.       int touched_element = MovingOrBlocked2Element(nextx, nexty);
  6429.       boolean object_hit = (!IS_MOVING(nextx, nexty) ||
  6430.                 MovDir[nextx][nexty] != direction ||
  6431.                 ABS(MovPos[nextx][nexty]) <= TILEY / 2);
  6432.  
  6433.       if (object_hit)
  6434.       {
  6435.     int i;
  6436.  
  6437.     CheckElementChangeBySide(nextx, nexty, touched_element,
  6438.                  CE_HIT_BY_SOMETHING, opposite_direction);
  6439.  
  6440.     if (IS_CUSTOM_ELEMENT(hitting_element) &&
  6441.         HAS_ANY_CHANGE_EVENT(hitting_element, CE_OTHER_IS_HITTING))
  6442.     {
  6443.       for (i = 0; i < element_info[hitting_element].num_change_pages; i++)
  6444.       {
  6445.         struct ElementChangeInfo *change =
  6446.           &element_info[hitting_element].change_page[i];
  6447.  
  6448.         if (change->can_change &&
  6449.         change->events & CH_EVENT_BIT(CE_OTHER_IS_HITTING) &&
  6450.         change->trigger_side & touched_side &&
  6451.         change->trigger_element == touched_element)
  6452.         {
  6453.           CheckElementChangeByPage(newx, newy, hitting_element,
  6454.                        touched_element, CE_OTHER_IS_HITTING,i);
  6455.           break;
  6456.         }
  6457.       }
  6458.     }
  6459.  
  6460.     if (IS_CUSTOM_ELEMENT(touched_element) &&
  6461.         HAS_ANY_CHANGE_EVENT(touched_element, CE_OTHER_GETS_HIT))
  6462.     {
  6463.       for (i = 0; i < element_info[touched_element].num_change_pages; i++)
  6464.       {
  6465.         struct ElementChangeInfo *change =
  6466.           &element_info[touched_element].change_page[i];
  6467.  
  6468.         if (change->can_change &&
  6469.         change->events & CH_EVENT_BIT(CE_OTHER_GETS_HIT) &&
  6470.         change->trigger_side & hitting_side &&
  6471.         change->trigger_element == hitting_element)
  6472.         {
  6473.           CheckElementChangeByPage(nextx, nexty, touched_element,
  6474.                        hitting_element, CE_OTHER_GETS_HIT, i);
  6475.           break;
  6476.         }
  6477.       }
  6478.     }
  6479.       }
  6480.     }
  6481. #endif
  6482.   }
  6483. #endif
  6484.  
  6485.   TestIfPlayerTouchesCustomElement(newx, newy);
  6486.   TestIfElementTouchesCustomElement(newx, newy);
  6487. }
  6488.  
  6489. int AmoebeNachbarNr(int ax, int ay)
  6490. {
  6491.   int i;
  6492.   int element = Feld[ax][ay];
  6493.   int group_nr = 0;
  6494.   static int xy[4][2] =
  6495.   {
  6496.     { 0, -1 },
  6497.     { -1, 0 },
  6498.     { +1, 0 },
  6499.     { 0, +1 }
  6500.   };
  6501.  
  6502.   for (i = 0; i < NUM_DIRECTIONS; i++)
  6503.   {
  6504.     int x = ax + xy[i][0];
  6505.     int y = ay + xy[i][1];
  6506.  
  6507.     if (!IN_LEV_FIELD(x, y))
  6508.       continue;
  6509.  
  6510.     if (Feld[x][y] == element && AmoebaNr[x][y] > 0)
  6511.       group_nr = AmoebaNr[x][y];
  6512.   }
  6513.  
  6514.   return group_nr;
  6515. }
  6516.  
  6517. void AmoebenVereinigen(int ax, int ay)
  6518. {
  6519.   int i, x, y, xx, yy;
  6520.   int new_group_nr = AmoebaNr[ax][ay];
  6521.   static int xy[4][2] =
  6522.   {
  6523.     { 0, -1 },
  6524.     { -1, 0 },
  6525.     { +1, 0 },
  6526.     { 0, +1 }
  6527.   };
  6528.  
  6529.   if (new_group_nr == 0)
  6530.     return;
  6531.  
  6532.   for (i = 0; i < NUM_DIRECTIONS; i++)
  6533.   {
  6534.     x = ax + xy[i][0];
  6535.     y = ay + xy[i][1];
  6536.  
  6537.     if (!IN_LEV_FIELD(x, y))
  6538.       continue;
  6539.  
  6540.     if ((Feld[x][y] == EL_AMOEBA_FULL ||
  6541.      Feld[x][y] == EL_BD_AMOEBA ||
  6542.      Feld[x][y] == EL_AMOEBA_DEAD) &&
  6543.     AmoebaNr[x][y] != new_group_nr)
  6544.     {
  6545.       int old_group_nr = AmoebaNr[x][y];
  6546.  
  6547.       if (old_group_nr == 0)
  6548.     return;
  6549.  
  6550.       AmoebaCnt[new_group_nr] += AmoebaCnt[old_group_nr];
  6551.       AmoebaCnt[old_group_nr] = 0;
  6552.       AmoebaCnt2[new_group_nr] += AmoebaCnt2[old_group_nr];
  6553.       AmoebaCnt2[old_group_nr] = 0;
  6554.  
  6555.       for (yy = 0; yy < lev_fieldy; yy++)
  6556.       {
  6557.     for (xx = 0; xx < lev_fieldx; xx++)
  6558.     {
  6559.       if (AmoebaNr[xx][yy] == old_group_nr)
  6560.         AmoebaNr[xx][yy] = new_group_nr;
  6561.     }
  6562.       }
  6563.     }
  6564.   }
  6565. }
  6566.  
  6567. void AmoebeUmwandeln(int ax, int ay)
  6568. {
  6569.   int i, x, y;
  6570.  
  6571.   if (Feld[ax][ay] == EL_AMOEBA_DEAD)
  6572.   {
  6573.     int group_nr = AmoebaNr[ax][ay];
  6574.  
  6575. #ifdef DEBUG
  6576.     if (group_nr == 0)
  6577.     {
  6578.       printf("AmoebeUmwandeln(): ax = %d, ay = %d\n", ax, ay);
  6579.       printf("AmoebeUmwandeln(): This should never happen!\n");
  6580.       return;
  6581.     }
  6582. #endif
  6583.  
  6584.     for (y = 0; y < lev_fieldy; y++)
  6585.     {
  6586.       for (x = 0; x < lev_fieldx; x++)
  6587.       {
  6588.     if (Feld[x][y] == EL_AMOEBA_DEAD && AmoebaNr[x][y] == group_nr)
  6589.     {
  6590.       AmoebaNr[x][y] = 0;
  6591.       Feld[x][y] = EL_AMOEBA_TO_DIAMOND;
  6592.     }
  6593.       }
  6594.     }
  6595.     PlayLevelSound(ax, ay, (IS_GEM(level.amoeba_content) ?
  6596.                 SND_AMOEBA_TURNING_TO_GEM :
  6597.                 SND_AMOEBA_TURNING_TO_ROCK));
  6598.     Bang(ax, ay);
  6599.   }
  6600.   else
  6601.   {
  6602.     static int xy[4][2] =
  6603.     {
  6604.       { 0, -1 },
  6605.       { -1, 0 },
  6606.       { +1, 0 },
  6607.       { 0, +1 }
  6608.     };
  6609.  
  6610.     for (i = 0; i < NUM_DIRECTIONS; i++)
  6611.     {
  6612.       x = ax + xy[i][0];
  6613.       y = ay + xy[i][1];
  6614.  
  6615.       if (!IN_LEV_FIELD(x, y))
  6616.     continue;
  6617.  
  6618.       if (Feld[x][y] == EL_AMOEBA_TO_DIAMOND)
  6619.       {
  6620.     PlayLevelSound(x, y, (IS_GEM(level.amoeba_content) ?
  6621.                   SND_AMOEBA_TURNING_TO_GEM :
  6622.                   SND_AMOEBA_TURNING_TO_ROCK));
  6623.     Bang(x, y);
  6624.       }
  6625.     }
  6626.   }
  6627. }
  6628.  
  6629. void AmoebeUmwandelnBD(int ax, int ay, int new_element)
  6630. {
  6631.   int x, y;
  6632.   int group_nr = AmoebaNr[ax][ay];
  6633.   boolean done = FALSE;
  6634.  
  6635. #ifdef DEBUG
  6636.   if (group_nr == 0)
  6637.   {
  6638.     printf("AmoebeUmwandelnBD(): ax = %d, ay = %d\n", ax, ay);
  6639.     printf("AmoebeUmwandelnBD(): This should never happen!\n");
  6640.     return;
  6641.   }
  6642. #endif
  6643.  
  6644.   for (y = 0; y < lev_fieldy; y++)
  6645.   {
  6646.     for (x = 0; x < lev_fieldx; x++)
  6647.     {
  6648.       if (AmoebaNr[x][y] == group_nr &&
  6649.       (Feld[x][y] == EL_AMOEBA_DEAD ||
  6650.        Feld[x][y] == EL_BD_AMOEBA ||
  6651.        Feld[x][y] == EL_AMOEBA_GROWING))
  6652.       {
  6653.     AmoebaNr[x][y] = 0;
  6654.     Feld[x][y] = new_element;
  6655.     InitField(x, y, FALSE);
  6656.     DrawLevelField(x, y);
  6657.     done = TRUE;
  6658.       }
  6659.     }
  6660.   }
  6661.  
  6662.   if (done)
  6663.     PlayLevelSound(ax, ay, (new_element == EL_BD_ROCK ?
  6664.                 SND_BD_AMOEBA_TURNING_TO_ROCK :
  6665.                 SND_BD_AMOEBA_TURNING_TO_GEM));
  6666. }
  6667.  
  6668. void AmoebeWaechst(int x, int y)
  6669. {
  6670.   static unsigned long sound_delay = 0;
  6671.   static unsigned long sound_delay_value = 0;
  6672.  
  6673.   if (!MovDelay[x][y])        /* start new growing cycle */
  6674.   {
  6675.     MovDelay[x][y] = 7;
  6676.  
  6677.     if (DelayReached(&sound_delay, sound_delay_value))
  6678.     {
  6679. #if 1
  6680.       PlayLevelSoundElementAction(x, y, Store[x][y], ACTION_GROWING);
  6681. #else
  6682.       if (Store[x][y] == EL_BD_AMOEBA)
  6683.     PlayLevelSound(x, y, SND_BD_AMOEBA_GROWING);
  6684.       else
  6685.     PlayLevelSound(x, y, SND_AMOEBA_GROWING);
  6686. #endif
  6687.       sound_delay_value = 30;
  6688.     }
  6689.   }
  6690.  
  6691.   if (MovDelay[x][y])        /* wait some time before growing bigger */
  6692.   {
  6693.     MovDelay[x][y]--;
  6694.     if (MovDelay[x][y]/2 && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
  6695.     {
  6696.       int frame = getGraphicAnimationFrame(IMG_AMOEBA_GROWING,
  6697.                        6 - MovDelay[x][y]);
  6698.  
  6699.       DrawGraphic(SCREENX(x), SCREENY(y), IMG_AMOEBA_GROWING, frame);
  6700.     }
  6701.  
  6702.     if (!MovDelay[x][y])
  6703.     {
  6704.       Feld[x][y] = Store[x][y];
  6705.       Store[x][y] = 0;
  6706.       DrawLevelField(x, y);
  6707.     }
  6708.   }
  6709. }
  6710.  
  6711. void AmoebaDisappearing(int x, int y)
  6712. {
  6713.   static unsigned long sound_delay = 0;
  6714.   static unsigned long sound_delay_value = 0;
  6715.  
  6716.   if (!MovDelay[x][y])        /* start new shrinking cycle */
  6717.   {
  6718.     MovDelay[x][y] = 7;
  6719.  
  6720.     if (DelayReached(&sound_delay, sound_delay_value))
  6721.       sound_delay_value = 30;
  6722.   }
  6723.  
  6724.   if (MovDelay[x][y])        /* wait some time before shrinking */
  6725.   {
  6726.     MovDelay[x][y]--;
  6727.     if (MovDelay[x][y]/2 && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
  6728.     {
  6729.       int frame = getGraphicAnimationFrame(IMG_AMOEBA_SHRINKING,
  6730.                        6 - MovDelay[x][y]);
  6731.  
  6732.       DrawGraphic(SCREENX(x), SCREENY(y), IMG_AMOEBA_SHRINKING, frame);
  6733.     }
  6734.  
  6735.     if (!MovDelay[x][y])
  6736.     {
  6737.       Feld[x][y] = EL_EMPTY;
  6738.       DrawLevelField(x, y);
  6739.  
  6740.       /* don't let mole enter this field in this cycle;
  6741.      (give priority to objects falling to this field from above) */
  6742.       Stop[x][y] = TRUE;
  6743.     }
  6744.   }
  6745. }
  6746.  
  6747. void AmoebeAbleger(int ax, int ay)
  6748. {
  6749.   int i;
  6750.   int element = Feld[ax][ay];
  6751.   int graphic = el2img(element);
  6752.   int newax = ax, neway = ay;
  6753.   static int xy[4][2] =
  6754.   {
  6755.     { 0, -1 },
  6756.     { -1, 0 },
  6757.     { +1, 0 },
  6758.     { 0, +1 }
  6759.   };
  6760.  
  6761.   if (!level.amoeba_speed)
  6762.   {
  6763.     Feld[ax][ay] = EL_AMOEBA_DEAD;
  6764.     DrawLevelField(ax, ay);
  6765.     return;
  6766.   }
  6767.  
  6768.   if (IS_ANIMATED(graphic))
  6769.     DrawLevelGraphicAnimationIfNeeded(ax, ay, graphic);
  6770.  
  6771.   if (!MovDelay[ax][ay])    /* start making new amoeba field */
  6772.     MovDelay[ax][ay] = RND(FRAMES_PER_SECOND * 25 / (1 + level.amoeba_speed));
  6773.  
  6774.   if (MovDelay[ax][ay])        /* wait some time before making new amoeba */
  6775.   {
  6776.     MovDelay[ax][ay]--;
  6777.     if (MovDelay[ax][ay])
  6778.       return;
  6779.   }
  6780.  
  6781.   if (element == EL_AMOEBA_WET)    /* object is an acid / amoeba drop */
  6782.   {
  6783.     int start = RND(4);
  6784.     int x = ax + xy[start][0];
  6785.     int y = ay + xy[start][1];
  6786.  
  6787.     if (!IN_LEV_FIELD(x, y))
  6788.       return;
  6789.  
  6790. #if 1
  6791.     if (IS_FREE(x, y) ||
  6792.     CAN_GROW_INTO(Feld[x][y]) ||
  6793.     Feld[x][y] == EL_QUICKSAND_EMPTY)
  6794.     {
  6795.       newax = x;
  6796.       neway = y;
  6797.     }
  6798. #else
  6799.     /* !!! extend EL_SAND to anything diggable (but maybe not SP_BASE) !!! */
  6800.     if (IS_FREE(x, y) ||
  6801.     Feld[x][y] == EL_SAND || Feld[x][y] == EL_QUICKSAND_EMPTY)
  6802.     {
  6803.       newax = x;
  6804.       neway = y;
  6805.     }
  6806. #endif
  6807.  
  6808.     if (newax == ax && neway == ay)
  6809.       return;
  6810.   }
  6811.   else                /* normal or "filled" (BD style) amoeba */
  6812.   {
  6813.     int start = RND(4);
  6814.     boolean waiting_for_player = FALSE;
  6815.  
  6816.     for (i = 0; i < NUM_DIRECTIONS; i++)
  6817.     {
  6818.       int j = (start + i) % 4;
  6819.       int x = ax + xy[j][0];
  6820.       int y = ay + xy[j][1];
  6821.  
  6822.       if (!IN_LEV_FIELD(x, y))
  6823.     continue;
  6824.  
  6825. #if 1
  6826.       if (IS_FREE(x, y) ||
  6827.       CAN_GROW_INTO(Feld[x][y]) ||
  6828.       Feld[x][y] == EL_QUICKSAND_EMPTY)
  6829.       {
  6830.     newax = x;
  6831.     neway = y;
  6832.     break;
  6833.       }
  6834. #else
  6835.       /* !!! extend EL_SAND to anything diggable (but maybe not SP_BASE) !!! */
  6836.       if (IS_FREE(x, y) ||
  6837.       Feld[x][y] == EL_SAND || Feld[x][y] == EL_QUICKSAND_EMPTY)
  6838.       {
  6839.     newax = x;
  6840.     neway = y;
  6841.     break;
  6842.       }
  6843. #endif
  6844.       else if (IS_PLAYER(x, y))
  6845.     waiting_for_player = TRUE;
  6846.     }
  6847.  
  6848.     if (newax == ax && neway == ay)        /* amoeba cannot grow */
  6849.     {
  6850. #if 1
  6851.       if (i == 4 && (!waiting_for_player || element == EL_BD_AMOEBA))
  6852. #else
  6853.       if (i == 4 && (!waiting_for_player || game.emulation == EMU_BOULDERDASH))
  6854. #endif
  6855.       {
  6856.     Feld[ax][ay] = EL_AMOEBA_DEAD;
  6857.     DrawLevelField(ax, ay);
  6858.     AmoebaCnt[AmoebaNr[ax][ay]]--;
  6859.  
  6860.     if (AmoebaCnt[AmoebaNr[ax][ay]] <= 0)    /* amoeba is completely dead */
  6861.     {
  6862.       if (element == EL_AMOEBA_FULL)
  6863.         AmoebeUmwandeln(ax, ay);
  6864.       else if (element == EL_BD_AMOEBA)
  6865.         AmoebeUmwandelnBD(ax, ay, level.amoeba_content);
  6866.     }
  6867.       }
  6868.       return;
  6869.     }
  6870.     else if (element == EL_AMOEBA_FULL || element == EL_BD_AMOEBA)
  6871.     {
  6872.       /* amoeba gets larger by growing in some direction */
  6873.  
  6874.       int new_group_nr = AmoebaNr[ax][ay];
  6875.  
  6876. #ifdef DEBUG
  6877.   if (new_group_nr == 0)
  6878.   {
  6879.     printf("AmoebeAbleger(): newax = %d, neway = %d\n", newax, neway);
  6880.     printf("AmoebeAbleger(): This should never happen!\n");
  6881.     return;
  6882.   }
  6883. #endif
  6884.  
  6885.       AmoebaNr[newax][neway] = new_group_nr;
  6886.       AmoebaCnt[new_group_nr]++;
  6887.       AmoebaCnt2[new_group_nr]++;
  6888.  
  6889.       /* if amoeba touches other amoeba(s) after growing, unify them */
  6890.       AmoebenVereinigen(newax, neway);
  6891.  
  6892.       if (element == EL_BD_AMOEBA && AmoebaCnt2[new_group_nr] >= 200)
  6893.       {
  6894.     AmoebeUmwandelnBD(newax, neway, EL_BD_ROCK);
  6895.     return;
  6896.       }
  6897.     }
  6898.   }
  6899.  
  6900.   if (element != EL_AMOEBA_WET || neway < ay || !IS_FREE(newax, neway) ||
  6901.       (neway == lev_fieldy - 1 && newax != ax))
  6902.   {
  6903.     Feld[newax][neway] = EL_AMOEBA_GROWING;    /* creation of new amoeba */
  6904.     Store[newax][neway] = element;
  6905.   }
  6906.   else if (neway == ay)
  6907.   {
  6908.     Feld[newax][neway] = EL_AMOEBA_DROP;    /* drop left/right of amoeba */
  6909. #if 1
  6910.     PlayLevelSoundAction(newax, neway, ACTION_GROWING);
  6911. #else
  6912.     PlayLevelSound(newax, neway, SND_AMOEBA_GROWING);
  6913. #endif
  6914.   }
  6915.   else
  6916.   {
  6917.     InitMovingField(ax, ay, MV_DOWN);        /* drop dripping from amoeba */
  6918.     Feld[ax][ay] = EL_AMOEBA_DROPPING;
  6919.     Store[ax][ay] = EL_AMOEBA_DROP;
  6920.     ContinueMoving(ax, ay);
  6921.     return;
  6922.   }
  6923.  
  6924.   DrawLevelField(newax, neway);
  6925. }
  6926.  
  6927. void Life(int ax, int ay)
  6928. {
  6929.   int x1, y1, x2, y2;
  6930.   static int life[4] = { 2, 3, 3, 3 };    /* parameters for "game of life" */
  6931.   int life_time = 40;
  6932.   int element = Feld[ax][ay];
  6933.   int graphic = el2img(element);
  6934.   boolean changed = FALSE;
  6935.  
  6936.   if (IS_ANIMATED(graphic))
  6937.     DrawLevelGraphicAnimationIfNeeded(ax, ay, graphic);
  6938.  
  6939.   if (Stop[ax][ay])
  6940.     return;
  6941.  
  6942.   if (!MovDelay[ax][ay])    /* start new "game of life" cycle */
  6943.     MovDelay[ax][ay] = life_time;
  6944.  
  6945.   if (MovDelay[ax][ay])        /* wait some time before next cycle */
  6946.   {
  6947.     MovDelay[ax][ay]--;
  6948.     if (MovDelay[ax][ay])
  6949.       return;
  6950.   }
  6951.  
  6952.   for (y1 = -1; y1 < 2; y1++) for (x1 = -1; x1 < 2; x1++)
  6953.   {
  6954.     int xx = ax+x1, yy = ay+y1;
  6955.     int nachbarn = 0;
  6956.  
  6957.     if (!IN_LEV_FIELD(xx, yy))
  6958.       continue;
  6959.  
  6960.     for (y2 = -1; y2 < 2; y2++) for (x2 = -1; x2 < 2; x2++)
  6961.     {
  6962.       int x = xx+x2, y = yy+y2;
  6963.  
  6964.       if (!IN_LEV_FIELD(x, y) || (x == xx && y == yy))
  6965.     continue;
  6966.  
  6967.       if (((Feld[x][y] == element ||
  6968.         (element == EL_GAME_OF_LIFE && IS_PLAYER(x, y))) &&
  6969.        !Stop[x][y]) ||
  6970.       (IS_FREE(x, y) && Stop[x][y]))
  6971.     nachbarn++;
  6972.     }
  6973.  
  6974.     if (xx == ax && yy == ay)        /* field in the middle */
  6975.     {
  6976.       if (nachbarn < life[0] || nachbarn > life[1])
  6977.       {
  6978.     Feld[xx][yy] = EL_EMPTY;
  6979.     if (!Stop[xx][yy])
  6980.       DrawLevelField(xx, yy);
  6981.     Stop[xx][yy] = TRUE;
  6982.     changed = TRUE;
  6983.       }
  6984.     }
  6985. #if 1
  6986.     else if (IS_FREE(xx, yy) || CAN_GROW_INTO(Feld[xx][yy]))
  6987.     {                    /* free border field */
  6988.       if (nachbarn >= life[2] && nachbarn <= life[3])
  6989.       {
  6990.     Feld[xx][yy] = element;
  6991.     MovDelay[xx][yy] = (element == EL_GAME_OF_LIFE ? 0 : life_time-1);
  6992.     if (!Stop[xx][yy])
  6993.       DrawLevelField(xx, yy);
  6994.     Stop[xx][yy] = TRUE;
  6995.     changed = TRUE;
  6996.       }
  6997.     }
  6998. #else
  6999.     /* !!! extend EL_SAND to anything diggable (but maybe not SP_BASE) !!! */
  7000.     else if (IS_FREE(xx, yy) || Feld[xx][yy] == EL_SAND)
  7001.     {                    /* free border field */
  7002.       if (nachbarn >= life[2] && nachbarn <= life[3])
  7003.       {
  7004.     Feld[xx][yy] = element;
  7005.     MovDelay[xx][yy] = (element == EL_GAME_OF_LIFE ? 0 : life_time-1);
  7006.     if (!Stop[xx][yy])
  7007.       DrawLevelField(xx, yy);
  7008.     Stop[xx][yy] = TRUE;
  7009.     changed = TRUE;
  7010.       }
  7011.     }
  7012. #endif
  7013.   }
  7014.  
  7015.   if (changed)
  7016.     PlayLevelSound(ax, ay, element == EL_BIOMAZE ? SND_BIOMAZE_GROWING :
  7017.            SND_GAME_OF_LIFE_GROWING);
  7018. }
  7019.  
  7020. static void InitRobotWheel(int x, int y)
  7021. {
  7022.   ChangeDelay[x][y] = level.time_wheel * FRAMES_PER_SECOND;
  7023. }
  7024.  
  7025. static void RunRobotWheel(int x, int y)
  7026. {
  7027.   PlayLevelSound(x, y, SND_ROBOT_WHEEL_ACTIVE);
  7028. }
  7029.  
  7030. static void StopRobotWheel(int x, int y)
  7031. {
  7032.   if (ZX == x && ZY == y)
  7033.     ZX = ZY = -1;
  7034. }
  7035.  
  7036. static void InitTimegateWheel(int x, int y)
  7037. {
  7038. #if 1
  7039.   ChangeDelay[x][y] = level.time_timegate * FRAMES_PER_SECOND;
  7040. #else
  7041.   /* another brainless, "type style" bug ... :-( */
  7042.   ChangeDelay[x][y] = level.time_wheel * FRAMES_PER_SECOND;
  7043. #endif
  7044. }
  7045.  
  7046. static void RunTimegateWheel(int x, int y)
  7047. {
  7048.   PlayLevelSound(x, y, SND_TIMEGATE_SWITCH_ACTIVE);
  7049. }
  7050.  
  7051. void CheckExit(int x, int y)
  7052. {
  7053.   if (local_player->gems_still_needed > 0 ||
  7054.       local_player->sokobanfields_still_needed > 0 ||
  7055.       local_player->lights_still_needed > 0)
  7056.   {
  7057.     int element = Feld[x][y];
  7058.     int graphic = el2img(element);
  7059.  
  7060.     if (IS_ANIMATED(graphic))
  7061.       DrawLevelGraphicAnimationIfNeeded(x, y, graphic);
  7062.  
  7063.     return;
  7064.   }
  7065.  
  7066.   if (AllPlayersGone)    /* do not re-open exit door closed after last player */
  7067.     return;
  7068.  
  7069.   Feld[x][y] = EL_EXIT_OPENING;
  7070.  
  7071.   PlayLevelSoundNearest(x, y, SND_CLASS_EXIT_OPENING);
  7072. }
  7073.  
  7074. void CheckExitSP(int x, int y)
  7075. {
  7076.   if (local_player->gems_still_needed > 0)
  7077.   {
  7078.     int element = Feld[x][y];
  7079.     int graphic = el2img(element);
  7080.  
  7081.     if (IS_ANIMATED(graphic))
  7082.       DrawLevelGraphicAnimationIfNeeded(x, y, graphic);
  7083.  
  7084.     return;
  7085.   }
  7086.  
  7087.   if (AllPlayersGone)    /* do not re-open exit door closed after last player */
  7088.     return;
  7089.  
  7090.   Feld[x][y] = EL_SP_EXIT_OPENING;
  7091.  
  7092.   PlayLevelSoundNearest(x, y, SND_CLASS_SP_EXIT_OPENING);
  7093. }
  7094.  
  7095. static void CloseAllOpenTimegates()
  7096. {
  7097.   int x, y;
  7098.  
  7099.   for (y = 0; y < lev_fieldy; y++)
  7100.   {
  7101.     for (x = 0; x < lev_fieldx; x++)
  7102.     {
  7103.       int element = Feld[x][y];
  7104.  
  7105.       if (element == EL_TIMEGATE_OPEN || element == EL_TIMEGATE_OPENING)
  7106.       {
  7107.     Feld[x][y] = EL_TIMEGATE_CLOSING;
  7108. #if 1
  7109.     PlayLevelSoundAction(x, y, ACTION_CLOSING);
  7110. #else
  7111.     PlayLevelSound(x, y, SND_TIMEGATE_CLOSING);
  7112. #endif
  7113.       }
  7114.     }
  7115.   }
  7116. }
  7117.  
  7118. void EdelsteinFunkeln(int x, int y)
  7119. {
  7120.   if (!IN_SCR_FIELD(SCREENX(x), SCREENY(y)) || IS_MOVING(x, y))
  7121.     return;
  7122.  
  7123.   if (Feld[x][y] == EL_BD_DIAMOND)
  7124.     return;
  7125.  
  7126.   if (MovDelay[x][y] == 0)    /* next animation frame */
  7127.     MovDelay[x][y] = 11 * !SimpleRND(500);
  7128.  
  7129.   if (MovDelay[x][y] != 0)    /* wait some time before next frame */
  7130.   {
  7131.     MovDelay[x][y]--;
  7132.  
  7133.     if (setup.direct_draw && MovDelay[x][y])
  7134.       SetDrawtoField(DRAW_BUFFERED);
  7135.  
  7136.     DrawLevelElementAnimation(x, y, Feld[x][y]);
  7137.  
  7138.     if (MovDelay[x][y] != 0)
  7139.     {
  7140.       int frame = getGraphicAnimationFrame(IMG_TWINKLE_WHITE,
  7141.                        10 - MovDelay[x][y]);
  7142.  
  7143.       DrawGraphicThruMask(SCREENX(x), SCREENY(y), IMG_TWINKLE_WHITE, frame);
  7144.  
  7145.       if (setup.direct_draw)
  7146.       {
  7147.     int dest_x, dest_y;
  7148.  
  7149.     dest_x = FX + SCREENX(x) * TILEX;
  7150.     dest_y = FY + SCREENY(y) * TILEY;
  7151.  
  7152.     BlitBitmap(drawto_field, window,
  7153.            dest_x, dest_y, TILEX, TILEY, dest_x, dest_y);
  7154.     SetDrawtoField(DRAW_DIRECT);
  7155.       }
  7156.     }
  7157.   }
  7158. }
  7159.  
  7160. void MauerWaechst(int x, int y)
  7161. {
  7162.   int delay = 6;
  7163.  
  7164.   if (!MovDelay[x][y])        /* next animation frame */
  7165.     MovDelay[x][y] = 3 * delay;
  7166.  
  7167.   if (MovDelay[x][y])        /* wait some time before next frame */
  7168.   {
  7169.     MovDelay[x][y]--;
  7170.  
  7171.     if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
  7172.     {
  7173.       int graphic = el_dir2img(Feld[x][y], GfxDir[x][y]);
  7174.       int frame = getGraphicAnimationFrame(graphic, 17 - MovDelay[x][y]);
  7175.  
  7176.       DrawGraphic(SCREENX(x), SCREENY(y), graphic, frame);
  7177.     }
  7178.  
  7179.     if (!MovDelay[x][y])
  7180.     {
  7181.       if (MovDir[x][y] == MV_LEFT)
  7182.       {
  7183.     if (IN_LEV_FIELD(x - 1, y) && IS_WALL(Feld[x - 1][y]))
  7184.       DrawLevelField(x - 1, y);
  7185.       }
  7186.       else if (MovDir[x][y] == MV_RIGHT)
  7187.       {
  7188.     if (IN_LEV_FIELD(x + 1, y) && IS_WALL(Feld[x + 1][y]))
  7189.       DrawLevelField(x + 1, y);
  7190.       }
  7191.       else if (MovDir[x][y] == MV_UP)
  7192.       {
  7193.     if (IN_LEV_FIELD(x, y - 1) && IS_WALL(Feld[x][y - 1]))
  7194.       DrawLevelField(x, y - 1);
  7195.       }
  7196.       else
  7197.       {
  7198.     if (IN_LEV_FIELD(x, y + 1) && IS_WALL(Feld[x][y + 1]))
  7199.       DrawLevelField(x, y + 1);
  7200.       }
  7201.  
  7202.       Feld[x][y] = Store[x][y];
  7203.       Store[x][y] = 0;
  7204.       GfxDir[x][y] = MovDir[x][y] = MV_NO_MOVING;
  7205.       DrawLevelField(x, y);
  7206.     }
  7207.   }
  7208. }
  7209.  
  7210. void MauerAbleger(int ax, int ay)
  7211. {
  7212.   int element = Feld[ax][ay];
  7213.   int graphic = el2img(element);
  7214.   boolean oben_frei = FALSE, unten_frei = FALSE;
  7215.   boolean links_frei = FALSE, rechts_frei = FALSE;
  7216.   boolean oben_massiv = FALSE, unten_massiv = FALSE;
  7217.   boolean links_massiv = FALSE, rechts_massiv = FALSE;
  7218.   boolean new_wall = FALSE;
  7219.  
  7220.   if (IS_ANIMATED(graphic))
  7221.     DrawLevelGraphicAnimationIfNeeded(ax, ay, graphic);
  7222.  
  7223.   if (!MovDelay[ax][ay])    /* start building new wall */
  7224.     MovDelay[ax][ay] = 6;
  7225.  
  7226.   if (MovDelay[ax][ay])        /* wait some time before building new wall */
  7227.   {
  7228.     MovDelay[ax][ay]--;
  7229.     if (MovDelay[ax][ay])
  7230.       return;
  7231.   }
  7232.  
  7233.   if (IN_LEV_FIELD(ax, ay-1) && IS_FREE(ax, ay-1))
  7234.     oben_frei = TRUE;
  7235.   if (IN_LEV_FIELD(ax, ay+1) && IS_FREE(ax, ay+1))
  7236.     unten_frei = TRUE;
  7237.   if (IN_LEV_FIELD(ax-1, ay) && IS_FREE(ax-1, ay))
  7238.     links_frei = TRUE;
  7239.   if (IN_LEV_FIELD(ax+1, ay) && IS_FREE(ax+1, ay))
  7240.     rechts_frei = TRUE;
  7241.  
  7242.   if (element == EL_EXPANDABLE_WALL_VERTICAL ||
  7243.       element == EL_EXPANDABLE_WALL_ANY)
  7244.   {
  7245.     if (oben_frei)
  7246.     {
  7247.       Feld[ax][ay-1] = EL_EXPANDABLE_WALL_GROWING;
  7248.       Store[ax][ay-1] = element;
  7249.       GfxDir[ax][ay-1] = MovDir[ax][ay-1] = MV_UP;
  7250.       if (IN_SCR_FIELD(SCREENX(ax), SCREENY(ay-1)))
  7251.       DrawGraphic(SCREENX(ax), SCREENY(ay - 1),
  7252.             IMG_EXPANDABLE_WALL_GROWING_UP, 0);
  7253.       new_wall = TRUE;
  7254.     }
  7255.     if (unten_frei)
  7256.     {
  7257.       Feld[ax][ay+1] = EL_EXPANDABLE_WALL_GROWING;
  7258.       Store[ax][ay+1] = element;
  7259.       GfxDir[ax][ay+1] = MovDir[ax][ay+1] = MV_DOWN;
  7260.       if (IN_SCR_FIELD(SCREENX(ax), SCREENY(ay+1)))
  7261.       DrawGraphic(SCREENX(ax), SCREENY(ay + 1),
  7262.             IMG_EXPANDABLE_WALL_GROWING_DOWN, 0);
  7263.       new_wall = TRUE;
  7264.     }
  7265.   }
  7266.  
  7267.   if (element == EL_EXPANDABLE_WALL_HORIZONTAL ||
  7268.       element == EL_EXPANDABLE_WALL_ANY ||
  7269.       element == EL_EXPANDABLE_WALL)
  7270.   {
  7271.     if (links_frei)
  7272.     {
  7273.       Feld[ax-1][ay] = EL_EXPANDABLE_WALL_GROWING;
  7274.       Store[ax-1][ay] = element;
  7275.       GfxDir[ax-1][ay] = MovDir[ax-1][ay] = MV_LEFT;
  7276.       if (IN_SCR_FIELD(SCREENX(ax-1), SCREENY(ay)))
  7277.       DrawGraphic(SCREENX(ax - 1), SCREENY(ay),
  7278.             IMG_EXPANDABLE_WALL_GROWING_LEFT, 0);
  7279.       new_wall = TRUE;
  7280.     }
  7281.  
  7282.     if (rechts_frei)
  7283.     {
  7284.       Feld[ax+1][ay] = EL_EXPANDABLE_WALL_GROWING;
  7285.       Store[ax+1][ay] = element;
  7286.       GfxDir[ax+1][ay] = MovDir[ax+1][ay] = MV_RIGHT;
  7287.       if (IN_SCR_FIELD(SCREENX(ax+1), SCREENY(ay)))
  7288.       DrawGraphic(SCREENX(ax + 1), SCREENY(ay),
  7289.             IMG_EXPANDABLE_WALL_GROWING_RIGHT, 0);
  7290.       new_wall = TRUE;
  7291.     }
  7292.   }
  7293.  
  7294.   if (element == EL_EXPANDABLE_WALL && (links_frei || rechts_frei))
  7295.     DrawLevelField(ax, ay);
  7296.  
  7297.   if (!IN_LEV_FIELD(ax, ay-1) || IS_WALL(Feld[ax][ay-1]))
  7298.     oben_massiv = TRUE;
  7299.   if (!IN_LEV_FIELD(ax, ay+1) || IS_WALL(Feld[ax][ay+1]))
  7300.     unten_massiv = TRUE;
  7301.   if (!IN_LEV_FIELD(ax-1, ay) || IS_WALL(Feld[ax-1][ay]))
  7302.     links_massiv = TRUE;
  7303.   if (!IN_LEV_FIELD(ax+1, ay) || IS_WALL(Feld[ax+1][ay]))
  7304.     rechts_massiv = TRUE;
  7305.  
  7306.   if (((oben_massiv && unten_massiv) ||
  7307.        element == EL_EXPANDABLE_WALL_HORIZONTAL ||
  7308.        element == EL_EXPANDABLE_WALL) &&
  7309.       ((links_massiv && rechts_massiv) ||
  7310.        element == EL_EXPANDABLE_WALL_VERTICAL))
  7311.     Feld[ax][ay] = EL_WALL;
  7312.  
  7313.   if (new_wall)
  7314. #if 1
  7315.     PlayLevelSoundAction(ax, ay, ACTION_GROWING);
  7316. #else
  7317.     PlayLevelSound(ax, ay, SND_EXPANDABLE_WALL_GROWING);
  7318. #endif
  7319. }
  7320.  
  7321. void CheckForDragon(int x, int y)
  7322. {
  7323.   int i, j;
  7324.   boolean dragon_found = FALSE;
  7325.   static int xy[4][2] =
  7326.   {
  7327.     { 0, -1 },
  7328.     { -1, 0 },
  7329.     { +1, 0 },
  7330.     { 0, +1 }
  7331.   };
  7332.  
  7333.   for (i = 0; i < NUM_DIRECTIONS; i++)
  7334.   {
  7335.     for (j = 0; j < 4; j++)
  7336.     {
  7337.       int xx = x + j * xy[i][0], yy = y + j * xy[i][1];
  7338.  
  7339.       if (IN_LEV_FIELD(xx, yy) &&
  7340.       (Feld[xx][yy] == EL_FLAMES || Feld[xx][yy] == EL_DRAGON))
  7341.       {
  7342.     if (Feld[xx][yy] == EL_DRAGON)
  7343.       dragon_found = TRUE;
  7344.       }
  7345.       else
  7346.     break;
  7347.     }
  7348.   }
  7349.  
  7350.   if (!dragon_found)
  7351.   {
  7352.     for (i = 0; i < NUM_DIRECTIONS; i++)
  7353.     {
  7354.       for (j = 0; j < 3; j++)
  7355.       {
  7356.       int xx = x + j * xy[i][0], yy = y + j * xy[i][1];
  7357.   
  7358.       if (IN_LEV_FIELD(xx, yy) && Feld[xx][yy] == EL_FLAMES)
  7359.       {
  7360.       Feld[xx][yy] = EL_EMPTY;
  7361.       DrawLevelField(xx, yy);
  7362.       }
  7363.       else
  7364.         break;
  7365.       }
  7366.     }
  7367.   }
  7368. }
  7369.  
  7370. static void InitBuggyBase(int x, int y)
  7371. {
  7372.   int element = Feld[x][y];
  7373.   int activating_delay = FRAMES_PER_SECOND / 4;
  7374.  
  7375.   ChangeDelay[x][y] =
  7376.     (element == EL_SP_BUGGY_BASE ?
  7377.      2 * FRAMES_PER_SECOND + RND(5 * FRAMES_PER_SECOND) - activating_delay :
  7378.      element == EL_SP_BUGGY_BASE_ACTIVATING ?
  7379.      activating_delay :
  7380.      element == EL_SP_BUGGY_BASE_ACTIVE ?
  7381.      1 * FRAMES_PER_SECOND + RND(1 * FRAMES_PER_SECOND) : 1);
  7382. }
  7383.  
  7384. static void WarnBuggyBase(int x, int y)
  7385. {
  7386.   int i;
  7387.   static int xy[4][2] =
  7388.   {
  7389.     { 0, -1 },
  7390.     { -1, 0 },
  7391.     { +1, 0 },
  7392.     { 0, +1 }
  7393.   };
  7394.  
  7395.   for (i = 0; i < NUM_DIRECTIONS; i++)
  7396.   {
  7397.     int xx = x + xy[i][0], yy = y + xy[i][1];
  7398.  
  7399.     if (IS_PLAYER(xx, yy))
  7400.     {
  7401.       PlayLevelSound(x, y, SND_SP_BUGGY_BASE_ACTIVE);
  7402.  
  7403.       break;
  7404.     }
  7405.   }
  7406. }
  7407.  
  7408. static void InitTrap(int x, int y)
  7409. {
  7410.   ChangeDelay[x][y] = 2 * FRAMES_PER_SECOND + RND(5 * FRAMES_PER_SECOND);
  7411. }
  7412.  
  7413. static void ActivateTrap(int x, int y)
  7414. {
  7415.   PlayLevelSound(x, y, SND_TRAP_ACTIVATING);
  7416. }
  7417.  
  7418. static void ChangeActiveTrap(int x, int y)
  7419. {
  7420.   int graphic = IMG_TRAP_ACTIVE;
  7421.  
  7422.   /* if new animation frame was drawn, correct crumbled sand border */
  7423.   if (IS_NEW_FRAME(GfxFrame[x][y], graphic))
  7424.     DrawLevelFieldCrumbledSand(x, y);
  7425. }
  7426.  
  7427. static void ChangeElementNowExt(int x, int y, int target_element)
  7428. {
  7429.   int previous_move_direction = MovDir[x][y];
  7430. #if 1
  7431.   boolean add_player = (ELEM_IS_PLAYER(target_element) &&
  7432.             IS_WALKABLE(Feld[x][y]));
  7433. #else
  7434.   boolean add_player = (ELEM_IS_PLAYER(target_element) &&
  7435.             IS_WALKABLE(Feld[x][y]) &&
  7436.             !IS_MOVING(x, y));
  7437. #endif
  7438.  
  7439.   /* check if element under player changes from accessible to unaccessible
  7440.      (needed for special case of dropping element which then changes) */
  7441.   if (IS_PLAYER(x, y) && !PLAYER_EXPLOSION_PROTECTED(x, y) &&
  7442.       IS_ACCESSIBLE(Feld[x][y]) && !IS_ACCESSIBLE(target_element))
  7443.   {
  7444. #if 0
  7445.     printf("::: BOOOM! [%d, '%s']\n", target_element,
  7446.        element_info[target_element].token_name);
  7447. #endif
  7448.  
  7449.     Bang(x, y);
  7450.     return;
  7451.   }
  7452.  
  7453. #if 1
  7454.   if (!add_player)
  7455. #endif
  7456.   {
  7457. #if 1
  7458.     if (IS_MOVING(x, y) || IS_BLOCKED(x, y))
  7459.       RemoveMovingField(x, y);
  7460.     else
  7461.       RemoveField(x, y);
  7462.  
  7463.     Feld[x][y] = target_element;
  7464. #else
  7465.     RemoveField(x, y);
  7466.     Feld[x][y] = target_element;
  7467. #endif
  7468.  
  7469.     ResetGfxAnimation(x, y);
  7470.     ResetRandomAnimationValue(x, y);
  7471.  
  7472.     if (element_info[Feld[x][y]].move_direction_initial == MV_START_PREVIOUS)
  7473.       MovDir[x][y] = previous_move_direction;
  7474.  
  7475. #if 1
  7476.     InitField_WithBug1(x, y, FALSE);
  7477. #else
  7478.     InitField(x, y, FALSE);
  7479.     if (CAN_MOVE(Feld[x][y]))
  7480.       InitMovDir(x, y);
  7481. #endif
  7482.  
  7483.     DrawLevelField(x, y);
  7484.  
  7485.     if (GFX_CRUMBLED(Feld[x][y]))
  7486.       DrawLevelFieldCrumbledSandNeighbours(x, y);
  7487.   }
  7488.  
  7489. #if 0
  7490.   Changed[x][y] |= ChangeEvent[x][y];    /* ignore same changes in this frame */
  7491. #endif
  7492.  
  7493. #if 0
  7494.   TestIfBadThingTouchesHero(x, y);
  7495.   TestIfPlayerTouchesCustomElement(x, y);
  7496.   TestIfElementTouchesCustomElement(x, y);
  7497. #endif
  7498.  
  7499.   /* "Changed[][]" not set yet to allow "entered by player" change one time */
  7500.   if (ELEM_IS_PLAYER(target_element))
  7501.     RelocatePlayer(x, y, target_element);
  7502.  
  7503. #if 1
  7504.   Changed[x][y] |= ChangeEvent[x][y];    /* ignore same changes in this frame */
  7505. #endif
  7506.  
  7507. #if 1
  7508.   TestIfBadThingTouchesHero(x, y);
  7509.   TestIfPlayerTouchesCustomElement(x, y);
  7510.   TestIfElementTouchesCustomElement(x, y);
  7511. #endif
  7512. }
  7513.  
  7514. static boolean ChangeElementNow(int x, int y, int element, int page)
  7515. {
  7516.   struct ElementChangeInfo *change = &element_info[element].change_page[page];
  7517.   int target_element;
  7518.   int old_element = Feld[x][y];
  7519.  
  7520.   /* always use default change event to prevent running into a loop */
  7521.   if (ChangeEvent[x][y] == CE_BITMASK_DEFAULT)
  7522.     ChangeEvent[x][y] = CH_EVENT_BIT(CE_DELAY);
  7523.  
  7524.   if (ChangeEvent[x][y] == CH_EVENT_BIT(CE_DELAY))
  7525.   {
  7526.     /* reset actual trigger element and player */
  7527.     change->actual_trigger_element = EL_EMPTY;
  7528.     change->actual_trigger_player = EL_PLAYER_1;
  7529.   }
  7530.  
  7531.   /* do not change already changed elements with same change event */
  7532. #if 0
  7533.   if (Changed[x][y] & ChangeEvent[x][y])
  7534.     return FALSE;
  7535. #else
  7536.   if (Changed[x][y])
  7537.     return FALSE;
  7538. #endif
  7539.  
  7540.   Changed[x][y] |= ChangeEvent[x][y];    /* ignore same changes in this frame */
  7541.  
  7542. #if 0
  7543.   /* !!! indirect change before direct change !!! */
  7544.   CheckTriggeredElementChangeByPage(x,y,Feld[x][y], CE_OTHER_IS_CHANGING,page);
  7545. #endif
  7546.  
  7547.   if (change->explode)
  7548.   {
  7549.     Bang(x, y);
  7550.  
  7551.     return TRUE;
  7552.   }
  7553.  
  7554.   if (change->use_target_content)
  7555.   {
  7556.     boolean complete_replace = TRUE;
  7557.     boolean can_replace[3][3];
  7558.     int xx, yy;
  7559.  
  7560.     for (yy = 0; yy < 3; yy++) for (xx = 0; xx < 3 ; xx++)
  7561.     {
  7562.       boolean is_empty;
  7563.       boolean is_walkable;
  7564.       boolean is_diggable;
  7565.       boolean is_collectible;
  7566.       boolean is_removable;
  7567.       boolean is_destructible;
  7568.       int ex = x + xx - 1;
  7569.       int ey = y + yy - 1;
  7570.       int content_element = change->target_content[xx][yy];
  7571.       int e;
  7572.  
  7573.       can_replace[xx][yy] = TRUE;
  7574.  
  7575.       if (ex == x && ey == y)    /* do not check changing element itself */
  7576.     continue;
  7577.  
  7578.       if (content_element == EL_EMPTY_SPACE)
  7579.       {
  7580.     can_replace[xx][yy] = FALSE;    /* do not replace border with space */
  7581.  
  7582.     continue;
  7583.       }
  7584.  
  7585.       if (!IN_LEV_FIELD(ex, ey))
  7586.       {
  7587.     can_replace[xx][yy] = FALSE;
  7588.     complete_replace = FALSE;
  7589.  
  7590.     continue;
  7591.       }
  7592.  
  7593. #if 0
  7594.       if (Changed[ex][ey])    /* do not change already changed elements */
  7595.       {
  7596.     can_replace[xx][yy] = FALSE;
  7597.     complete_replace = FALSE;
  7598.  
  7599.     continue;
  7600.       }
  7601. #endif
  7602.  
  7603.       e = Feld[ex][ey];
  7604.  
  7605.       if (IS_MOVING(ex, ey) || IS_BLOCKED(ex, ey))
  7606.     e = MovingOrBlocked2Element(ex, ey);
  7607.  
  7608. #if 1
  7609.  
  7610. #if 0
  7611.       is_empty = (IS_FREE(ex, ey) ||
  7612.           (IS_PLAYER(ex, ey) && IS_WALKABLE(content_element)) ||
  7613.           (IS_WALKABLE(e) && ELEM_IS_PLAYER(content_element) &&
  7614.            !IS_MOVING(ex, ey) && !IS_BLOCKED(ex, ey)));
  7615. #else
  7616.  
  7617. #if 0
  7618.       is_empty = (IS_FREE(ex, ey) ||
  7619.           (IS_PLAYER(ex, ey) && IS_WALKABLE(content_element)));
  7620. #else
  7621.       is_empty = (IS_FREE(ex, ey) ||
  7622.           (IS_FREE_OR_PLAYER(ex, ey) && IS_WALKABLE(content_element)));
  7623. #endif
  7624.  
  7625. #endif
  7626.  
  7627.       is_walkable     = (is_empty || IS_WALKABLE(e));
  7628.       is_diggable     = (is_empty || IS_DIGGABLE(e));
  7629.       is_collectible  = (is_empty || IS_COLLECTIBLE(e));
  7630.       is_destructible = (is_empty || !IS_INDESTRUCTIBLE(e));
  7631.       is_removable    = (is_diggable || is_collectible);
  7632.  
  7633.       can_replace[xx][yy] =
  7634.     (((change->replace_when == CP_WHEN_EMPTY        && is_empty) ||
  7635.       (change->replace_when == CP_WHEN_WALKABLE     && is_walkable) ||
  7636.       (change->replace_when == CP_WHEN_DIGGABLE     && is_diggable) ||
  7637.       (change->replace_when == CP_WHEN_COLLECTIBLE  && is_collectible) ||
  7638.       (change->replace_when == CP_WHEN_REMOVABLE    && is_removable) ||
  7639.       (change->replace_when == CP_WHEN_DESTRUCTIBLE && is_destructible)) &&
  7640.      !(IS_PLAYER(ex, ey) && ELEM_IS_PLAYER(content_element)));
  7641.  
  7642.       if (!can_replace[xx][yy])
  7643.     complete_replace = FALSE;
  7644. #else
  7645.       empty_for_element = (IS_FREE(ex, ey) || (IS_FREE_OR_PLAYER(ex, ey) &&
  7646.                            IS_WALKABLE(content_element)));
  7647. #if 1
  7648.       half_destructible = (empty_for_element || IS_DIGGABLE(e));
  7649. #else
  7650.       half_destructible = (IS_FREE(ex, ey) || IS_DIGGABLE(e));
  7651. #endif
  7652.  
  7653.       if ((change->replace_when <= CP_WHEN_EMPTY  && !empty_for_element) ||
  7654.       (change->replace_when <= CP_WHEN_DIGGABLE && !half_destructible) ||
  7655.       (change->replace_when <= CP_WHEN_DESTRUCTIBLE && IS_INDESTRUCTIBLE(e)))
  7656.       {
  7657.     can_replace[xx][yy] = FALSE;
  7658.     complete_replace = FALSE;
  7659.       }
  7660. #endif
  7661.     }
  7662.  
  7663.     if (!change->only_if_complete || complete_replace)
  7664.     {
  7665.       boolean something_has_changed = FALSE;
  7666.  
  7667.       if (change->only_if_complete && change->use_random_replace &&
  7668.       RND(100) < change->random_percentage)
  7669.     return FALSE;
  7670.  
  7671.       for (yy = 0; yy < 3; yy++) for (xx = 0; xx < 3 ; xx++)
  7672.       {
  7673.     int ex = x + xx - 1;
  7674.     int ey = y + yy - 1;
  7675.     int content_element;
  7676.  
  7677.     if (can_replace[xx][yy] && (!change->use_random_replace ||
  7678.                     RND(100) < change->random_percentage))
  7679.     {
  7680.       if (IS_MOVING(ex, ey) || IS_BLOCKED(ex, ey))
  7681.         RemoveMovingField(ex, ey);
  7682.  
  7683.       ChangeEvent[ex][ey] = ChangeEvent[x][y];
  7684.  
  7685.       content_element = change->target_content[xx][yy];
  7686.       target_element = GET_TARGET_ELEMENT(content_element, change);
  7687.  
  7688.       ChangeElementNowExt(ex, ey, target_element);
  7689.  
  7690.       something_has_changed = TRUE;
  7691.  
  7692.       /* for symmetry reasons, freeze newly created border elements */
  7693.       if (ex != x || ey != y)
  7694.         Stop[ex][ey] = TRUE;    /* no more moving in this frame */
  7695.     }
  7696.       }
  7697.  
  7698.       if (something_has_changed)
  7699.     PlayLevelSoundElementAction(x, y, element, ACTION_CHANGING);
  7700.     }
  7701.   }
  7702.   else
  7703.   {
  7704.     target_element = GET_TARGET_ELEMENT(change->target_element, change);
  7705.  
  7706.     ChangeElementNowExt(x, y, target_element);
  7707.  
  7708.     PlayLevelSoundElementAction(x, y, element, ACTION_CHANGING);
  7709.   }
  7710.  
  7711. #if 1
  7712.   /* this uses direct change before indirect change */
  7713.   CheckTriggeredElementChangeByPage(x,y,old_element,CE_OTHER_IS_CHANGING,page);
  7714. #endif
  7715.  
  7716.   return TRUE;
  7717. }
  7718.  
  7719. static void ChangeElement(int x, int y, int page)
  7720. {
  7721.   int element = MovingOrBlocked2Element(x, y);
  7722.   struct ElementInfo *ei = &element_info[element];
  7723.   struct ElementChangeInfo *change = &ei->change_page[page];
  7724.  
  7725. #ifdef DEBUG
  7726.   if (!CAN_CHANGE(element) && !CAN_CHANGE(Back[x][y]))
  7727.   {
  7728.     printf("\n\n");
  7729.     printf("ChangeElement(): %d,%d: element = %d ('%s')\n",
  7730.        x, y, element, element_info[element].token_name);
  7731.     printf("ChangeElement(): This should never happen!\n");
  7732.     printf("\n\n");
  7733.   }
  7734. #endif
  7735.  
  7736.   /* this can happen with classic bombs on walkable, changing elements */
  7737.   if (!CAN_CHANGE(element))
  7738.   {
  7739. #if 0
  7740.     if (!CAN_CHANGE(Back[x][y]))    /* prevent permanent repetition */
  7741.       ChangeDelay[x][y] = 0;
  7742. #endif
  7743.  
  7744.     return;
  7745.   }
  7746.  
  7747.   if (ChangeDelay[x][y] == 0)        /* initialize element change */
  7748.   {
  7749.     ChangeDelay[x][y] = (    change->delay_fixed  * change->delay_frames +
  7750.              RND(change->delay_random * change->delay_frames)) + 1;
  7751.  
  7752.     ResetGfxAnimation(x, y);
  7753.     ResetRandomAnimationValue(x, y);
  7754.  
  7755.     if (change->pre_change_function)
  7756.       change->pre_change_function(x, y);
  7757.   }
  7758.  
  7759.   ChangeDelay[x][y]--;
  7760.  
  7761.   if (ChangeDelay[x][y] != 0)        /* continue element change */
  7762.   {
  7763.     int graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
  7764.  
  7765.     if (IS_ANIMATED(graphic))
  7766.       DrawLevelGraphicAnimationIfNeeded(x, y, graphic);
  7767.  
  7768.     if (change->change_function)
  7769.       change->change_function(x, y);
  7770.   }
  7771.   else                    /* finish element change */
  7772.   {
  7773.     if (ChangePage[x][y] != -1)        /* remember page from delayed change */
  7774.     {
  7775.       page = ChangePage[x][y];
  7776.       ChangePage[x][y] = -1;
  7777.  
  7778.       change = &ei->change_page[page];
  7779.     }
  7780.  
  7781. #if 0
  7782.     if (IS_MOVING(x, y) && !change->explode)
  7783. #else
  7784.     if (IS_MOVING(x, y))        /* never change a running system ;-) */
  7785. #endif
  7786.     {
  7787.       ChangeDelay[x][y] = 1;        /* try change after next move step */
  7788.       ChangePage[x][y] = page;        /* remember page to use for change */
  7789.  
  7790.       return;
  7791.     }
  7792.  
  7793.     if (ChangeElementNow(x, y, element, page))
  7794.     {
  7795.       if (change->post_change_function)
  7796.     change->post_change_function(x, y);
  7797.     }
  7798.   }
  7799. }
  7800.  
  7801. static boolean CheckTriggeredElementChangeExt(int lx, int ly,
  7802.                           int trigger_element,
  7803.                           int trigger_event,
  7804.                           int trigger_player,
  7805.                           int trigger_side,
  7806.                           int trigger_page)
  7807. {
  7808.   int i, j, x, y;
  7809.   int trigger_page_bits = (trigger_page < 0 ? CH_PAGE_ANY : 1 << trigger_page);
  7810.  
  7811.   if (!(trigger_events[trigger_element] & CH_EVENT_BIT(trigger_event)))
  7812.     return FALSE;
  7813.  
  7814.   for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
  7815.   {
  7816.     int element = EL_CUSTOM_START + i;
  7817.  
  7818.     boolean change_element = FALSE;
  7819.     int page = 0;
  7820.  
  7821.     if (!CAN_CHANGE(element) || !HAS_ANY_CHANGE_EVENT(element, trigger_event))
  7822.       continue;
  7823.  
  7824.     for (j = 0; j < element_info[element].num_change_pages; j++)
  7825.     {
  7826.       struct ElementChangeInfo *change = &element_info[element].change_page[j];
  7827.  
  7828.       if (change->can_change &&
  7829.       change->events & CH_EVENT_BIT(trigger_event) &&
  7830.       change->trigger_side & trigger_side &&
  7831.       change->trigger_player & trigger_player &&
  7832.       change->trigger_page & trigger_page_bits &&
  7833.       IS_EQUAL_OR_IN_GROUP(trigger_element, change->trigger_element))
  7834.       {
  7835. #if 0
  7836.     if (!(change->events & CH_EVENT_BIT(trigger_event)))
  7837.       printf("::: !!! %d triggers %d: using wrong page %d [event %d]\n",
  7838.          trigger_element-EL_CUSTOM_START+1, i+1, j, trigger_event);
  7839. #endif
  7840.  
  7841.     change_element = TRUE;
  7842.     page = j;
  7843.  
  7844.     change->actual_trigger_element = trigger_element;
  7845.     change->actual_trigger_player = EL_PLAYER_1 + log_2(trigger_player);
  7846.  
  7847.     break;
  7848.       }
  7849.     }
  7850.  
  7851.     if (!change_element)
  7852.       continue;
  7853.  
  7854.     for (y = 0; y < lev_fieldy; y++) for (x = 0; x < lev_fieldx; x++)
  7855.     {
  7856. #if 0
  7857.       if (x == lx && y == ly)    /* do not change trigger element itself */
  7858.     continue;
  7859. #endif
  7860.  
  7861.       if (Feld[x][y] == element)
  7862.       {
  7863.     ChangeDelay[x][y] = 1;
  7864.     ChangeEvent[x][y] = CH_EVENT_BIT(trigger_event);
  7865.     ChangeElement(x, y, page);
  7866.       }
  7867.     }
  7868.   }
  7869.  
  7870.   return TRUE;
  7871. }
  7872.  
  7873. static boolean CheckElementChangeExt(int x, int y,
  7874.                      int element,
  7875.                      int trigger_element,
  7876.                      int trigger_event,
  7877.                      int trigger_player,
  7878.                      int trigger_side,
  7879.                      int trigger_page)
  7880. {
  7881.   if (!CAN_CHANGE(element) || !HAS_ANY_CHANGE_EVENT(element, trigger_event))
  7882.     return FALSE;
  7883.  
  7884.   if (Feld[x][y] == EL_BLOCKED)
  7885.   {
  7886.     Blocked2Moving(x, y, &x, &y);
  7887.     element = Feld[x][y];
  7888.   }
  7889.  
  7890. #if 1
  7891.   if (Feld[x][y] != element)    /* check if element has already changed */
  7892.   {
  7893. #if 0
  7894.     printf("::: %d ('%s') != %d ('%s') [%d]\n",
  7895.        Feld[x][y], element_info[Feld[x][y]].token_name,
  7896.        element, element_info[element].token_name,
  7897.        trigger_event);
  7898. #endif
  7899.  
  7900.     return FALSE;
  7901.   }
  7902. #endif
  7903.  
  7904. #if 1
  7905.   if (trigger_page < 0)
  7906.   {
  7907.     boolean change_element = FALSE;
  7908.     int i;
  7909.  
  7910.     for (i = 0; i < element_info[element].num_change_pages; i++)
  7911.     {
  7912.       struct ElementChangeInfo *change = &element_info[element].change_page[i];
  7913.  
  7914.       if (change->can_change &&
  7915.       change->events & CH_EVENT_BIT(trigger_event) &&
  7916.       change->trigger_side & trigger_side &&
  7917.       change->trigger_player & trigger_player)
  7918.       {
  7919.     change_element = TRUE;
  7920.     trigger_page = i;
  7921.  
  7922.     change->actual_trigger_element = trigger_element;
  7923.     change->actual_trigger_player = EL_PLAYER_1 + log_2(trigger_player);
  7924.  
  7925.     break;
  7926.       }
  7927.     }
  7928.  
  7929.     if (!change_element)
  7930.       return FALSE;
  7931.   }
  7932.   else
  7933.   {
  7934.     struct ElementInfo *ei = &element_info[element];
  7935.     struct ElementChangeInfo *change = &ei->change_page[trigger_page];
  7936.  
  7937.     change->actual_trigger_element = trigger_element;
  7938.     change->actual_trigger_player = EL_PLAYER_1;    /* unused */
  7939.   }
  7940.  
  7941. #else
  7942.  
  7943.   /* !!! this check misses pages with same event, but different side !!! */
  7944.  
  7945.   if (trigger_page < 0)
  7946.     trigger_page = element_info[element].event_page_nr[trigger_event];
  7947.  
  7948.   if (!(element_info[element].change_page[trigger_page].trigger_side & trigger_side))
  7949.     return FALSE;
  7950. #endif
  7951.  
  7952.   ChangeDelay[x][y] = 1;
  7953.   ChangeEvent[x][y] = CH_EVENT_BIT(trigger_event);
  7954.   ChangeElement(x, y, trigger_page);
  7955.  
  7956.   return TRUE;
  7957. }
  7958.  
  7959. static void PlayPlayerSound(struct PlayerInfo *player)
  7960. {
  7961.   int jx = player->jx, jy = player->jy;
  7962.   int element = player->element_nr;
  7963.   int last_action = player->last_action_waiting;
  7964.   int action = player->action_waiting;
  7965.  
  7966.   if (player->is_waiting)
  7967.   {
  7968.     if (action != last_action)
  7969.       PlayLevelSoundElementAction(jx, jy, element, action);
  7970.     else
  7971.       PlayLevelSoundElementActionIfLoop(jx, jy, element, action);
  7972.   }
  7973.   else
  7974.   {
  7975.     if (action != last_action)
  7976.       StopSound(element_info[element].sound[last_action]);
  7977.  
  7978.     if (last_action == ACTION_SLEEPING)
  7979.       PlayLevelSoundElementAction(jx, jy, element, ACTION_AWAKENING);
  7980.   }
  7981. }
  7982.  
  7983. static void PlayAllPlayersSound()
  7984. {
  7985.   int i;
  7986.  
  7987.   for (i = 0; i < MAX_PLAYERS; i++)
  7988.     if (stored_player[i].active)
  7989.       PlayPlayerSound(&stored_player[i]);
  7990. }
  7991.  
  7992. static void SetPlayerWaiting(struct PlayerInfo *player, boolean is_waiting)
  7993. {
  7994.   boolean last_waiting = player->is_waiting;
  7995.   int move_dir = player->MovDir;
  7996.  
  7997.   player->last_action_waiting = player->action_waiting;
  7998.  
  7999.   if (is_waiting)
  8000.   {
  8001.     if (!last_waiting)        /* not waiting -> waiting */
  8002.     {
  8003.       player->is_waiting = TRUE;
  8004.  
  8005.       player->frame_counter_bored =
  8006.     FrameCounter +
  8007.     game.player_boring_delay_fixed +
  8008.     SimpleRND(game.player_boring_delay_random);
  8009.       player->frame_counter_sleeping =
  8010.     FrameCounter +
  8011.     game.player_sleeping_delay_fixed +
  8012.     SimpleRND(game.player_sleeping_delay_random);
  8013.  
  8014.       InitPlayerGfxAnimation(player, ACTION_WAITING, player->MovDir);
  8015.     }
  8016.  
  8017.     if (game.player_sleeping_delay_fixed +
  8018.     game.player_sleeping_delay_random > 0 &&
  8019.     player->anim_delay_counter == 0 &&
  8020.     player->post_delay_counter == 0 &&
  8021.     FrameCounter >= player->frame_counter_sleeping)
  8022.       player->is_sleeping = TRUE;
  8023.     else if (game.player_boring_delay_fixed +
  8024.          game.player_boring_delay_random > 0 &&
  8025.          FrameCounter >= player->frame_counter_bored)
  8026.       player->is_bored = TRUE;
  8027.  
  8028.     player->action_waiting = (player->is_sleeping ? ACTION_SLEEPING :
  8029.                   player->is_bored ? ACTION_BORING :
  8030.                   ACTION_WAITING);
  8031.  
  8032.     if (player->is_sleeping)
  8033.     {
  8034.       if (player->num_special_action_sleeping > 0)
  8035.       {
  8036.     if (player->anim_delay_counter == 0 && player->post_delay_counter == 0)
  8037.     {
  8038.       int last_special_action = player->special_action_sleeping;
  8039.       int num_special_action = player->num_special_action_sleeping;
  8040.       int special_action =
  8041.         (last_special_action == ACTION_DEFAULT ? ACTION_SLEEPING_1 :
  8042.          last_special_action == ACTION_SLEEPING ? ACTION_SLEEPING :
  8043.          last_special_action < ACTION_SLEEPING_1 + num_special_action - 1 ?
  8044.          last_special_action + 1 : ACTION_SLEEPING);
  8045.       int special_graphic =
  8046.         el_act_dir2img(player->element_nr, special_action, move_dir);
  8047.  
  8048.       player->anim_delay_counter =
  8049.         graphic_info[special_graphic].anim_delay_fixed +
  8050.         SimpleRND(graphic_info[special_graphic].anim_delay_random);
  8051.       player->post_delay_counter =
  8052.         graphic_info[special_graphic].post_delay_fixed +
  8053.         SimpleRND(graphic_info[special_graphic].post_delay_random);
  8054.  
  8055.       player->special_action_sleeping = special_action;
  8056.     }
  8057.  
  8058.     if (player->anim_delay_counter > 0)
  8059.     {
  8060.       player->action_waiting = player->special_action_sleeping;
  8061.       player->anim_delay_counter--;
  8062.     }
  8063.     else if (player->post_delay_counter > 0)
  8064.     {
  8065.       player->post_delay_counter--;
  8066.     }
  8067.       }
  8068.     }
  8069.     else if (player->is_bored)
  8070.     {
  8071.       if (player->num_special_action_bored > 0)
  8072.       {
  8073.     if (player->anim_delay_counter == 0 && player->post_delay_counter == 0)
  8074.     {
  8075.       int special_action =
  8076.         ACTION_BORING_1 + SimpleRND(player->num_special_action_bored);
  8077.       int special_graphic =
  8078.         el_act_dir2img(player->element_nr, special_action, move_dir);
  8079.  
  8080.       player->anim_delay_counter =
  8081.         graphic_info[special_graphic].anim_delay_fixed +
  8082.         SimpleRND(graphic_info[special_graphic].anim_delay_random);
  8083.       player->post_delay_counter =
  8084.         graphic_info[special_graphic].post_delay_fixed +
  8085.         SimpleRND(graphic_info[special_graphic].post_delay_random);
  8086.  
  8087.       player->special_action_bored = special_action;
  8088.     }
  8089.  
  8090.     if (player->anim_delay_counter > 0)
  8091.     {
  8092.       player->action_waiting = player->special_action_bored;
  8093.       player->anim_delay_counter--;
  8094.     }
  8095.     else if (player->post_delay_counter > 0)
  8096.     {
  8097.       player->post_delay_counter--;
  8098.     }
  8099.       }
  8100.     }
  8101.   }
  8102.   else if (last_waiting)    /* waiting -> not waiting */
  8103.   {
  8104.     player->is_waiting = FALSE;
  8105.     player->is_bored = FALSE;
  8106.     player->is_sleeping = FALSE;
  8107.  
  8108.     player->frame_counter_bored = -1;
  8109.     player->frame_counter_sleeping = -1;
  8110.  
  8111.     player->anim_delay_counter = 0;
  8112.     player->post_delay_counter = 0;
  8113.  
  8114.     player->action_waiting = ACTION_DEFAULT;
  8115.  
  8116.     player->special_action_bored = ACTION_DEFAULT;
  8117.     player->special_action_sleeping = ACTION_DEFAULT;
  8118.   }
  8119. }
  8120.  
  8121. #if 1
  8122. static byte PlayerActions(struct PlayerInfo *player, byte player_action)
  8123. {
  8124. #if 0
  8125.   static byte stored_player_action[MAX_PLAYERS];
  8126.   static int num_stored_actions = 0;
  8127. #endif
  8128.   boolean moved = FALSE, snapped = FALSE, dropped = FALSE;
  8129.   int left    = player_action & JOY_LEFT;
  8130.   int right    = player_action & JOY_RIGHT;
  8131.   int up    = player_action & JOY_UP;
  8132.   int down    = player_action & JOY_DOWN;
  8133.   int button1    = player_action & JOY_BUTTON_1;
  8134.   int button2    = player_action & JOY_BUTTON_2;
  8135.   int dx    = (left ? -1    : right ? 1    : 0);
  8136.   int dy    = (up   ? -1    : down  ? 1    : 0);
  8137.  
  8138. #if 0
  8139.   stored_player_action[player->index_nr] = 0;
  8140.   num_stored_actions++;
  8141. #endif
  8142.  
  8143. #if 0
  8144.   printf("::: player %d [%d]\n", player->index_nr, FrameCounter);
  8145. #endif
  8146.  
  8147.   if (!player->active || tape.pausing)
  8148.     return 0;
  8149.  
  8150. #if 0
  8151.   printf("::: [%d %d %d %d] [%d %d]\n",
  8152.      left, right, up, down, button1, button2);
  8153. #endif
  8154.  
  8155.   if (player_action)
  8156.   {
  8157. #if 0
  8158.     printf("::: player %d acts [%d]\n", player->index_nr, FrameCounter);
  8159. #endif
  8160.  
  8161. #if 0
  8162.     /* !!! TEST !!! */
  8163.     if (player->MovPos == 0)
  8164.       CheckGravityMovement(player);
  8165. #endif
  8166.     if (button1)
  8167.       snapped = SnapField(player, dx, dy);
  8168.     else
  8169.     {
  8170.       if (button2)
  8171.     dropped = DropElement(player);
  8172.  
  8173.       moved = MovePlayer(player, dx, dy);
  8174.     }
  8175.  
  8176.     if (tape.single_step && tape.recording && !tape.pausing)
  8177.     {
  8178.       if (button1 || (dropped && !moved))
  8179.       {
  8180.     TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
  8181.     SnapField(player, 0, 0);        /* stop snapping */
  8182.       }
  8183.     }
  8184.  
  8185.     SetPlayerWaiting(player, FALSE);
  8186.  
  8187. #if 1
  8188.     return player_action;
  8189. #else
  8190.     stored_player_action[player->index_nr] = player_action;
  8191. #endif
  8192.   }
  8193.   else
  8194.   {
  8195. #if 0
  8196.     printf("::: player %d waits [%d]\n", player->index_nr, FrameCounter);
  8197. #endif
  8198.  
  8199.     /* no actions for this player (no input at player's configured device) */
  8200.  
  8201.     DigField(player, 0, 0, 0, 0, 0, 0, DF_NO_PUSH);
  8202.     SnapField(player, 0, 0);
  8203.     CheckGravityMovementWhenNotMoving(player);
  8204.  
  8205.     if (player->MovPos == 0)
  8206.       SetPlayerWaiting(player, TRUE);
  8207.  
  8208.     if (player->MovPos == 0)    /* needed for tape.playing */
  8209.       player->is_moving = FALSE;
  8210.  
  8211.     player->is_dropping = FALSE;
  8212.  
  8213.     return 0;
  8214.   }
  8215.  
  8216. #if 0
  8217.   if (tape.recording && num_stored_actions >= MAX_PLAYERS)
  8218.   {
  8219.     printf("::: player %d recorded [%d]\n", player->index_nr, FrameCounter);
  8220.  
  8221.     TapeRecordAction(stored_player_action);
  8222.     num_stored_actions = 0;
  8223.   }
  8224. #endif
  8225. }
  8226.  
  8227. #else
  8228.  
  8229. static void PlayerActions(struct PlayerInfo *player, byte player_action)
  8230. {
  8231.   static byte stored_player_action[MAX_PLAYERS];
  8232.   static int num_stored_actions = 0;
  8233.   boolean moved = FALSE, snapped = FALSE, dropped = FALSE;
  8234.   int left    = player_action & JOY_LEFT;
  8235.   int right    = player_action & JOY_RIGHT;
  8236.   int up    = player_action & JOY_UP;
  8237.   int down    = player_action & JOY_DOWN;
  8238.   int button1    = player_action & JOY_BUTTON_1;
  8239.   int button2    = player_action & JOY_BUTTON_2;
  8240.   int dx    = (left ? -1    : right ? 1    : 0);
  8241.   int dy    = (up   ? -1    : down  ? 1    : 0);
  8242.  
  8243.   stored_player_action[player->index_nr] = 0;
  8244.   num_stored_actions++;
  8245.  
  8246.   printf("::: player %d [%d]\n", player->index_nr, FrameCounter);
  8247.  
  8248.   if (!player->active || tape.pausing)
  8249.     return;
  8250.  
  8251.   if (player_action)
  8252.   {
  8253.     printf("::: player %d acts [%d]\n", player->index_nr, FrameCounter);
  8254.  
  8255.     if (button1)
  8256.       snapped = SnapField(player, dx, dy);
  8257.     else
  8258.     {
  8259.       if (button2)
  8260.     dropped = DropElement(player);
  8261.  
  8262.       moved = MovePlayer(player, dx, dy);
  8263.     }
  8264.  
  8265.     if (tape.single_step && tape.recording && !tape.pausing)
  8266.     {
  8267.       if (button1 || (dropped && !moved))
  8268.       {
  8269.     TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
  8270.     SnapField(player, 0, 0);        /* stop snapping */
  8271.       }
  8272.     }
  8273.  
  8274.     stored_player_action[player->index_nr] = player_action;
  8275.   }
  8276.   else
  8277.   {
  8278.     printf("::: player %d waits [%d]\n", player->index_nr, FrameCounter);
  8279.  
  8280.     /* no actions for this player (no input at player's configured device) */
  8281.  
  8282.     DigField(player, 0, 0, 0, 0, 0, 0, DF_NO_PUSH);
  8283.     SnapField(player, 0, 0);
  8284.     CheckGravityMovementWhenNotMoving(player);
  8285.  
  8286.     if (player->MovPos == 0)
  8287.       InitPlayerGfxAnimation(player, ACTION_DEFAULT, player->MovDir);
  8288.  
  8289.     if (player->MovPos == 0)    /* needed for tape.playing */
  8290.       player->is_moving = FALSE;
  8291.   }
  8292.  
  8293.   if (tape.recording && num_stored_actions >= MAX_PLAYERS)
  8294.   {
  8295.     printf("::: player %d recorded [%d]\n", player->index_nr, FrameCounter);
  8296.  
  8297.     TapeRecordAction(stored_player_action);
  8298.     num_stored_actions = 0;
  8299.   }
  8300. }
  8301. #endif
  8302.  
  8303. void GameActions()
  8304. {
  8305.   static unsigned long action_delay = 0;
  8306.   unsigned long action_delay_value;
  8307.   int magic_wall_x = 0, magic_wall_y = 0;
  8308.   int i, x, y, element, graphic;
  8309.   byte *recorded_player_action;
  8310.   byte summarized_player_action = 0;
  8311. #if 1
  8312.   byte tape_action[MAX_PLAYERS];
  8313. #endif
  8314.  
  8315.   if (game_status != GAME_MODE_PLAYING)
  8316.     return;
  8317.  
  8318.   action_delay_value =
  8319.     (tape.playing && tape.fast_forward ? FfwdFrameDelay : GameFrameDelay);
  8320.  
  8321.   if (tape.playing && tape.warp_forward && !tape.pausing)
  8322.     action_delay_value = 0;
  8323.  
  8324.   /* ---------- main game synchronization point ---------- */
  8325.  
  8326.   WaitUntilDelayReached(&action_delay, action_delay_value);
  8327.  
  8328.   if (network_playing && !network_player_action_received)
  8329.   {
  8330.     /*
  8331. #ifdef DEBUG
  8332.     printf("DEBUG: try to get network player actions in time\n");
  8333. #endif
  8334.     */
  8335.  
  8336. #if defined(NETWORK_AVALIABLE)
  8337.     /* last chance to get network player actions without main loop delay */
  8338.     HandleNetworking();
  8339. #endif
  8340.  
  8341.     if (game_status != GAME_MODE_PLAYING)
  8342.       return;
  8343.  
  8344.     if (!network_player_action_received)
  8345.     {
  8346.       /*
  8347. #ifdef DEBUG
  8348.       printf("DEBUG: failed to get network player actions in time\n");
  8349. #endif
  8350.       */
  8351.       return;
  8352.     }
  8353.   }
  8354.  
  8355.   if (tape.pausing)
  8356.     return;
  8357.  
  8358. #if 0
  8359.   printf("::: getting new tape action [%d]\n", FrameCounter);
  8360. #endif
  8361.  
  8362.   recorded_player_action = (tape.playing ? TapePlayAction() : NULL);
  8363.  
  8364. #if 1
  8365.   if (recorded_player_action == NULL && tape.pausing)
  8366.     return;
  8367. #endif
  8368.  
  8369. #if 0
  8370.   printf("::: %d\n", stored_player[0].action);
  8371. #endif
  8372.  
  8373. #if 0
  8374.   if (recorded_player_action != NULL)
  8375.     for (i = 0; i < MAX_PLAYERS; i++)
  8376.       stored_player[i].action = recorded_player_action[i];
  8377. #endif
  8378.  
  8379.   for (i = 0; i < MAX_PLAYERS; i++)
  8380.   {
  8381.     summarized_player_action |= stored_player[i].action;
  8382.  
  8383.     if (!network_playing)
  8384.       stored_player[i].effective_action = stored_player[i].action;
  8385.   }
  8386.  
  8387. #if defined(NETWORK_AVALIABLE)
  8388.   if (network_playing)
  8389.     SendToServer_MovePlayer(summarized_player_action);
  8390. #endif
  8391.  
  8392.   if (!options.network && !setup.team_mode)
  8393.     local_player->effective_action = summarized_player_action;
  8394.  
  8395. #if 1
  8396.   if (recorded_player_action != NULL)
  8397.     for (i = 0; i < MAX_PLAYERS; i++)
  8398.       stored_player[i].effective_action = recorded_player_action[i];
  8399. #endif
  8400.  
  8401. #if 1
  8402.   for (i = 0; i < MAX_PLAYERS; i++)
  8403.   {
  8404.     tape_action[i] = stored_player[i].effective_action;
  8405.  
  8406.     if (tape.recording && tape_action[i] && !tape.player_participates[i])
  8407.       tape.player_participates[i] = TRUE;    /* player just appeared from CE */
  8408.   }
  8409.  
  8410.   /* only save actions from input devices, but not programmed actions */
  8411.   if (tape.recording)
  8412.     TapeRecordAction(tape_action);
  8413. #endif
  8414.  
  8415.   for (i = 0; i < MAX_PLAYERS; i++)
  8416.   {
  8417.     int actual_player_action = stored_player[i].effective_action;
  8418.  
  8419. #if 1
  8420.     /* !!! THIS BREAKS THE FOLLOWING TAPES: !!!
  8421.        - rnd_equinox_tetrachloride 048
  8422.        - rnd_equinox_tetrachloride_ii 096
  8423.        - rnd_emanuel_schmieg 002
  8424.        - doctor_sloan_ww 001, 020
  8425.     */
  8426.     if (stored_player[i].MovPos == 0)
  8427.       CheckGravityMovement(&stored_player[i]);
  8428. #endif
  8429.  
  8430. #if 1
  8431.     /* overwrite programmed action with tape action */
  8432.     if (stored_player[i].programmed_action)
  8433.       actual_player_action = stored_player[i].programmed_action;
  8434. #endif
  8435.  
  8436. #if 0
  8437.     if (stored_player[i].programmed_action)
  8438.       printf("::: %d\n", stored_player[i].programmed_action);
  8439. #endif
  8440.  
  8441.     if (recorded_player_action)
  8442.     {
  8443. #if 0
  8444.       if (stored_player[i].programmed_action &&
  8445.       stored_player[i].programmed_action != recorded_player_action[i])
  8446.     printf("::: %d: %d <-> %d\n", i,
  8447.            stored_player[i].programmed_action, recorded_player_action[i]);
  8448. #endif
  8449.  
  8450. #if 0
  8451.       actual_player_action = recorded_player_action[i];
  8452. #endif
  8453.     }
  8454.  
  8455. #if 0
  8456.     /* overwrite tape action with programmed action */
  8457.     if (stored_player[i].programmed_action)
  8458.       actual_player_action = stored_player[i].programmed_action;
  8459. #endif
  8460.  
  8461. #if 0
  8462.     if (i == 0)
  8463.       printf("::: action: %d: %x [%d]\n",
  8464.          stored_player[i].MovPos, actual_player_action, FrameCounter);
  8465. #endif
  8466.  
  8467. #if 1
  8468.     PlayerActions(&stored_player[i], actual_player_action);
  8469. #else
  8470.     tape_action[i] = PlayerActions(&stored_player[i], actual_player_action);
  8471.  
  8472.     if (tape.recording && tape_action[i] && !tape.player_participates[i])
  8473.       tape.player_participates[i] = TRUE;    /* player just appeared from CE */
  8474. #endif
  8475.  
  8476.     ScrollPlayer(&stored_player[i], SCROLL_GO_ON);
  8477.   }
  8478.  
  8479. #if 0
  8480.   if (tape.recording)
  8481.     TapeRecordAction(tape_action);
  8482. #endif
  8483.  
  8484.   network_player_action_received = FALSE;
  8485.  
  8486.   ScrollScreen(NULL, SCROLL_GO_ON);
  8487.  
  8488. #if 0
  8489.   FrameCounter++;
  8490.   TimeFrames++;
  8491.  
  8492.   for (i = 0; i < MAX_PLAYERS; i++)
  8493.     stored_player[i].Frame++;
  8494. #endif
  8495.  
  8496. #if 1
  8497.   /* for downwards compatibility, the following code emulates a fixed bug that
  8498.      occured when pushing elements (causing elements that just made their last
  8499.      pushing step to already (if possible) make their first falling step in the
  8500.      same game frame, which is bad); this code is also needed to use the famous
  8501.      "spring push bug" which is used in older levels and might be wanted to be
  8502.      used also in newer levels, but in this case the buggy pushing code is only
  8503.      affecting the "spring" element and no other elements */
  8504.  
  8505. #if 1
  8506.   if (game.engine_version < VERSION_IDENT(2,2,0,7) || level.use_spring_bug)
  8507. #else
  8508.   if (game.engine_version < VERSION_IDENT(2,2,0,7))
  8509. #endif
  8510.   {
  8511.     for (i = 0; i < MAX_PLAYERS; i++)
  8512.     {
  8513.       struct PlayerInfo *player = &stored_player[i];
  8514.       int x = player->jx;
  8515.       int y = player->jy;
  8516.  
  8517. #if 1
  8518.       if (player->active && player->is_pushing && player->is_moving &&
  8519.       IS_MOVING(x, y) &&
  8520.       (game.engine_version < VERSION_IDENT(2,2,0,7) ||
  8521.        Feld[x][y] == EL_SPRING))
  8522. #else
  8523.       if (player->active && player->is_pushing && player->is_moving &&
  8524.       IS_MOVING(x, y))
  8525. #endif
  8526.       {
  8527.     ContinueMoving(x, y);
  8528.  
  8529.     /* continue moving after pushing (this is actually a bug) */
  8530.     if (!IS_MOVING(x, y))
  8531.     {
  8532.       Stop[x][y] = FALSE;
  8533.     }
  8534.       }
  8535.     }
  8536.   }
  8537. #endif
  8538.  
  8539.   for (y = 0; y < lev_fieldy; y++) for (x = 0; x < lev_fieldx; x++)
  8540.   {
  8541.     Changed[x][y] = CE_BITMASK_DEFAULT;
  8542.     ChangeEvent[x][y] = CE_BITMASK_DEFAULT;
  8543.  
  8544. #if DEBUG
  8545.     if (ChangePage[x][y] != -1 && ChangeDelay[x][y] != 1)
  8546.     {
  8547.       printf("GameActions(): x = %d, y = %d: ChangePage != -1\n", x, y);
  8548.       printf("GameActions(): This should never happen!\n");
  8549.  
  8550.       ChangePage[x][y] = -1;
  8551.     }
  8552. #endif
  8553.  
  8554.     Stop[x][y] = FALSE;
  8555.     if (WasJustMoving[x][y] > 0)
  8556.       WasJustMoving[x][y]--;
  8557.     if (WasJustFalling[x][y] > 0)
  8558.       WasJustFalling[x][y]--;
  8559.     if (CheckCollision[x][y] > 0)
  8560.       CheckCollision[x][y]--;
  8561.  
  8562.     GfxFrame[x][y]++;
  8563.  
  8564. #if 1
  8565.     /* reset finished pushing action (not done in ContinueMoving() to allow
  8566.        continous pushing animation for elements with zero push delay) */
  8567.     if (GfxAction[x][y] == ACTION_PUSHING && !IS_MOVING(x, y))
  8568.     {
  8569.       ResetGfxAnimation(x, y);
  8570.       DrawLevelField(x, y);
  8571.     }
  8572. #endif
  8573.  
  8574. #if DEBUG
  8575.     if (IS_BLOCKED(x, y))
  8576.     {
  8577.       int oldx, oldy;
  8578.  
  8579.       Blocked2Moving(x, y, &oldx, &oldy);
  8580.       if (!IS_MOVING(oldx, oldy))
  8581.       {
  8582.     printf("GameActions(): (BLOCKED => MOVING) context corrupted!\n");
  8583.     printf("GameActions(): BLOCKED: x = %d, y = %d\n", x, y);
  8584.     printf("GameActions(): !MOVING: oldx = %d, oldy = %d\n", oldx, oldy);
  8585.     printf("GameActions(): This should never happen!\n");
  8586.       }
  8587.     }
  8588. #endif
  8589.   }
  8590.  
  8591.   for (y = 0; y < lev_fieldy; y++) for (x = 0; x < lev_fieldx; x++)
  8592.   {
  8593.     element = Feld[x][y];
  8594. #if 1
  8595.     graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
  8596. #else
  8597.     graphic = el2img(element);
  8598. #endif
  8599.  
  8600. #if 0
  8601.     if (element == -1)
  8602.     {
  8603.       printf("::: %d,%d: %d [%d]\n", x, y, element, FrameCounter);
  8604.  
  8605.       element = graphic = 0;
  8606.     }
  8607. #endif
  8608.  
  8609.     if (graphic_info[graphic].anim_global_sync)
  8610.       GfxFrame[x][y] = FrameCounter;
  8611.  
  8612.     if (ANIM_MODE(graphic) == ANIM_RANDOM &&
  8613.     IS_NEXT_FRAME(GfxFrame[x][y], graphic))
  8614.       ResetRandomAnimationValue(x, y);
  8615.  
  8616.     SetRandomAnimationValue(x, y);
  8617.  
  8618. #if 1
  8619.     PlayLevelSoundActionIfLoop(x, y, GfxAction[x][y]);
  8620. #endif
  8621.  
  8622.     if (IS_INACTIVE(element))
  8623.     {
  8624.       if (IS_ANIMATED(graphic))
  8625.     DrawLevelGraphicAnimationIfNeeded(x, y, graphic);
  8626.  
  8627.       continue;
  8628.     }
  8629.  
  8630. #if 1
  8631.     /* this may take place after moving, so 'element' may have changed */
  8632. #if 0
  8633.     if (IS_CHANGING(x, y))
  8634. #else
  8635.     if (IS_CHANGING(x, y) &&
  8636.     (game.engine_version < VERSION_IDENT(3,0,7,1) || !Stop[x][y]))
  8637. #endif
  8638.     {
  8639. #if 0
  8640.       ChangeElement(x, y, ChangePage[x][y] != -1 ? ChangePage[x][y] :
  8641.             element_info[element].event_page_nr[CE_DELAY]);
  8642. #else
  8643.       ChangeElement(x, y, element_info[element].event_page_nr[CE_DELAY]);
  8644. #endif
  8645.  
  8646.       element = Feld[x][y];
  8647.       graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
  8648.     }
  8649. #endif
  8650.  
  8651.     if (!IS_MOVING(x, y) && (CAN_FALL(element) || CAN_MOVE(element)))
  8652.     {
  8653.       StartMoving(x, y);
  8654.  
  8655. #if 1
  8656.       element = Feld[x][y];
  8657.       graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
  8658. #if 0
  8659.       if (element == EL_MOLE)
  8660.     printf("::: %d, %d, %d [%d]\n",
  8661.            IS_ANIMATED(graphic), IS_MOVING(x, y), Stop[x][y],
  8662.            GfxAction[x][y]);
  8663. #endif
  8664. #if 0
  8665.       if (element == EL_YAMYAM)
  8666.     printf("::: %d, %d, %d\n",
  8667.            IS_ANIMATED(graphic), IS_MOVING(x, y), Stop[x][y]);
  8668. #endif
  8669. #endif
  8670.  
  8671.       if (IS_ANIMATED(graphic) &&
  8672.       !IS_MOVING(x, y) &&
  8673.       !Stop[x][y])
  8674.       {
  8675.     DrawLevelGraphicAnimationIfNeeded(x, y, graphic);
  8676.  
  8677. #if 0
  8678.     if (element == EL_BUG)
  8679.       printf("::: %d, %d\n", graphic, GfxFrame[x][y]);
  8680. #endif
  8681.  
  8682. #if 0
  8683.     if (element == EL_MOLE)
  8684.       printf("::: %d, %d\n", graphic, GfxFrame[x][y]);
  8685. #endif
  8686.       }
  8687.  
  8688.       if (IS_GEM(element) || element == EL_SP_INFOTRON)
  8689.     EdelsteinFunkeln(x, y);
  8690.     }
  8691.     else if ((element == EL_ACID ||
  8692.           element == EL_EXIT_OPEN ||
  8693.           element == EL_SP_EXIT_OPEN ||
  8694.           element == EL_SP_TERMINAL ||
  8695.           element == EL_SP_TERMINAL_ACTIVE ||
  8696.           element == EL_EXTRA_TIME ||
  8697.           element == EL_SHIELD_NORMAL ||
  8698.           element == EL_SHIELD_DEADLY) &&
  8699.          IS_ANIMATED(graphic))
  8700.       DrawLevelGraphicAnimationIfNeeded(x, y, graphic);
  8701.     else if (IS_MOVING(x, y))
  8702.       ContinueMoving(x, y);
  8703.     else if (IS_ACTIVE_BOMB(element))
  8704.       CheckDynamite(x, y);
  8705. #if 0
  8706.     else if (element == EL_EXPLOSION && !game.explosions_delayed)
  8707.       Explode(x, y, ExplodePhase[x][y], EX_TYPE_NORMAL);
  8708. #endif
  8709.     else if (element == EL_AMOEBA_GROWING)
  8710.       AmoebeWaechst(x, y);
  8711.     else if (element == EL_AMOEBA_SHRINKING)
  8712.       AmoebaDisappearing(x, y);
  8713.  
  8714. #if !USE_NEW_AMOEBA_CODE
  8715.     else if (IS_AMOEBALIVE(element))
  8716.       AmoebeAbleger(x, y);
  8717. #endif
  8718.  
  8719.     else if (element == EL_GAME_OF_LIFE || element == EL_BIOMAZE)
  8720.       Life(x, y);
  8721.     else if (element == EL_EXIT_CLOSED)
  8722.       CheckExit(x, y);
  8723.     else if (element == EL_SP_EXIT_CLOSED)
  8724.       CheckExitSP(x, y);
  8725.     else if (element == EL_EXPANDABLE_WALL_GROWING)
  8726.       MauerWaechst(x, y);
  8727.     else if (element == EL_EXPANDABLE_WALL ||
  8728.          element == EL_EXPANDABLE_WALL_HORIZONTAL ||
  8729.          element == EL_EXPANDABLE_WALL_VERTICAL ||
  8730.          element == EL_EXPANDABLE_WALL_ANY)
  8731.       MauerAbleger(x, y);
  8732.     else if (element == EL_FLAMES)
  8733.       CheckForDragon(x, y);
  8734. #if 0
  8735.     else if (IS_AUTO_CHANGING(element))
  8736.       ChangeElement(x, y);
  8737. #endif
  8738.     else if (element == EL_EXPLOSION)
  8739.       ;    /* drawing of correct explosion animation is handled separately */
  8740.     else if (IS_ANIMATED(graphic) && !IS_CHANGING(x, y))
  8741.       DrawLevelGraphicAnimationIfNeeded(x, y, graphic);
  8742.  
  8743. #if 0
  8744.     /* this may take place after moving, so 'element' may have changed */
  8745.     if (IS_AUTO_CHANGING(Feld[x][y]))
  8746.       ChangeElement(x, y);
  8747. #endif
  8748.  
  8749.     if (IS_BELT_ACTIVE(element))
  8750.       PlayLevelSoundAction(x, y, ACTION_ACTIVE);
  8751.  
  8752.     if (game.magic_wall_active)
  8753.     {
  8754.       int jx = local_player->jx, jy = local_player->jy;
  8755.  
  8756.       /* play the element sound at the position nearest to the player */
  8757.       if ((element == EL_MAGIC_WALL_FULL ||
  8758.        element == EL_MAGIC_WALL_ACTIVE ||
  8759.        element == EL_MAGIC_WALL_EMPTYING ||
  8760.        element == EL_BD_MAGIC_WALL_FULL ||
  8761.        element == EL_BD_MAGIC_WALL_ACTIVE ||
  8762.        element == EL_BD_MAGIC_WALL_EMPTYING) &&
  8763.       ABS(x-jx) + ABS(y-jy) < ABS(magic_wall_x-jx) + ABS(magic_wall_y-jy))
  8764.       {
  8765.     magic_wall_x = x;
  8766.     magic_wall_y = y;
  8767.       }
  8768.     }
  8769.   }
  8770.  
  8771. #if USE_NEW_AMOEBA_CODE
  8772.   /* new experimental amoeba growth stuff */
  8773. #if 1
  8774.   if (!(FrameCounter % 8))
  8775. #endif
  8776.   {
  8777.     static unsigned long random = 1684108901;
  8778.  
  8779.     for (i = 0; i < level.amoeba_speed * 28 / 8; i++)
  8780.     {
  8781. #if 0
  8782.       x = (random >> 10) % lev_fieldx;
  8783.       y = (random >> 20) % lev_fieldy;
  8784. #else
  8785.       x = RND(lev_fieldx);
  8786.       y = RND(lev_fieldy);
  8787. #endif
  8788.       element = Feld[x][y];
  8789.  
  8790. #if 1
  8791.       if (!IS_PLAYER(x,y) &&
  8792.       (element == EL_EMPTY ||
  8793.        CAN_GROW_INTO(element) ||
  8794.        element == EL_QUICKSAND_EMPTY ||
  8795.        element == EL_ACID_SPLASH_LEFT ||
  8796.        element == EL_ACID_SPLASH_RIGHT))
  8797.       {
  8798.     if ((IN_LEV_FIELD(x, y-1) && Feld[x][y-1] == EL_AMOEBA_WET) ||
  8799.         (IN_LEV_FIELD(x-1, y) && Feld[x-1][y] == EL_AMOEBA_WET) ||
  8800.         (IN_LEV_FIELD(x+1, y) && Feld[x+1][y] == EL_AMOEBA_WET) ||
  8801.         (IN_LEV_FIELD(x, y+1) && Feld[x][y+1] == EL_AMOEBA_WET))
  8802.       Feld[x][y] = EL_AMOEBA_DROP;
  8803.       }
  8804. #else
  8805.       /* !!! extend EL_SAND to anything diggable (but maybe not SP_BASE) !!! */
  8806.       if (!IS_PLAYER(x,y) &&
  8807.       (element == EL_EMPTY ||
  8808.        element == EL_SAND ||
  8809.        element == EL_QUICKSAND_EMPTY ||
  8810.        element == EL_ACID_SPLASH_LEFT ||
  8811.        element == EL_ACID_SPLASH_RIGHT))
  8812.       {
  8813.     if ((IN_LEV_FIELD(x, y-1) && Feld[x][y-1] == EL_AMOEBA_WET) ||
  8814.         (IN_LEV_FIELD(x-1, y) && Feld[x-1][y] == EL_AMOEBA_WET) ||
  8815.         (IN_LEV_FIELD(x+1, y) && Feld[x+1][y] == EL_AMOEBA_WET) ||
  8816.         (IN_LEV_FIELD(x, y+1) && Feld[x][y+1] == EL_AMOEBA_WET))
  8817.       Feld[x][y] = EL_AMOEBA_DROP;
  8818.       }
  8819. #endif
  8820.  
  8821.       random = random * 129 + 1;
  8822.     }
  8823.   }
  8824. #endif
  8825.  
  8826. #if 0
  8827.   if (game.explosions_delayed)
  8828. #endif
  8829.   {
  8830.     game.explosions_delayed = FALSE;
  8831.  
  8832.     for (y = 0; y < lev_fieldy; y++) for (x = 0; x < lev_fieldx; x++)
  8833.     {
  8834.       element = Feld[x][y];
  8835.  
  8836.       if (ExplodeField[x][y])
  8837.     Explode(x, y, EX_PHASE_START, ExplodeField[x][y]);
  8838.       else if (element == EL_EXPLOSION)
  8839.     Explode(x, y, ExplodePhase[x][y], EX_TYPE_NORMAL);
  8840.  
  8841.       ExplodeField[x][y] = EX_TYPE_NONE;
  8842.     }
  8843.  
  8844.     game.explosions_delayed = TRUE;
  8845.   }
  8846.  
  8847.   if (game.magic_wall_active)
  8848.   {
  8849.     if (!(game.magic_wall_time_left % 4))
  8850.     {
  8851.       int element = Feld[magic_wall_x][magic_wall_y];
  8852.  
  8853.       if (element == EL_BD_MAGIC_WALL_FULL ||
  8854.       element == EL_BD_MAGIC_WALL_ACTIVE ||
  8855.       element == EL_BD_MAGIC_WALL_EMPTYING)
  8856.     PlayLevelSound(magic_wall_x, magic_wall_y, SND_BD_MAGIC_WALL_ACTIVE);
  8857.       else
  8858.     PlayLevelSound(magic_wall_x, magic_wall_y, SND_MAGIC_WALL_ACTIVE);
  8859.     }
  8860.  
  8861.     if (game.magic_wall_time_left > 0)
  8862.     {
  8863.       game.magic_wall_time_left--;
  8864.       if (!game.magic_wall_time_left)
  8865.       {
  8866.     for (y = 0; y < lev_fieldy; y++) for (x = 0; x < lev_fieldx; x++)
  8867.     {
  8868.       element = Feld[x][y];
  8869.  
  8870.       if (element == EL_MAGIC_WALL_ACTIVE ||
  8871.           element == EL_MAGIC_WALL_FULL)
  8872.       {
  8873.         Feld[x][y] = EL_MAGIC_WALL_DEAD;
  8874.         DrawLevelField(x, y);
  8875.       }
  8876.       else if (element == EL_BD_MAGIC_WALL_ACTIVE ||
  8877.            element == EL_BD_MAGIC_WALL_FULL)
  8878.       {
  8879.         Feld[x][y] = EL_BD_MAGIC_WALL_DEAD;
  8880.         DrawLevelField(x, y);
  8881.       }
  8882.     }
  8883.  
  8884.     game.magic_wall_active = FALSE;
  8885.       }
  8886.     }
  8887.   }
  8888.  
  8889.   if (game.light_time_left > 0)
  8890.   {
  8891.     game.light_time_left--;
  8892.  
  8893.     if (game.light_time_left == 0)
  8894.       RedrawAllLightSwitchesAndInvisibleElements();
  8895.   }
  8896.  
  8897.   if (game.timegate_time_left > 0)
  8898.   {
  8899.     game.timegate_time_left--;
  8900.  
  8901.     if (game.timegate_time_left == 0)
  8902.       CloseAllOpenTimegates();
  8903.   }
  8904.  
  8905.   for (i = 0; i < MAX_PLAYERS; i++)
  8906.   {
  8907.     struct PlayerInfo *player = &stored_player[i];
  8908.  
  8909.     if (SHIELD_ON(player))
  8910.     {
  8911.       if (player->shield_deadly_time_left)
  8912.     PlayLevelSound(player->jx, player->jy, SND_SHIELD_DEADLY_ACTIVE);
  8913.       else if (player->shield_normal_time_left)
  8914.     PlayLevelSound(player->jx, player->jy, SND_SHIELD_NORMAL_ACTIVE);
  8915.     }
  8916.   }
  8917.  
  8918.   if (TimeFrames >= FRAMES_PER_SECOND)
  8919.   {
  8920.     TimeFrames = 0;
  8921.     TapeTime++;
  8922.  
  8923.     for (i = 0; i < MAX_PLAYERS; i++)
  8924.     {
  8925.       struct PlayerInfo *player = &stored_player[i];
  8926.  
  8927.       if (SHIELD_ON(player))
  8928.       {
  8929.     player->shield_normal_time_left--;
  8930.  
  8931.     if (player->shield_deadly_time_left > 0)
  8932.       player->shield_deadly_time_left--;
  8933.       }
  8934.     }
  8935.  
  8936.     if (!level.use_step_counter)
  8937.     {
  8938.       TimePlayed++;
  8939.  
  8940.       if (TimeLeft > 0)
  8941.       {
  8942.     TimeLeft--;
  8943.  
  8944.     if (TimeLeft <= 10 && setup.time_limit)
  8945.       PlaySoundStereo(SND_GAME_RUNNING_OUT_OF_TIME, SOUND_MIDDLE);
  8946.  
  8947.     DrawGameValue_Time(TimeLeft);
  8948.  
  8949.     if (!TimeLeft && setup.time_limit)
  8950.       for (i = 0; i < MAX_PLAYERS; i++)
  8951.         KillHero(&stored_player[i]);
  8952.       }
  8953.       else if (level.time == 0 && !AllPlayersGone) /* level w/o time limit */
  8954.     DrawGameValue_Time(TimePlayed);
  8955.     }
  8956.  
  8957.     if (tape.recording || tape.playing)
  8958.       DrawVideoDisplay(VIDEO_STATE_TIME_ON, TapeTime);
  8959.   }
  8960.  
  8961.   DrawAllPlayers();
  8962.   PlayAllPlayersSound();
  8963.  
  8964.   if (options.debug)            /* calculate frames per second */
  8965.   {
  8966.     static unsigned long fps_counter = 0;
  8967.     static int fps_frames = 0;
  8968.     unsigned long fps_delay_ms = Counter() - fps_counter;
  8969.  
  8970.     fps_frames++;
  8971.  
  8972.     if (fps_delay_ms >= 500)    /* calculate fps every 0.5 seconds */
  8973.     {
  8974.       global.frames_per_second = 1000 * (float)fps_frames / fps_delay_ms;
  8975.  
  8976.       fps_frames = 0;
  8977.       fps_counter = Counter();
  8978.     }
  8979.  
  8980.     redraw_mask |= REDRAW_FPS;
  8981.   }
  8982.  
  8983. #if 0
  8984.   if (stored_player[0].jx != stored_player[0].last_jx ||
  8985.       stored_player[0].jy != stored_player[0].last_jy)
  8986.     printf("::: %d, %d, %d, %d, %d\n",
  8987.        stored_player[0].MovDir,
  8988.        stored_player[0].MovPos,
  8989.        stored_player[0].GfxPos,
  8990.        stored_player[0].Frame,
  8991.        stored_player[0].StepFrame);
  8992. #endif
  8993.  
  8994. #if 1
  8995.   FrameCounter++;
  8996.   TimeFrames++;
  8997.  
  8998.   for (i = 0; i < MAX_PLAYERS; i++)
  8999.   {
  9000.     int move_frames =
  9001.       MOVE_DELAY_NORMAL_SPEED /  stored_player[i].move_delay_value;
  9002.  
  9003.     stored_player[i].Frame += move_frames;
  9004.  
  9005.     if (stored_player[i].MovPos != 0)
  9006.       stored_player[i].StepFrame += move_frames;
  9007.  
  9008.     if (stored_player[i].drop_delay > 0)
  9009.       stored_player[i].drop_delay--;
  9010.   }
  9011. #endif
  9012.  
  9013. #if 1
  9014.   if (local_player->show_envelope != 0 && local_player->MovPos == 0)
  9015.   {
  9016.     ShowEnvelope(local_player->show_envelope - EL_ENVELOPE_1);
  9017.  
  9018.     local_player->show_envelope = 0;
  9019.   }
  9020. #endif
  9021. }
  9022.  
  9023. static boolean AllPlayersInSight(struct PlayerInfo *player, int x, int y)
  9024. {
  9025.   int min_x = x, min_y = y, max_x = x, max_y = y;
  9026.   int i;
  9027.  
  9028.   for (i = 0; i < MAX_PLAYERS; i++)
  9029.   {
  9030.     int jx = stored_player[i].jx, jy = stored_player[i].jy;
  9031.  
  9032.     if (!stored_player[i].active || &stored_player[i] == player)
  9033.       continue;
  9034.  
  9035.     min_x = MIN(min_x, jx);
  9036.     min_y = MIN(min_y, jy);
  9037.     max_x = MAX(max_x, jx);
  9038.     max_y = MAX(max_y, jy);
  9039.   }
  9040.  
  9041.   return (max_x - min_x < SCR_FIELDX && max_y - min_y < SCR_FIELDY);
  9042. }
  9043.  
  9044. static boolean AllPlayersInVisibleScreen()
  9045. {
  9046.   int i;
  9047.  
  9048.   for (i = 0; i < MAX_PLAYERS; i++)
  9049.   {
  9050.     int jx = stored_player[i].jx, jy = stored_player[i].jy;
  9051.  
  9052.     if (!stored_player[i].active)
  9053.       continue;
  9054.  
  9055.     if (!IN_VIS_FIELD(SCREENX(jx), SCREENY(jy)))
  9056.       return FALSE;
  9057.   }
  9058.  
  9059.   return TRUE;
  9060. }
  9061.  
  9062. void ScrollLevel(int dx, int dy)
  9063. {
  9064.   int softscroll_offset = (setup.soft_scrolling ? TILEX : 0);
  9065.   int x, y;
  9066.  
  9067.   BlitBitmap(drawto_field, drawto_field,
  9068.          FX + TILEX * (dx == -1) - softscroll_offset,
  9069.          FY + TILEY * (dy == -1) - softscroll_offset,
  9070.          SXSIZE - TILEX * (dx!=0) + 2 * softscroll_offset,
  9071.          SYSIZE - TILEY * (dy!=0) + 2 * softscroll_offset,
  9072.          FX + TILEX * (dx == 1) - softscroll_offset,
  9073.          FY + TILEY * (dy == 1) - softscroll_offset);
  9074.  
  9075.   if (dx)
  9076.   {
  9077.     x = (dx == 1 ? BX1 : BX2);
  9078.     for (y = BY1; y <= BY2; y++)
  9079.       DrawScreenField(x, y);
  9080.   }
  9081.  
  9082.   if (dy)
  9083.   {
  9084.     y = (dy == 1 ? BY1 : BY2);
  9085.     for (x = BX1; x <= BX2; x++)
  9086.       DrawScreenField(x, y);
  9087.   }
  9088.  
  9089.   redraw_mask |= REDRAW_FIELD;
  9090. }
  9091.  
  9092. #if 0
  9093. static boolean canEnterSupaplexPort(int x, int y, int dx, int dy)
  9094. {
  9095.   int nextx = x + dx, nexty = y + dy;
  9096.   int element = Feld[x][y];
  9097.  
  9098.   if ((dx == -1 &&
  9099.        element != EL_SP_PORT_LEFT &&
  9100.        element != EL_SP_GRAVITY_PORT_LEFT &&
  9101.        element != EL_SP_PORT_HORIZONTAL &&
  9102.        element != EL_SP_PORT_ANY) ||
  9103.       (dx == +1 &&
  9104.        element != EL_SP_PORT_RIGHT &&
  9105.        element != EL_SP_GRAVITY_PORT_RIGHT &&
  9106.        element != EL_SP_PORT_HORIZONTAL &&
  9107.        element != EL_SP_PORT_ANY) ||
  9108.       (dy == -1 &&
  9109.        element != EL_SP_PORT_UP &&
  9110.        element != EL_SP_GRAVITY_PORT_UP &&
  9111.        element != EL_SP_PORT_VERTICAL &&
  9112.        element != EL_SP_PORT_ANY) ||
  9113.       (dy == +1 &&
  9114.        element != EL_SP_PORT_DOWN &&
  9115.        element != EL_SP_GRAVITY_PORT_DOWN &&
  9116.        element != EL_SP_PORT_VERTICAL &&
  9117.        element != EL_SP_PORT_ANY) ||
  9118.       !IN_LEV_FIELD(nextx, nexty) ||
  9119.       !IS_FREE(nextx, nexty))
  9120.     return FALSE;
  9121.  
  9122.   return TRUE;
  9123. }
  9124. #endif
  9125.  
  9126. static boolean canFallDown(struct PlayerInfo *player)
  9127. {
  9128.   int jx = player->jx, jy = player->jy;
  9129.  
  9130.   return (IN_LEV_FIELD(jx, jy + 1) &&
  9131.       (IS_FREE(jx, jy + 1) ||
  9132.        (Feld[jx][jy + 1] == EL_ACID && player->can_fall_into_acid)) &&
  9133.       IS_WALKABLE_FROM(Feld[jx][jy], MV_DOWN) &&
  9134.       !IS_WALKABLE_INSIDE(Feld[jx][jy]));
  9135. }
  9136.  
  9137. static boolean canPassField(int x, int y, int move_dir)
  9138. {
  9139.   int opposite_dir = MV_DIR_OPPOSITE(move_dir);
  9140.   int dx = (move_dir & MV_LEFT ? -1 : move_dir & MV_RIGHT ? +1 : 0);
  9141.   int dy = (move_dir & MV_UP   ? -1 : move_dir & MV_DOWN  ? +1 : 0);
  9142.   int nextx = x + dx;
  9143.   int nexty = y + dy;
  9144.   int element = Feld[x][y];
  9145.  
  9146.   return (IS_PASSABLE_FROM(element, opposite_dir) &&
  9147.       !CAN_MOVE(element) &&
  9148.       IN_LEV_FIELD(nextx, nexty) && !IS_PLAYER(nextx, nexty) &&
  9149.       IS_WALKABLE_FROM(Feld[nextx][nexty], move_dir) &&
  9150.       (level.can_pass_to_walkable || IS_FREE(nextx, nexty)));
  9151. }
  9152.  
  9153. static boolean canMoveToValidFieldWithGravity(int x, int y, int move_dir)
  9154. {
  9155.   int opposite_dir = MV_DIR_OPPOSITE(move_dir);
  9156.   int dx = (move_dir & MV_LEFT ? -1 : move_dir & MV_RIGHT ? +1 : 0);
  9157.   int dy = (move_dir & MV_UP   ? -1 : move_dir & MV_DOWN  ? +1 : 0);
  9158.   int newx = x + dx;
  9159.   int newy = y + dy;
  9160. #if 0
  9161.   int nextx = newx + dx;
  9162.   int nexty = newy + dy;
  9163. #endif
  9164.  
  9165. #if 1
  9166.   return (IN_LEV_FIELD(newx, newy) && !IS_FREE_OR_PLAYER(newx, newy) &&
  9167.       IS_GRAVITY_REACHABLE(Feld[newx][newy]) &&
  9168. #if 0
  9169.       (!IS_SP_PORT(Feld[newx][newy]) || move_dir == MV_UP) &&
  9170. #endif
  9171.       (IS_DIGGABLE(Feld[newx][newy]) ||
  9172.        IS_WALKABLE_FROM(Feld[newx][newy], opposite_dir) ||
  9173.        canPassField(newx, newy, move_dir)));
  9174. #else
  9175. #if 1
  9176.   return (IN_LEV_FIELD(newx, newy) && !IS_FREE_OR_PLAYER(newx, newy) &&
  9177.       IS_GRAVITY_REACHABLE(Feld[newx][newy]) &&
  9178.       (IS_DIGGABLE(Feld[newx][newy]) ||
  9179.        IS_WALKABLE_FROM(Feld[newx][newy], opposite_dir) ||
  9180.        canPassField(newx, newy, move_dir)));
  9181. #else
  9182. #if 1
  9183.   return (IN_LEV_FIELD(newx, newy) && !IS_FREE_OR_PLAYER(newx, newy) &&
  9184.       (IS_DIGGABLE_WITH_GRAVITY(Feld[newx][newy]) ||
  9185.        IS_WALKABLE_FROM(Feld[newx][newy], opposite_dir) ||
  9186.        canPassField(newx, newy, move_dir)));
  9187. #else
  9188.   return (IN_LEV_FIELD(newx, newy) && !IS_FREE_OR_PLAYER(newx, newy) &&
  9189.       (IS_DIGGABLE(Feld[newx][newy]) ||
  9190.        IS_WALKABLE_FROM(Feld[newx][newy], opposite_dir) ||
  9191.        (IS_PASSABLE_FROM(Feld[newx][newy], opposite_dir) &&
  9192.         !CAN_MOVE(Feld[newx][newy]) &&
  9193.         IN_LEV_FIELD(nextx, nexty) && !IS_PLAYER(nextx, nexty) &&
  9194.         IS_WALKABLE_FROM(Feld[nextx][nexty], move_dir) &&
  9195.         (level.can_pass_to_walkable || IS_FREE(nextx, nexty)))));
  9196. #endif
  9197. #endif
  9198. #endif
  9199. }
  9200.  
  9201. static void CheckGravityMovement(struct PlayerInfo *player)
  9202. {
  9203.   if (game.gravity && !player->programmed_action)
  9204.   {
  9205. #if 1
  9206.     int move_dir_horizontal = player->effective_action & MV_HORIZONTAL;
  9207.     int move_dir_vertical   = player->effective_action & MV_VERTICAL;
  9208. #else
  9209.     int move_dir_horizontal = player->action & MV_HORIZONTAL;
  9210.     int move_dir_vertical   = player->action & MV_VERTICAL;
  9211. #endif
  9212.  
  9213. #if 1
  9214.     boolean player_is_snapping = player->effective_action & JOY_BUTTON_1;
  9215. #else
  9216.     boolean player_is_snapping = player->action & JOY_BUTTON_1;
  9217. #endif
  9218.  
  9219.     int jx = player->jx, jy = player->jy;
  9220.  
  9221.     boolean player_is_moving_to_valid_field =
  9222.       (!player_is_snapping &&
  9223.        (canMoveToValidFieldWithGravity(jx, jy, move_dir_horizontal) ||
  9224.     canMoveToValidFieldWithGravity(jx, jy, move_dir_vertical)));
  9225.  
  9226. #if 0
  9227.     int move_dir =
  9228.       (player->last_move_dir & MV_HORIZONTAL ?
  9229.        (move_dir_vertical ? move_dir_vertical : move_dir_horizontal) :
  9230.        (move_dir_horizontal ? move_dir_horizontal : move_dir_vertical));
  9231. #endif
  9232.  
  9233. #if 0
  9234.     int opposite_dir = MV_DIR_OPPOSITE(move_dir);
  9235.     int dx = (move_dir & MV_LEFT ? -1 : move_dir & MV_RIGHT ? +1 : 0);
  9236.     int dy = (move_dir & MV_UP ? -1 : move_dir & MV_DOWN ? +1 : 0);
  9237.     int new_jx = jx + dx, new_jy = jy + dy;
  9238.     int nextx = new_jx + dx, nexty = new_jy + dy;
  9239. #endif
  9240.  
  9241. #if 1
  9242.  
  9243. #if 1
  9244.     boolean player_can_fall_down = canFallDown(player);
  9245. #else
  9246.     boolean player_can_fall_down =
  9247.       (IN_LEV_FIELD(jx, jy + 1) &&
  9248.        (IS_FREE(jx, jy + 1) ||
  9249.     (Feld[jx][jy + 1] == EL_ACID && player->can_fall_into_acid)));
  9250. #endif
  9251.  
  9252. #else
  9253.     boolean player_can_fall_down =
  9254.       (IN_LEV_FIELD(jx, jy + 1) &&
  9255.        (IS_FREE(jx, jy + 1)));
  9256. #endif
  9257.  
  9258. #if 0
  9259.     boolean player_is_moving_to_valid_field =
  9260.       (
  9261. #if 1
  9262.        !player_is_snapping &&
  9263. #endif
  9264.  
  9265. #if 1
  9266.        IN_LEV_FIELD(new_jx, new_jy) &&
  9267.        (IS_DIGGABLE(Feld[new_jx][new_jy]) ||
  9268.     (IS_SP_PORT(Feld[new_jx][new_jy]) &&
  9269.      element_info[Feld[new_jx][new_jy]].access_direction & opposite_dir &&
  9270.      IN_LEV_FIELD(nextx, nexty) &&
  9271.      element_info[Feld[nextx][nexty]].access_direction & move_dir))
  9272. #else
  9273.        IN_LEV_FIELD(new_jx, new_jy) &&
  9274.        (Feld[new_jx][new_jy] == EL_SP_BASE ||
  9275.     Feld[new_jx][new_jy] == EL_SAND ||
  9276.     (IS_SP_PORT(Feld[new_jx][new_jy]) &&
  9277.      canEnterSupaplexPort(new_jx, new_jy, dx, dy)))
  9278.     /* !!! extend EL_SAND to anything diggable !!! */
  9279. #endif
  9280.        );
  9281. #endif
  9282.  
  9283. #if 0
  9284.     boolean player_is_standing_on_valid_field =
  9285.       (IS_WALKABLE_INSIDE(Feld[jx][jy]) ||
  9286.        (IS_WALKABLE(Feld[jx][jy]) && !ACCESS_FROM(Feld[jx][jy], MV_DOWN)));
  9287. #endif
  9288.  
  9289. #if 0
  9290.     printf("::: checking gravity NOW [%d, %d, %d] [%d] [%d / %d] ...\n",
  9291.        player_can_fall_down,
  9292.        player_is_standing_on_valid_field,
  9293.        player_is_moving_to_valid_field,
  9294.        (player_is_moving_to_valid_field ? Feld[new_jx][new_jy] : -1),
  9295.        player->effective_action,
  9296.        player->can_fall_into_acid);
  9297. #endif
  9298.  
  9299.     if (player_can_fall_down &&
  9300. #if 0
  9301.     !player_is_standing_on_valid_field &&
  9302. #endif
  9303.     !player_is_moving_to_valid_field)
  9304.     {
  9305. #if 0
  9306.       printf("::: setting programmed_action to MV_DOWN [%d,%d - %d] ...\n",
  9307.          jx, jy, FrameCounter);
  9308. #endif
  9309.  
  9310.       player->programmed_action = MV_DOWN;
  9311.     }
  9312.   }
  9313. }
  9314.  
  9315. static void CheckGravityMovementWhenNotMoving(struct PlayerInfo *player)
  9316. {
  9317. #if 1
  9318.   return CheckGravityMovement(player);
  9319. #endif
  9320.  
  9321.   if (game.gravity && !player->programmed_action)
  9322.   {
  9323.     int jx = player->jx, jy = player->jy;
  9324.     boolean field_under_player_is_free =
  9325.       (IN_LEV_FIELD(jx, jy + 1) && IS_FREE(jx, jy + 1));
  9326.     boolean player_is_standing_on_valid_field =
  9327.       (IS_WALKABLE_INSIDE(Feld[jx][jy]) ||
  9328.        (IS_WALKABLE(Feld[jx][jy]) &&
  9329.     !(element_info[Feld[jx][jy]].access_direction & MV_DOWN)));
  9330.  
  9331.     if (field_under_player_is_free && !player_is_standing_on_valid_field)
  9332.       player->programmed_action = MV_DOWN;
  9333.   }
  9334. }
  9335.  
  9336. /*
  9337.   MovePlayerOneStep()
  9338.   -----------------------------------------------------------------------------
  9339.   dx, dy:        direction (non-diagonal) to try to move the player to
  9340.   real_dx, real_dy:    direction as read from input device (can be diagonal)
  9341. */
  9342.  
  9343. boolean MovePlayerOneStep(struct PlayerInfo *player,
  9344.               int dx, int dy, int real_dx, int real_dy)
  9345. {
  9346. #if 0
  9347.   static int trigger_sides[4][2] =
  9348.   {
  9349.     /* enter side        leave side */
  9350.     { CH_SIDE_RIGHT,    CH_SIDE_LEFT    },    /* moving left  */
  9351.     { CH_SIDE_LEFT,    CH_SIDE_RIGHT    },    /* moving right */
  9352.     { CH_SIDE_BOTTOM,    CH_SIDE_TOP    },    /* moving up    */
  9353.     { CH_SIDE_TOP,    CH_SIDE_BOTTOM    }    /* moving down  */
  9354.   };
  9355.   int move_direction = (dx == -1 ? MV_LEFT :
  9356.             dx == +1 ? MV_RIGHT :
  9357.             dy == -1 ? MV_UP :
  9358.             dy == +1 ? MV_DOWN : MV_NO_MOVING);
  9359.   int enter_side = trigger_sides[MV_DIR_BIT(move_direction)][0];
  9360.   int leave_side = trigger_sides[MV_DIR_BIT(move_direction)][1];
  9361. #endif
  9362.   int jx = player->jx, jy = player->jy;
  9363.   int new_jx = jx + dx, new_jy = jy + dy;
  9364.   int element;
  9365.   int can_move;
  9366.  
  9367.   if (!player->active || (!dx && !dy))
  9368.     return MF_NO_ACTION;
  9369.  
  9370.   player->MovDir = (dx < 0 ? MV_LEFT :
  9371.             dx > 0 ? MV_RIGHT :
  9372.             dy < 0 ? MV_UP :
  9373.             dy > 0 ? MV_DOWN :    MV_NO_MOVING);
  9374.  
  9375.   if (!IN_LEV_FIELD(new_jx, new_jy))
  9376.     return MF_NO_ACTION;
  9377.  
  9378.   if (!options.network && !AllPlayersInSight(player, new_jx, new_jy))
  9379.     return MF_NO_ACTION;
  9380.  
  9381. #if 0
  9382.   element = MovingOrBlocked2Element(new_jx, new_jy);
  9383. #else
  9384.   element = MovingOrBlocked2ElementIfNotLeaving(new_jx, new_jy);
  9385. #endif
  9386.  
  9387.   if (DONT_RUN_INTO(element))
  9388.   {
  9389.     if (element == EL_ACID && dx == 0 && dy == 1)
  9390.     {
  9391.       SplashAcid(new_jx, new_jy);
  9392.       Feld[jx][jy] = EL_PLAYER_1;
  9393.       InitMovingField(jx, jy, MV_DOWN);
  9394.       Store[jx][jy] = EL_ACID;
  9395.       ContinueMoving(jx, jy);
  9396.       BuryHero(player);
  9397.     }
  9398.     else
  9399.       TestIfHeroRunsIntoBadThing(jx, jy, player->MovDir);
  9400.  
  9401.     return MF_MOVING;
  9402.   }
  9403.  
  9404.   can_move = DigField(player, jx, jy, new_jx, new_jy, real_dx,real_dy, DF_DIG);
  9405.   if (can_move != MF_MOVING)
  9406.     return can_move;
  9407.  
  9408.   /* check if DigField() has caused relocation of the player */
  9409.   if (player->jx != jx || player->jy != jy)
  9410.     return MF_NO_ACTION;
  9411.  
  9412.   StorePlayer[jx][jy] = 0;
  9413.   player->last_jx = jx;
  9414.   player->last_jy = jy;
  9415.   player->jx = new_jx;
  9416.   player->jy = new_jy;
  9417.   StorePlayer[new_jx][new_jy] = player->element_nr;
  9418.  
  9419.   player->MovPos =
  9420.     (dx > 0 || dy > 0 ? -1 : 1) * (TILEX - TILEX / player->move_delay_value);
  9421.  
  9422.   player->step_counter++;
  9423.  
  9424. #if 0
  9425.   player->drop_delay = 0;
  9426. #endif
  9427.  
  9428.   PlayerVisit[jx][jy] = FrameCounter;
  9429.  
  9430.   ScrollPlayer(player, SCROLL_INIT);
  9431.  
  9432. #if 0
  9433.   if (IS_CUSTOM_ELEMENT(Feld[jx][jy]))
  9434.   {
  9435.     CheckTriggeredElementChangeBySide(jx, jy, Feld[jx][jy], CE_OTHER_GETS_LEFT,
  9436.                       leave_side);
  9437.     CheckElementChangeBySide(jx,jy, Feld[jx][jy],CE_LEFT_BY_PLAYER,leave_side);
  9438.   }
  9439.  
  9440.   if (IS_CUSTOM_ELEMENT(Feld[new_jx][new_jy]))
  9441.   {
  9442.     CheckTriggeredElementChangeBySide(new_jx, new_jy, Feld[new_jx][new_jy],
  9443.                       CE_OTHER_GETS_ENTERED, enter_side);
  9444.     CheckElementChangeBySide(new_jx, new_jy, Feld[new_jx][new_jy],
  9445.                  CE_ENTERED_BY_PLAYER, enter_side);
  9446.   }
  9447. #endif
  9448.  
  9449.   return MF_MOVING;
  9450. }
  9451.  
  9452. boolean MovePlayer(struct PlayerInfo *player, int dx, int dy)
  9453. {
  9454.   int jx = player->jx, jy = player->jy;
  9455.   int old_jx = jx, old_jy = jy;
  9456.   int moved = MF_NO_ACTION;
  9457.  
  9458. #if 1
  9459.   if (!player->active)
  9460.     return FALSE;
  9461.  
  9462.   if (!dx && !dy)
  9463.   {
  9464.     if (player->MovPos == 0)
  9465.     {
  9466.       player->is_moving = FALSE;
  9467.       player->is_digging = FALSE;
  9468.       player->is_collecting = FALSE;
  9469.       player->is_snapping = FALSE;
  9470.       player->is_pushing = FALSE;
  9471.     }
  9472.  
  9473.     return FALSE;
  9474.   }
  9475. #else
  9476.   if (!player->active || (!dx && !dy))
  9477.     return FALSE;
  9478. #endif
  9479.  
  9480. #if 0
  9481.   if (!FrameReached(&player->move_delay, player->move_delay_value) &&
  9482.       !tape.playing)
  9483.     return FALSE;
  9484. #else
  9485.  
  9486. #if 1
  9487.   if (!FrameReached(&player->move_delay, player->move_delay_value))
  9488.     return FALSE;
  9489. #else
  9490.   if (!FrameReached(&player->move_delay, player->move_delay_value) &&
  9491.       !(tape.playing && tape.file_version < FILE_VERSION_2_0))
  9492.     return FALSE;
  9493. #endif
  9494.  
  9495. #endif
  9496.  
  9497.   /* store if player is automatically moved to next field */
  9498.   player->is_auto_moving = (player->programmed_action != MV_NO_MOVING);
  9499.  
  9500.   /* remove the last programmed player action */
  9501.   player->programmed_action = 0;
  9502.  
  9503.   if (player->MovPos)
  9504.   {
  9505.     /* should only happen if pre-1.2 tape recordings are played */
  9506.     /* this is only for backward compatibility */
  9507.  
  9508.     int original_move_delay_value = player->move_delay_value;
  9509.  
  9510. #if DEBUG
  9511.     printf("THIS SHOULD ONLY HAPPEN WITH PRE-1.2 LEVEL TAPES. [%ld]\n",
  9512.        tape.counter);
  9513. #endif
  9514.  
  9515.     /* scroll remaining steps with finest movement resolution */
  9516.     player->move_delay_value = MOVE_DELAY_NORMAL_SPEED;
  9517.  
  9518.     while (player->MovPos)
  9519.     {
  9520.       ScrollPlayer(player, SCROLL_GO_ON);
  9521.       ScrollScreen(NULL, SCROLL_GO_ON);
  9522.       FrameCounter++;
  9523.       DrawAllPlayers();
  9524.       BackToFront();
  9525.     }
  9526.  
  9527.     player->move_delay_value = original_move_delay_value;
  9528.   }
  9529.  
  9530.   if (player->last_move_dir & MV_HORIZONTAL)
  9531.   {
  9532.     if (!(moved |= MovePlayerOneStep(player, 0, dy, dx, dy)))
  9533.       moved |= MovePlayerOneStep(player, dx, 0, dx, dy);
  9534.   }
  9535.   else
  9536.   {
  9537.     if (!(moved |= MovePlayerOneStep(player, dx, 0, dx, dy)))
  9538.       moved |= MovePlayerOneStep(player, 0, dy, dx, dy);
  9539.   }
  9540.  
  9541.   jx = player->jx;
  9542.   jy = player->jy;
  9543.  
  9544.   if (moved & MF_MOVING && !ScreenMovPos &&
  9545.       (player == local_player || !options.network))
  9546.   {
  9547.     int old_scroll_x = scroll_x, old_scroll_y = scroll_y;
  9548.     int offset = (setup.scroll_delay ? 3 : 0);
  9549.  
  9550.     if (!IN_VIS_FIELD(SCREENX(jx), SCREENY(jy)))
  9551.     {
  9552.       /* actual player has left the screen -- scroll in that direction */
  9553.       if (jx != old_jx)        /* player has moved horizontally */
  9554.     scroll_x += (jx - old_jx);
  9555.       else            /* player has moved vertically */
  9556.     scroll_y += (jy - old_jy);
  9557.     }
  9558.     else
  9559.     {
  9560.       if (jx != old_jx)        /* player has moved horizontally */
  9561.       {
  9562.      if ((player->MovDir == MV_LEFT  && scroll_x > jx - MIDPOSX + offset) ||
  9563.         (player->MovDir == MV_RIGHT && scroll_x < jx - MIDPOSX - offset))
  9564.       scroll_x = jx-MIDPOSX + (scroll_x < jx-MIDPOSX ? -offset : +offset);
  9565.  
  9566.     /* don't scroll over playfield boundaries */
  9567.     if (scroll_x < SBX_Left || scroll_x > SBX_Right)
  9568.       scroll_x = (scroll_x < SBX_Left ? SBX_Left : SBX_Right);
  9569.  
  9570.     /* don't scroll more than one field at a time */
  9571.     scroll_x = old_scroll_x + SIGN(scroll_x - old_scroll_x);
  9572.  
  9573.     /* don't scroll against the player's moving direction */
  9574.     if ((player->MovDir == MV_LEFT  && scroll_x > old_scroll_x) ||
  9575.         (player->MovDir == MV_RIGHT && scroll_x < old_scroll_x))
  9576.       scroll_x = old_scroll_x;
  9577.       }
  9578.       else            /* player has moved vertically */
  9579.       {
  9580.     if ((player->MovDir == MV_UP   && scroll_y > jy - MIDPOSY + offset) ||
  9581.         (player->MovDir == MV_DOWN && scroll_y < jy - MIDPOSY - offset))
  9582.       scroll_y = jy-MIDPOSY + (scroll_y < jy-MIDPOSY ? -offset : +offset);
  9583.  
  9584.     /* don't scroll over playfield boundaries */
  9585.     if (scroll_y < SBY_Upper || scroll_y > SBY_Lower)
  9586.       scroll_y = (scroll_y < SBY_Upper ? SBY_Upper : SBY_Lower);
  9587.  
  9588.     /* don't scroll more than one field at a time */
  9589.     scroll_y = old_scroll_y + SIGN(scroll_y - old_scroll_y);
  9590.  
  9591.     /* don't scroll against the player's moving direction */
  9592.     if ((player->MovDir == MV_UP   && scroll_y > old_scroll_y) ||
  9593.         (player->MovDir == MV_DOWN && scroll_y < old_scroll_y))
  9594.       scroll_y = old_scroll_y;
  9595.       }
  9596.     }
  9597.  
  9598.     if (scroll_x != old_scroll_x || scroll_y != old_scroll_y)
  9599.     {
  9600.       if (!options.network && !AllPlayersInVisibleScreen())
  9601.       {
  9602.     scroll_x = old_scroll_x;
  9603.     scroll_y = old_scroll_y;
  9604.       }
  9605.       else
  9606.       {
  9607.     ScrollScreen(player, SCROLL_INIT);
  9608.     ScrollLevel(old_scroll_x - scroll_x, old_scroll_y - scroll_y);
  9609.       }
  9610.     }
  9611.   }
  9612.  
  9613. #if 0
  9614. #if 1
  9615.   InitPlayerGfxAnimation(player, ACTION_DEFAULT);
  9616. #else
  9617.   if (!(moved & MF_MOVING) && !player->is_pushing)
  9618.     player->Frame = 0;
  9619. #endif
  9620. #endif
  9621.  
  9622.   player->StepFrame = 0;
  9623.  
  9624.   if (moved & MF_MOVING)
  9625.   {
  9626.     if (old_jx != jx && old_jy == jy)
  9627.       player->MovDir = (old_jx < jx ? MV_RIGHT : MV_LEFT);
  9628.     else if (old_jx == jx && old_jy != jy)
  9629.       player->MovDir = (old_jy < jy ? MV_DOWN : MV_UP);
  9630.  
  9631.     DrawLevelField(jx, jy);    /* for "crumbled sand" */
  9632.  
  9633.     player->last_move_dir = player->MovDir;
  9634.     player->is_moving = TRUE;
  9635. #if 1
  9636.     player->is_snapping = FALSE;
  9637. #endif
  9638.  
  9639. #if 1
  9640.     player->is_switching = FALSE;
  9641. #endif
  9642.  
  9643.     player->is_dropping = FALSE;
  9644.  
  9645.  
  9646. #if 0
  9647.     /* !!! ENABLE THIS FOR OLD VERSIONS !!! */
  9648.  
  9649. #if 1
  9650.     if (game.engine_version < VERSION_IDENT(3,1,0,0))
  9651. #endif
  9652.     {
  9653.       int move_direction = player->MovDir;
  9654. #if 1
  9655.       int enter_side = MV_DIR_OPPOSITE(move_direction);
  9656.       int leave_side = move_direction;
  9657. #else
  9658.       static int trigger_sides[4][2] =
  9659.       {
  9660.     /* enter side           leave side */
  9661.     { CH_SIDE_RIGHT,    CH_SIDE_LEFT    },    /* moving left  */
  9662.     { CH_SIDE_LEFT,        CH_SIDE_RIGHT    },    /* moving right */
  9663.     { CH_SIDE_BOTTOM,    CH_SIDE_TOP    },    /* moving up    */
  9664.     { CH_SIDE_TOP,        CH_SIDE_BOTTOM    }    /* moving down  */
  9665.       };
  9666.       int enter_side = trigger_sides[MV_DIR_BIT(move_direction)][0];
  9667.       int leave_side = trigger_sides[MV_DIR_BIT(move_direction)][1];
  9668. #endif
  9669.       int old_element = Feld[old_jx][old_jy];
  9670.       int new_element = Feld[jx][jy];
  9671.  
  9672. #if 1
  9673.       /* !!! TEST ONLY !!! */
  9674.       if (IS_CUSTOM_ELEMENT(old_element))
  9675.     CheckElementChangeByPlayer(old_jx, old_jy, old_element,
  9676.                    CE_LEFT_BY_PLAYER,
  9677.                    player->index_bit, leave_side);
  9678.  
  9679.       CheckTriggeredElementChangeByPlayer(old_jx, old_jy, old_element,
  9680.                       CE_OTHER_GETS_LEFT,
  9681.                       player->index_bit, leave_side);
  9682.  
  9683.       if (IS_CUSTOM_ELEMENT(new_element))
  9684.     CheckElementChangeByPlayer(jx, jy, new_element, CE_ENTERED_BY_PLAYER,
  9685.                    player->index_bit, enter_side);
  9686.  
  9687.       CheckTriggeredElementChangeByPlayer(jx, jy, new_element,
  9688.                       CE_OTHER_GETS_ENTERED,
  9689.                       player->index_bit, enter_side);
  9690. #endif
  9691.  
  9692.     }
  9693. #endif
  9694.  
  9695.  
  9696.   }
  9697.   else
  9698.   {
  9699.     CheckGravityMovementWhenNotMoving(player);
  9700.  
  9701.     /*
  9702.     player->last_move_dir = MV_NO_MOVING;
  9703.     */
  9704.     player->is_moving = FALSE;
  9705.   }
  9706.  
  9707.   if (game.engine_version < VERSION_IDENT(3,0,7,0))
  9708.   {
  9709.     TestIfHeroTouchesBadThing(jx, jy);
  9710.     TestIfPlayerTouchesCustomElement(jx, jy);
  9711.   }
  9712.  
  9713.   if (!player->active)
  9714.     RemoveHero(player);
  9715.  
  9716.   return moved;
  9717. }
  9718.  
  9719. void ScrollPlayer(struct PlayerInfo *player, int mode)
  9720. {
  9721.   int jx = player->jx, jy = player->jy;
  9722.   int last_jx = player->last_jx, last_jy = player->last_jy;
  9723.   int move_stepsize = TILEX / player->move_delay_value;
  9724.  
  9725.   if (!player->active || !player->MovPos)
  9726.     return;
  9727.  
  9728.   if (mode == SCROLL_INIT)
  9729.   {
  9730.     player->actual_frame_counter = FrameCounter;
  9731.     player->GfxPos = move_stepsize * (player->MovPos / move_stepsize);
  9732.  
  9733.     if (Feld[last_jx][last_jy] == EL_EMPTY)
  9734.       Feld[last_jx][last_jy] = EL_PLAYER_IS_LEAVING;
  9735.  
  9736. #if 0
  9737.     DrawPlayer(player);
  9738. #endif
  9739.  
  9740.     return;
  9741.   }
  9742.   else if (!FrameReached(&player->actual_frame_counter, 1))
  9743.     return;
  9744.  
  9745.   player->MovPos += (player->MovPos > 0 ? -1 : 1) * move_stepsize;
  9746.   player->GfxPos = move_stepsize * (player->MovPos / move_stepsize);
  9747.  
  9748.   if (!player->block_last_field &&
  9749.       Feld[last_jx][last_jy] == EL_PLAYER_IS_LEAVING)
  9750.     Feld[last_jx][last_jy] = EL_EMPTY;
  9751.  
  9752.   /* before DrawPlayer() to draw correct player graphic for this case */
  9753.   if (player->MovPos == 0)
  9754.     CheckGravityMovement(player);
  9755.  
  9756. #if 0
  9757.   DrawPlayer(player);    /* needed here only to cleanup last field */
  9758. #endif
  9759.  
  9760.   if (player->MovPos == 0)    /* player reached destination field */
  9761.   {
  9762. #if 1
  9763.     if (player->move_delay_reset_counter > 0)
  9764.     {
  9765.       player->move_delay_reset_counter--;
  9766.  
  9767.       if (player->move_delay_reset_counter == 0)
  9768.       {
  9769.     /* continue with normal speed after quickly moving through gate */
  9770.     HALVE_PLAYER_SPEED(player);
  9771.  
  9772.     /* be able to make the next move without delay */
  9773.     player->move_delay = 0;
  9774.       }
  9775.     }
  9776. #else
  9777.     if (IS_PASSABLE(Feld[last_jx][last_jy]))
  9778.     {
  9779.       /* continue with normal speed after quickly moving through gate */
  9780.       HALVE_PLAYER_SPEED(player);
  9781.  
  9782.       /* be able to make the next move without delay */
  9783.       player->move_delay = 0;
  9784.     }
  9785. #endif
  9786.  
  9787.     if (player->block_last_field &&
  9788.     Feld[last_jx][last_jy] == EL_PLAYER_IS_LEAVING)
  9789.       Feld[last_jx][last_jy] = EL_EMPTY;
  9790.  
  9791.     player->last_jx = jx;
  9792.     player->last_jy = jy;
  9793.  
  9794.     if (Feld[jx][jy] == EL_EXIT_OPEN ||
  9795.     Feld[jx][jy] == EL_SP_EXIT_OPEN ||
  9796.     Feld[jx][jy] == EL_SP_EXIT_OPENING)    /* <-- special case */
  9797.     {
  9798.       DrawPlayer(player);    /* needed here only to cleanup last field */
  9799.       RemoveHero(player);
  9800.  
  9801.       if (local_player->friends_still_needed == 0 ||
  9802.       IS_SP_ELEMENT(Feld[jx][jy]))
  9803.     player->LevelSolved = player->GameOver = TRUE;
  9804.     }
  9805.  
  9806. #if 1
  9807.     /* !!! ENABLE THIS FOR NEW VERSIONS !!! */
  9808.     /* this breaks one level: "machine", level 000 */
  9809. #if 0
  9810.     if (game.engine_version >= VERSION_IDENT(3,1,0,0))
  9811. #endif
  9812.     {
  9813.       int move_direction = player->MovDir;
  9814. #if 1
  9815.       int enter_side = MV_DIR_OPPOSITE(move_direction);
  9816.       int leave_side = move_direction;
  9817. #else
  9818.       static int trigger_sides[4][2] =
  9819.       {
  9820.     /* enter side           leave side */
  9821.     { CH_SIDE_RIGHT,    CH_SIDE_LEFT    },    /* moving left  */
  9822.     { CH_SIDE_LEFT,        CH_SIDE_RIGHT    },    /* moving right */
  9823.     { CH_SIDE_BOTTOM,    CH_SIDE_TOP    },    /* moving up    */
  9824.     { CH_SIDE_TOP,        CH_SIDE_BOTTOM    }    /* moving down  */
  9825.       };
  9826.       int enter_side = trigger_sides[MV_DIR_BIT(move_direction)][0];
  9827.       int leave_side = trigger_sides[MV_DIR_BIT(move_direction)][1];
  9828. #endif
  9829.       int old_jx = last_jx;
  9830.       int old_jy = last_jy;
  9831.       int old_element = Feld[old_jx][old_jy];
  9832.       int new_element = Feld[jx][jy];
  9833.  
  9834. #if 1
  9835.       /* !!! TEST ONLY !!! */
  9836.       if (IS_CUSTOM_ELEMENT(old_element))
  9837.     CheckElementChangeByPlayer(old_jx, old_jy, old_element,
  9838.                    CE_LEFT_BY_PLAYER,
  9839.                    player->index_bit, leave_side);
  9840.  
  9841.       CheckTriggeredElementChangeByPlayer(old_jx, old_jy, old_element,
  9842.                       CE_OTHER_GETS_LEFT,
  9843.                       player->index_bit, leave_side);
  9844.  
  9845.       if (IS_CUSTOM_ELEMENT(new_element))
  9846.     CheckElementChangeByPlayer(jx, jy, new_element, CE_ENTERED_BY_PLAYER,
  9847.                    player->index_bit, enter_side);
  9848.  
  9849.       CheckTriggeredElementChangeByPlayer(jx, jy, new_element,
  9850.                       CE_OTHER_GETS_ENTERED,
  9851.                       player->index_bit, enter_side);
  9852. #endif
  9853.  
  9854.     }
  9855. #endif
  9856.  
  9857.     if (game.engine_version >= VERSION_IDENT(3,0,7,0))
  9858.     {
  9859.       TestIfHeroTouchesBadThing(jx, jy);
  9860.       TestIfPlayerTouchesCustomElement(jx, jy);
  9861. #if 1
  9862. #if 1
  9863.       /* needed because pushed element has not yet reached its destination,
  9864.      so it would trigger a change event at its previous field location */
  9865.       if (!player->is_pushing)
  9866. #endif
  9867.     TestIfElementTouchesCustomElement(jx, jy);    /* for empty space */
  9868. #endif
  9869.  
  9870.       if (!player->active)
  9871.     RemoveHero(player);
  9872.     }
  9873.  
  9874.     if (level.use_step_counter)
  9875.     {
  9876.       int i;
  9877.  
  9878.       TimePlayed++;
  9879.  
  9880.       if (TimeLeft > 0)
  9881.       {
  9882.     TimeLeft--;
  9883.  
  9884.     if (TimeLeft <= 10 && setup.time_limit)
  9885.       PlaySoundStereo(SND_GAME_RUNNING_OUT_OF_TIME, SOUND_MIDDLE);
  9886.  
  9887.     DrawGameValue_Time(TimeLeft);
  9888.  
  9889.     if (!TimeLeft && setup.time_limit)
  9890.       for (i = 0; i < MAX_PLAYERS; i++)
  9891.         KillHero(&stored_player[i]);
  9892.       }
  9893.       else if (level.time == 0 && !AllPlayersGone) /* level w/o time limit */
  9894.     DrawGameValue_Time(TimePlayed);
  9895.     }
  9896.  
  9897.     if (tape.single_step && tape.recording && !tape.pausing &&
  9898.     !player->programmed_action)
  9899.       TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
  9900.   }
  9901. }
  9902.  
  9903. void ScrollScreen(struct PlayerInfo *player, int mode)
  9904. {
  9905.   static unsigned long screen_frame_counter = 0;
  9906.  
  9907.   if (mode == SCROLL_INIT)
  9908.   {
  9909.     /* set scrolling step size according to actual player's moving speed */
  9910.     ScrollStepSize = TILEX / player->move_delay_value;
  9911.  
  9912.     screen_frame_counter = FrameCounter;
  9913.     ScreenMovDir = player->MovDir;
  9914.     ScreenMovPos = player->MovPos;
  9915.     ScreenGfxPos = ScrollStepSize * (ScreenMovPos / ScrollStepSize);
  9916.     return;
  9917.   }
  9918.   else if (!FrameReached(&screen_frame_counter, 1))
  9919.     return;
  9920.  
  9921.   if (ScreenMovPos)
  9922.   {
  9923.     ScreenMovPos += (ScreenMovPos > 0 ? -1 : 1) * ScrollStepSize;
  9924.     ScreenGfxPos = ScrollStepSize * (ScreenMovPos / ScrollStepSize);
  9925.     redraw_mask |= REDRAW_FIELD;
  9926.   }
  9927.   else
  9928.     ScreenMovDir = MV_NO_MOVING;
  9929. }
  9930.  
  9931. void TestIfPlayerTouchesCustomElement(int x, int y)
  9932. {
  9933.   static int xy[4][2] =
  9934.   {
  9935.     { 0, -1 },
  9936.     { -1, 0 },
  9937.     { +1, 0 },
  9938.     { 0, +1 }
  9939.   };
  9940.   static int trigger_sides[4][2] =
  9941.   {
  9942.     /* center side       border side */
  9943.     { CH_SIDE_TOP,    CH_SIDE_BOTTOM    },    /* check top    */
  9944.     { CH_SIDE_LEFT,    CH_SIDE_RIGHT    },    /* check left   */
  9945.     { CH_SIDE_RIGHT,    CH_SIDE_LEFT    },    /* check right  */
  9946.     { CH_SIDE_BOTTOM,    CH_SIDE_TOP    }    /* check bottom */
  9947.   };
  9948.   static int touch_dir[4] =
  9949.   {
  9950.     MV_LEFT | MV_RIGHT,
  9951.     MV_UP   | MV_DOWN,
  9952.     MV_UP   | MV_DOWN,
  9953.     MV_LEFT | MV_RIGHT
  9954.   };
  9955.   int center_element = Feld[x][y];    /* should always be non-moving! */
  9956.   int i;
  9957.  
  9958.   for (i = 0; i < NUM_DIRECTIONS; i++)
  9959.   {
  9960.     int xx = x + xy[i][0];
  9961.     int yy = y + xy[i][1];
  9962.     int center_side = trigger_sides[i][0];
  9963.     int border_side = trigger_sides[i][1];
  9964.     int border_element;
  9965.  
  9966.     if (!IN_LEV_FIELD(xx, yy))
  9967.       continue;
  9968.  
  9969.     if (IS_PLAYER(x, y))
  9970.     {
  9971.       struct PlayerInfo *player = PLAYERINFO(x, y);
  9972.  
  9973.       if (game.engine_version < VERSION_IDENT(3,0,7,0))
  9974.     border_element = Feld[xx][yy];        /* may be moving! */
  9975.       else if (!IS_MOVING(xx, yy) && !IS_BLOCKED(xx, yy))
  9976.     border_element = Feld[xx][yy];
  9977.       else if (MovDir[xx][yy] & touch_dir[i])    /* elements are touching */
  9978.     border_element = MovingOrBlocked2Element(xx, yy);
  9979.       else
  9980.     continue;        /* center and border element do not touch */
  9981.  
  9982. #if 1
  9983.       /* !!! TEST ONLY !!! */
  9984.       CheckElementChangeByPlayer(xx, yy, border_element, CE_TOUCHED_BY_PLAYER,
  9985.                  player->index_bit, border_side);
  9986.       CheckTriggeredElementChangeByPlayer(xx, yy, border_element,
  9987.                       CE_OTHER_GETS_TOUCHED,
  9988.                       player->index_bit, border_side);
  9989. #else
  9990.       CheckTriggeredElementChangeByPlayer(xx, yy, border_element,
  9991.                       CE_OTHER_GETS_TOUCHED,
  9992.                       player->index_bit, border_side);
  9993.       CheckElementChangeByPlayer(xx, yy, border_element, CE_TOUCHED_BY_PLAYER,
  9994.                  player->index_bit, border_side);
  9995. #endif
  9996.     }
  9997.     else if (IS_PLAYER(xx, yy))
  9998.     {
  9999.       struct PlayerInfo *player = PLAYERINFO(xx, yy);
  10000.  
  10001.       if (game.engine_version >= VERSION_IDENT(3,0,7,0))
  10002.       {
  10003.     if (player->MovPos != 0 && !(player->MovDir & touch_dir[i]))
  10004.       continue;        /* center and border element do not touch */
  10005.       }
  10006.  
  10007. #if 1
  10008.       /* !!! TEST ONLY !!! */
  10009.       CheckElementChangeByPlayer(x, y, center_element, CE_TOUCHED_BY_PLAYER,
  10010.                  player->index_bit, center_side);
  10011.       CheckTriggeredElementChangeByPlayer(x, y, center_element,
  10012.                       CE_OTHER_GETS_TOUCHED,
  10013.                       player->index_bit, center_side);
  10014. #else
  10015.       CheckTriggeredElementChangeByPlayer(x, y, center_element,
  10016.                       CE_OTHER_GETS_TOUCHED,
  10017.                       player->index_bit, center_side);
  10018.       CheckElementChangeByPlayer(x, y, center_element, CE_TOUCHED_BY_PLAYER,
  10019.                  player->index_bit, center_side);
  10020. #endif
  10021.  
  10022.       break;
  10023.     }
  10024.   }
  10025. }
  10026.  
  10027. void TestIfElementTouchesCustomElement(int x, int y)
  10028. {
  10029.   static int xy[4][2] =
  10030.   {
  10031.     { 0, -1 },
  10032.     { -1, 0 },
  10033.     { +1, 0 },
  10034.     { 0, +1 }
  10035.   };
  10036.   static int trigger_sides[4][2] =
  10037.   {
  10038.     /* center side    border side */
  10039.     { CH_SIDE_TOP,    CH_SIDE_BOTTOM    },    /* check top    */
  10040.     { CH_SIDE_LEFT,    CH_SIDE_RIGHT    },    /* check left   */
  10041.     { CH_SIDE_RIGHT,    CH_SIDE_LEFT    },    /* check right  */
  10042.     { CH_SIDE_BOTTOM,    CH_SIDE_TOP    }    /* check bottom */
  10043.   };
  10044.   static int touch_dir[4] =
  10045.   {
  10046.     MV_LEFT | MV_RIGHT,
  10047.     MV_UP   | MV_DOWN,
  10048.     MV_UP   | MV_DOWN,
  10049.     MV_LEFT | MV_RIGHT
  10050.   };
  10051.   boolean change_center_element = FALSE;
  10052.   int center_element_change_page = 0;
  10053.   int center_element = Feld[x][y];    /* should always be non-moving! */
  10054.   int border_trigger_element = EL_UNDEFINED;
  10055.   int i, j;
  10056.  
  10057.   for (i = 0; i < NUM_DIRECTIONS; i++)
  10058.   {
  10059.     int xx = x + xy[i][0];
  10060.     int yy = y + xy[i][1];
  10061.     int center_side = trigger_sides[i][0];
  10062.     int border_side = trigger_sides[i][1];
  10063.     int border_element;
  10064.  
  10065.     if (!IN_LEV_FIELD(xx, yy))
  10066.       continue;
  10067.  
  10068.     if (game.engine_version < VERSION_IDENT(3,0,7,0))
  10069.       border_element = Feld[xx][yy];    /* may be moving! */
  10070.     else if (!IS_MOVING(xx, yy) && !IS_BLOCKED(xx, yy))
  10071.       border_element = Feld[xx][yy];
  10072.     else if (MovDir[xx][yy] & touch_dir[i])    /* elements are touching */
  10073.       border_element = MovingOrBlocked2Element(xx, yy);
  10074.     else
  10075.       continue;            /* center and border element do not touch */
  10076.  
  10077.     /* check for change of center element (but change it only once) */
  10078.     if (IS_CUSTOM_ELEMENT(center_element) &&
  10079.     HAS_ANY_CHANGE_EVENT(center_element, CE_OTHER_IS_TOUCHING) &&
  10080.     !change_center_element)
  10081.     {
  10082.       for (j = 0; j < element_info[center_element].num_change_pages; j++)
  10083.       {
  10084.     struct ElementChangeInfo *change =
  10085.       &element_info[center_element].change_page[j];
  10086.  
  10087.     if (change->can_change &&
  10088.         change->events & CH_EVENT_BIT(CE_OTHER_IS_TOUCHING) &&
  10089.         change->trigger_side & border_side &&
  10090. #if 1
  10091.         IS_EQUAL_OR_IN_GROUP(border_element, change->trigger_element)
  10092. #else
  10093.         change->trigger_element == border_element
  10094. #endif
  10095.         )
  10096.     {
  10097.       change_center_element = TRUE;
  10098.       center_element_change_page = j;
  10099.       border_trigger_element = border_element;
  10100.  
  10101.       break;
  10102.     }
  10103.       }
  10104.     }
  10105.  
  10106.     /* check for change of border element */
  10107.     if (IS_CUSTOM_ELEMENT(border_element) &&
  10108.     HAS_ANY_CHANGE_EVENT(border_element, CE_OTHER_IS_TOUCHING))
  10109.     {
  10110.       for (j = 0; j < element_info[border_element].num_change_pages; j++)
  10111.       {
  10112.     struct ElementChangeInfo *change =
  10113.       &element_info[border_element].change_page[j];
  10114.  
  10115.     if (change->can_change &&
  10116.         change->events & CH_EVENT_BIT(CE_OTHER_IS_TOUCHING) &&
  10117.         change->trigger_side & center_side &&
  10118. #if 1
  10119.         IS_EQUAL_OR_IN_GROUP(center_element, change->trigger_element)
  10120. #else
  10121.         change->trigger_element == center_element
  10122. #endif
  10123.         )
  10124.     {
  10125. #if 0
  10126.       printf("::: border_element %d, %d\n", x, y);
  10127. #endif
  10128.  
  10129.       CheckElementChangeByPage(xx, yy, border_element, center_element,
  10130.                    CE_OTHER_IS_TOUCHING, j);
  10131.       break;
  10132.     }
  10133.       }
  10134.     }
  10135.   }
  10136.  
  10137.   if (change_center_element)
  10138.   {
  10139. #if 0
  10140.     printf("::: center_element %d, %d\n", x, y);
  10141. #endif
  10142.  
  10143.     CheckElementChangeByPage(x, y, center_element, border_trigger_element,
  10144.                  CE_OTHER_IS_TOUCHING, center_element_change_page);
  10145.   }
  10146. }
  10147.  
  10148. void TestIfElementHitsCustomElement(int x, int y, int direction)
  10149. {
  10150.   int dx = (direction == MV_LEFT ? -1 : direction == MV_RIGHT ? +1 : 0);
  10151.   int dy = (direction == MV_UP   ? -1 : direction == MV_DOWN  ? +1 : 0);
  10152.   int hitx = x + dx, hity = y + dy;
  10153.   int hitting_element = Feld[x][y];
  10154.   int touched_element;
  10155. #if 0
  10156.   boolean object_hit = (IN_LEV_FIELD(hitx, hity) &&
  10157.             !IS_FREE(hitx, hity) &&
  10158.             (!IS_MOVING(hitx, hity) ||
  10159.              MovDir[hitx][hity] != direction ||
  10160.              ABS(MovPos[hitx][hity]) <= TILEY / 2));
  10161. #endif
  10162.  
  10163.   if (IN_LEV_FIELD(hitx, hity) && IS_FREE(hitx, hity))
  10164.     return;
  10165.  
  10166. #if 0
  10167.   if (IN_LEV_FIELD(hitx, hity) && !object_hit)
  10168.     return;
  10169. #endif
  10170.  
  10171.   touched_element = (IN_LEV_FIELD(hitx, hity) ?
  10172.              MovingOrBlocked2Element(hitx, hity) : EL_STEELWALL);
  10173.  
  10174.   CheckElementChangeBySide(x, y, hitting_element, touched_element,
  10175.                CE_HITTING_SOMETHING, direction);
  10176.  
  10177.   if (IN_LEV_FIELD(hitx, hity))
  10178.   {
  10179.     int opposite_direction = MV_DIR_OPPOSITE(direction);
  10180.     int hitting_side = direction;
  10181.     int touched_side = opposite_direction;
  10182. #if 0
  10183.     int touched_element = MovingOrBlocked2Element(hitx, hity);
  10184. #endif
  10185. #if 1
  10186.     boolean object_hit = (!IS_MOVING(hitx, hity) ||
  10187.               MovDir[hitx][hity] != direction ||
  10188.               ABS(MovPos[hitx][hity]) <= TILEY / 2);
  10189.  
  10190.     object_hit = TRUE;
  10191. #endif
  10192.  
  10193.     if (object_hit)
  10194.     {
  10195.       int i;
  10196.  
  10197.       CheckElementChangeBySide(hitx, hity, touched_element, hitting_element,
  10198.                    CE_HIT_BY_SOMETHING, opposite_direction);
  10199.  
  10200.       if (IS_CUSTOM_ELEMENT(hitting_element) &&
  10201.       HAS_ANY_CHANGE_EVENT(hitting_element, CE_OTHER_IS_HITTING))
  10202.       {
  10203.     for (i = 0; i < element_info[hitting_element].num_change_pages; i++)
  10204.     {
  10205.       struct ElementChangeInfo *change =
  10206.         &element_info[hitting_element].change_page[i];
  10207.  
  10208.       if (change->can_change &&
  10209.           change->events & CH_EVENT_BIT(CE_OTHER_IS_HITTING) &&
  10210.           change->trigger_side & touched_side &&
  10211.       
  10212. #if 1
  10213.           IS_EQUAL_OR_IN_GROUP(touched_element, change->trigger_element)
  10214. #else
  10215.           change->trigger_element == touched_element
  10216. #endif
  10217.           )
  10218.       {
  10219.         CheckElementChangeByPage(x, y, hitting_element, touched_element,
  10220.                      CE_OTHER_IS_HITTING, i);
  10221.         break;
  10222.       }
  10223.     }
  10224.       }
  10225.  
  10226.       if (IS_CUSTOM_ELEMENT(touched_element) &&
  10227.       HAS_ANY_CHANGE_EVENT(touched_element, CE_OTHER_GETS_HIT))
  10228.       {
  10229.     for (i = 0; i < element_info[touched_element].num_change_pages; i++)
  10230.     {
  10231.       struct ElementChangeInfo *change =
  10232.         &element_info[touched_element].change_page[i];
  10233.  
  10234.       if (change->can_change &&
  10235.           change->events & CH_EVENT_BIT(CE_OTHER_GETS_HIT) &&
  10236.           change->trigger_side & hitting_side &&
  10237. #if 1
  10238.           IS_EQUAL_OR_IN_GROUP(hitting_element, change->trigger_element)
  10239. #else
  10240.           change->trigger_element == hitting_element
  10241. #endif
  10242.           )
  10243.       {
  10244.         CheckElementChangeByPage(hitx, hity, touched_element,
  10245.                      hitting_element, CE_OTHER_GETS_HIT, i);
  10246.         break;
  10247.       }
  10248.     }
  10249.       }
  10250.     }
  10251.   }
  10252. }
  10253.  
  10254. #if 0
  10255. void TestIfElementSmashesCustomElement(int x, int y, int direction)
  10256. {
  10257.   int dx = (direction == MV_LEFT ? -1 : direction == MV_RIGHT ? +1 : 0);
  10258.   int dy = (direction == MV_UP   ? -1 : direction == MV_DOWN  ? +1 : 0);
  10259.   int hitx = x + dx, hity = y + dy;
  10260.   int hitting_element = Feld[x][y];
  10261.   int touched_element;
  10262. #if 0
  10263.   boolean object_hit = (IN_LEV_FIELD(hitx, hity) &&
  10264.             !IS_FREE(hitx, hity) &&
  10265.             (!IS_MOVING(hitx, hity) ||
  10266.              MovDir[hitx][hity] != direction ||
  10267.              ABS(MovPos[hitx][hity]) <= TILEY / 2));
  10268. #endif
  10269.  
  10270.   if (IN_LEV_FIELD(hitx, hity) && IS_FREE(hitx, hity))
  10271.     return;
  10272.  
  10273. #if 0
  10274.   if (IN_LEV_FIELD(hitx, hity) && !object_hit)
  10275.     return;
  10276. #endif
  10277.  
  10278.   touched_element = (IN_LEV_FIELD(hitx, hity) ?
  10279.              MovingOrBlocked2Element(hitx, hity) : EL_STEELWALL);
  10280.  
  10281.   CheckElementChangeBySide(x, y, hitting_element, touched_element,
  10282.                EP_CAN_SMASH_EVERYTHING, direction);
  10283.  
  10284.   if (IN_LEV_FIELD(hitx, hity))
  10285.   {
  10286.     int opposite_direction = MV_DIR_OPPOSITE(direction);
  10287.     int hitting_side = direction;
  10288.     int touched_side = opposite_direction;
  10289. #if 0
  10290.     int touched_element = MovingOrBlocked2Element(hitx, hity);
  10291. #endif
  10292. #if 1
  10293.     boolean object_hit = (!IS_MOVING(hitx, hity) ||
  10294.               MovDir[hitx][hity] != direction ||
  10295.               ABS(MovPos[hitx][hity]) <= TILEY / 2);
  10296.  
  10297.     object_hit = TRUE;
  10298. #endif
  10299.  
  10300.     if (object_hit)
  10301.     {
  10302.       int i;
  10303.  
  10304.       CheckElementChangeBySide(hitx, hity, touched_element, hitting_element,
  10305.                    CE_SMASHED_BY_SOMETHING, opposite_direction);
  10306.  
  10307.       if (IS_CUSTOM_ELEMENT(hitting_element) &&
  10308.       HAS_ANY_CHANGE_EVENT(hitting_element, CE_OTHER_IS_SMASHING))
  10309.       {
  10310.     for (i = 0; i < element_info[hitting_element].num_change_pages; i++)
  10311.     {
  10312.       struct ElementChangeInfo *change =
  10313.         &element_info[hitting_element].change_page[i];
  10314.  
  10315.       if (change->can_change &&
  10316.           change->events & CH_EVENT_BIT(CE_OTHER_IS_SMASHING) &&
  10317.           change->trigger_side & touched_side &&
  10318.       
  10319. #if 1
  10320.           IS_EQUAL_OR_IN_GROUP(touched_element, change->trigger_element)
  10321. #else
  10322.           change->trigger_element == touched_element
  10323. #endif
  10324.           )
  10325.       {
  10326.         CheckElementChangeByPage(x, y, hitting_element, touched_element,
  10327.                      CE_OTHER_IS_SMASHING, i);
  10328.         break;
  10329.       }
  10330.     }
  10331.       }
  10332.  
  10333.       if (IS_CUSTOM_ELEMENT(touched_element) &&
  10334.       HAS_ANY_CHANGE_EVENT(touched_element, CE_OTHER_GETS_SMASHED))
  10335.       {
  10336.     for (i = 0; i < element_info[touched_element].num_change_pages; i++)
  10337.     {
  10338.       struct ElementChangeInfo *change =
  10339.         &element_info[touched_element].change_page[i];
  10340.  
  10341.       if (change->can_change &&
  10342.           change->events & CH_EVENT_BIT(CE_OTHER_GETS_SMASHED) &&
  10343.           change->trigger_side & hitting_side &&
  10344. #if 1
  10345.           IS_EQUAL_OR_IN_GROUP(hitting_element, change->trigger_element)
  10346. #else
  10347.           change->trigger_element == hitting_element
  10348. #endif
  10349.           )
  10350.       {
  10351.         CheckElementChangeByPage(hitx, hity, touched_element,
  10352.                      hitting_element, CE_OTHER_GETS_SMASHED,i);
  10353.         break;
  10354.       }
  10355.     }
  10356.       }
  10357.     }
  10358.   }
  10359. }
  10360. #endif
  10361.  
  10362. void TestIfGoodThingHitsBadThing(int good_x, int good_y, int good_move_dir)
  10363. {
  10364.   int i, kill_x = -1, kill_y = -1;
  10365.   int bad_element = -1;
  10366.   static int test_xy[4][2] =
  10367.   {
  10368.     { 0, -1 },
  10369.     { -1, 0 },
  10370.     { +1, 0 },
  10371.     { 0, +1 }
  10372.   };
  10373.   static int test_dir[4] =
  10374.   {
  10375.     MV_UP,
  10376.     MV_LEFT,
  10377.     MV_RIGHT,
  10378.     MV_DOWN
  10379.   };
  10380.  
  10381.   for (i = 0; i < NUM_DIRECTIONS; i++)
  10382.   {
  10383.     int test_x, test_y, test_move_dir, test_element;
  10384.  
  10385.     test_x = good_x + test_xy[i][0];
  10386.     test_y = good_y + test_xy[i][1];
  10387.  
  10388.     if (!IN_LEV_FIELD(test_x, test_y))
  10389.       continue;
  10390.  
  10391.     test_move_dir =
  10392.       (IS_MOVING(test_x, test_y) ? MovDir[test_x][test_y] : MV_NO_MOVING);
  10393.  
  10394. #if 0
  10395.     test_element = Feld[test_x][test_y];
  10396. #else
  10397.     test_element = MovingOrBlocked2ElementIfNotLeaving(test_x, test_y);
  10398. #endif
  10399.  
  10400.     /* 1st case: good thing is moving towards DONT_RUN_INTO style bad thing;
  10401.        2nd case: DONT_TOUCH style bad thing does not move away from good thing
  10402.     */
  10403.     if ((DONT_RUN_INTO(test_element) && good_move_dir == test_dir[i]) ||
  10404.     (DONT_TOUCH(test_element)    && test_move_dir != test_dir[i]))
  10405.     {
  10406.       kill_x = test_x;
  10407.       kill_y = test_y;
  10408.       bad_element = test_element;
  10409.  
  10410.       break;
  10411.     }
  10412.   }
  10413.  
  10414.   if (kill_x != -1 || kill_y != -1)
  10415.   {
  10416.     if (IS_PLAYER(good_x, good_y))
  10417.     {
  10418.       struct PlayerInfo *player = PLAYERINFO(good_x, good_y);
  10419.  
  10420. #if 1
  10421.       if (player->shield_deadly_time_left > 0 &&
  10422.       !IS_INDESTRUCTIBLE(bad_element))
  10423.     Bang(kill_x, kill_y);
  10424.       else if (!PLAYER_ENEMY_PROTECTED(good_x, good_y))
  10425.     KillHero(player);
  10426. #else
  10427.       if (player->shield_deadly_time_left > 0)
  10428.     Bang(kill_x, kill_y);
  10429.       else if (!PLAYER_ENEMY_PROTECTED(good_x, good_y))
  10430.     KillHero(player);
  10431. #endif
  10432.     }
  10433.     else
  10434.       Bang(good_x, good_y);
  10435.   }
  10436. }
  10437.  
  10438. void TestIfBadThingHitsGoodThing(int bad_x, int bad_y, int bad_move_dir)
  10439. {
  10440.   int i, kill_x = -1, kill_y = -1;
  10441.   int bad_element = Feld[bad_x][bad_y];
  10442.   static int test_xy[4][2] =
  10443.   {
  10444.     { 0, -1 },
  10445.     { -1, 0 },
  10446.     { +1, 0 },
  10447.     { 0, +1 }
  10448.   };
  10449.   static int touch_dir[4] =
  10450.   {
  10451.     MV_LEFT | MV_RIGHT,
  10452.     MV_UP   | MV_DOWN,
  10453.     MV_UP   | MV_DOWN,
  10454.     MV_LEFT | MV_RIGHT
  10455.   };
  10456.   static int test_dir[4] =
  10457.   {
  10458.     MV_UP,
  10459.     MV_LEFT,
  10460.     MV_RIGHT,
  10461.     MV_DOWN
  10462.   };
  10463.  
  10464.   if (bad_element == EL_EXPLOSION)    /* skip just exploding bad things */
  10465.     return;
  10466.  
  10467.   for (i = 0; i < NUM_DIRECTIONS; i++)
  10468.   {
  10469.     int test_x, test_y, test_move_dir, test_element;
  10470.  
  10471.     test_x = bad_x + test_xy[i][0];
  10472.     test_y = bad_y + test_xy[i][1];
  10473.     if (!IN_LEV_FIELD(test_x, test_y))
  10474.       continue;
  10475.  
  10476.     test_move_dir =
  10477.       (IS_MOVING(test_x, test_y) ? MovDir[test_x][test_y] : MV_NO_MOVING);
  10478.  
  10479.     test_element = Feld[test_x][test_y];
  10480.  
  10481.     /* 1st case: good thing is moving towards DONT_RUN_INTO style bad thing;
  10482.        2nd case: DONT_TOUCH style bad thing does not move away from good thing
  10483.     */
  10484.     if ((DONT_RUN_INTO(bad_element) &&  bad_move_dir == test_dir[i]) ||
  10485.     (DONT_TOUCH(bad_element)    && test_move_dir != test_dir[i]))
  10486.     {
  10487.       /* good thing is player or penguin that does not move away */
  10488.       if (IS_PLAYER(test_x, test_y))
  10489.       {
  10490.     struct PlayerInfo *player = PLAYERINFO(test_x, test_y);
  10491.  
  10492.     if (bad_element == EL_ROBOT && player->is_moving)
  10493.       continue;    /* robot does not kill player if he is moving */
  10494.  
  10495.     if (game.engine_version >= VERSION_IDENT(3,0,7,0))
  10496.     {
  10497.       if (player->MovPos != 0 && !(player->MovDir & touch_dir[i]))
  10498.         continue;        /* center and border element do not touch */
  10499.     }
  10500.  
  10501.     kill_x = test_x;
  10502.     kill_y = test_y;
  10503.     break;
  10504.       }
  10505.       else if (test_element == EL_PENGUIN)
  10506.       {
  10507.     kill_x = test_x;
  10508.     kill_y = test_y;
  10509.     break;
  10510.       }
  10511.     }
  10512.   }
  10513.  
  10514.   if (kill_x != -1 || kill_y != -1)
  10515.   {
  10516.     if (IS_PLAYER(kill_x, kill_y))
  10517.     {
  10518.       struct PlayerInfo *player = PLAYERINFO(kill_x, kill_y);
  10519.  
  10520. #if 1
  10521.       if (player->shield_deadly_time_left > 0 &&
  10522.       !IS_INDESTRUCTIBLE(bad_element))
  10523.     Bang(bad_x, bad_y);
  10524.       else if (!PLAYER_ENEMY_PROTECTED(kill_x, kill_y))
  10525.     KillHero(player);
  10526. #else
  10527.       if (player->shield_deadly_time_left > 0)
  10528.     Bang(bad_x, bad_y);
  10529.       else if (!PLAYER_ENEMY_PROTECTED(kill_x, kill_y))
  10530.     KillHero(player);
  10531. #endif
  10532.     }
  10533.     else
  10534.       Bang(kill_x, kill_y);
  10535.   }
  10536. }
  10537.  
  10538. void TestIfHeroTouchesBadThing(int x, int y)
  10539. {
  10540.   TestIfGoodThingHitsBadThing(x, y, MV_NO_MOVING);
  10541. }
  10542.  
  10543. void TestIfHeroRunsIntoBadThing(int x, int y, int move_dir)
  10544. {
  10545.   TestIfGoodThingHitsBadThing(x, y, move_dir);
  10546. }
  10547.  
  10548. void TestIfBadThingTouchesHero(int x, int y)
  10549. {
  10550.   TestIfBadThingHitsGoodThing(x, y, MV_NO_MOVING);
  10551. }
  10552.  
  10553. void TestIfBadThingRunsIntoHero(int x, int y, int move_dir)
  10554. {
  10555.   TestIfBadThingHitsGoodThing(x, y, move_dir);
  10556. }
  10557.  
  10558. void TestIfFriendTouchesBadThing(int x, int y)
  10559. {
  10560.   TestIfGoodThingHitsBadThing(x, y, MV_NO_MOVING);
  10561. }
  10562.  
  10563. void TestIfBadThingTouchesFriend(int x, int y)
  10564. {
  10565.   TestIfBadThingHitsGoodThing(x, y, MV_NO_MOVING);
  10566. }
  10567.  
  10568. void TestIfBadThingTouchesOtherBadThing(int bad_x, int bad_y)
  10569. {
  10570.   int i, kill_x = bad_x, kill_y = bad_y;
  10571.   static int xy[4][2] =
  10572.   {
  10573.     { 0, -1 },
  10574.     { -1, 0 },
  10575.     { +1, 0 },
  10576.     { 0, +1 }
  10577.   };
  10578.  
  10579.   for (i = 0; i < NUM_DIRECTIONS; i++)
  10580.   {
  10581.     int x, y, element;
  10582.  
  10583.     x = bad_x + xy[i][0];
  10584.     y = bad_y + xy[i][1];
  10585.     if (!IN_LEV_FIELD(x, y))
  10586.       continue;
  10587.  
  10588.     element = Feld[x][y];
  10589.     if (IS_AMOEBOID(element) || element == EL_GAME_OF_LIFE ||
  10590.     element == EL_AMOEBA_GROWING || element == EL_AMOEBA_DROP)
  10591.     {
  10592.       kill_x = x;
  10593.       kill_y = y;
  10594.       break;
  10595.     }
  10596.   }
  10597.  
  10598.   if (kill_x != bad_x || kill_y != bad_y)
  10599.     Bang(bad_x, bad_y);
  10600. }
  10601.  
  10602. void KillHero(struct PlayerInfo *player)
  10603. {
  10604.   int jx = player->jx, jy = player->jy;
  10605.  
  10606.   if (!player->active)
  10607.     return;
  10608.  
  10609.   /* remove accessible field at the player's position */
  10610.   Feld[jx][jy] = EL_EMPTY;
  10611.  
  10612.   /* deactivate shield (else Bang()/Explode() would not work right) */
  10613.   player->shield_normal_time_left = 0;
  10614.   player->shield_deadly_time_left = 0;
  10615.  
  10616.   Bang(jx, jy);
  10617.   BuryHero(player);
  10618. }
  10619.  
  10620. static void KillHeroUnlessEnemyProtected(int x, int y)
  10621. {
  10622.   if (!PLAYER_ENEMY_PROTECTED(x, y))
  10623.     KillHero(PLAYERINFO(x, y));
  10624. }
  10625.  
  10626. static void KillHeroUnlessExplosionProtected(int x, int y)
  10627. {
  10628.   if (!PLAYER_EXPLOSION_PROTECTED(x, y))
  10629.     KillHero(PLAYERINFO(x, y));
  10630. }
  10631.  
  10632. void BuryHero(struct PlayerInfo *player)
  10633. {
  10634.   int jx = player->jx, jy = player->jy;
  10635.  
  10636.   if (!player->active)
  10637.     return;
  10638.  
  10639. #if 1
  10640.   PlayLevelSoundElementAction(jx, jy, player->element_nr, ACTION_DYING);
  10641. #else
  10642.   PlayLevelSound(jx, jy, SND_CLASS_PLAYER_DYING);
  10643. #endif
  10644.   PlayLevelSound(jx, jy, SND_GAME_LOSING);
  10645.  
  10646.   player->GameOver = TRUE;
  10647.   RemoveHero(player);
  10648. }
  10649.  
  10650. void RemoveHero(struct PlayerInfo *player)
  10651. {
  10652.   int jx = player->jx, jy = player->jy;
  10653.   int i, found = FALSE;
  10654.  
  10655.   player->present = FALSE;
  10656.   player->active = FALSE;
  10657.  
  10658.   if (!ExplodeField[jx][jy])
  10659.     StorePlayer[jx][jy] = 0;
  10660.  
  10661.   for (i = 0; i < MAX_PLAYERS; i++)
  10662.     if (stored_player[i].active)
  10663.       found = TRUE;
  10664.  
  10665.   if (!found)
  10666.     AllPlayersGone = TRUE;
  10667.  
  10668.   ExitX = ZX = jx;
  10669.   ExitY = ZY = jy;
  10670. }
  10671.  
  10672. /*
  10673.   =============================================================================
  10674.   checkDiagonalPushing()
  10675.   -----------------------------------------------------------------------------
  10676.   check if diagonal input device direction results in pushing of object
  10677.   (by checking if the alternative direction is walkable, diggable, ...)
  10678.   =============================================================================
  10679. */
  10680.  
  10681. static boolean checkDiagonalPushing(struct PlayerInfo *player,
  10682.                     int x, int y, int real_dx, int real_dy)
  10683. {
  10684.   int jx, jy, dx, dy, xx, yy;
  10685.  
  10686.   if (real_dx == 0 || real_dy == 0)    /* no diagonal direction => push */
  10687.     return TRUE;
  10688.  
  10689.   /* diagonal direction: check alternative direction */
  10690.   jx = player->jx;
  10691.   jy = player->jy;
  10692.   dx = x - jx;
  10693.   dy = y - jy;
  10694.   xx = jx + (dx == 0 ? real_dx : 0);
  10695.   yy = jy + (dy == 0 ? real_dy : 0);
  10696.  
  10697.   return (!IN_LEV_FIELD(xx, yy) || IS_SOLID_FOR_PUSHING(Feld[xx][yy]));
  10698. }
  10699.  
  10700. /*
  10701.   =============================================================================
  10702.   DigField()
  10703.   -----------------------------------------------------------------------------
  10704.   x, y:            field next to player (non-diagonal) to try to dig to
  10705.   real_dx, real_dy:    direction as read from input device (can be diagonal)
  10706.   =============================================================================
  10707. */
  10708.  
  10709. int DigField(struct PlayerInfo *player,
  10710.          int oldx, int oldy, int x, int y,
  10711.          int real_dx, int real_dy, int mode)
  10712. {
  10713. #if 0
  10714.   boolean use_spring_bug = (game.engine_version < VERSION_IDENT(2,2,0,0));
  10715. #endif
  10716.   boolean is_player = (IS_PLAYER(oldx, oldy) || mode != DF_DIG);
  10717.   boolean player_was_pushing = player->is_pushing;
  10718.   int jx = oldx, jy = oldy;
  10719.   int dx = x - jx, dy = y - jy;
  10720.   int nextx = x + dx, nexty = y + dy;
  10721.   int move_direction = (dx == -1 ? MV_LEFT :
  10722.             dx == +1 ? MV_RIGHT :
  10723.             dy == -1 ? MV_UP :
  10724.             dy == +1 ? MV_DOWN : MV_NO_MOVING);
  10725.   int opposite_direction = MV_DIR_OPPOSITE(move_direction);
  10726. #if 1
  10727.   int dig_side = MV_DIR_OPPOSITE(move_direction);
  10728. #else
  10729.   static int trigger_sides[4] =
  10730.   {
  10731.     CH_SIDE_RIGHT,    /* moving left  */
  10732.     CH_SIDE_LEFT,    /* moving right */
  10733.     CH_SIDE_BOTTOM,    /* moving up    */
  10734.     CH_SIDE_TOP,    /* moving down  */
  10735.   };
  10736.   int dig_side = trigger_sides[MV_DIR_BIT(move_direction)];
  10737. #endif
  10738.   int old_element = Feld[jx][jy];
  10739.   int element;
  10740.  
  10741.   if (is_player)        /* function can also be called by EL_PENGUIN */
  10742.   {
  10743.     if (player->MovPos == 0)
  10744.     {
  10745.       player->is_digging = FALSE;
  10746.       player->is_collecting = FALSE;
  10747.     }
  10748.  
  10749.     if (player->MovPos == 0)    /* last pushing move finished */
  10750.       player->is_pushing = FALSE;
  10751.  
  10752.     if (mode == DF_NO_PUSH)    /* player just stopped pushing */
  10753.     {
  10754.       player->is_switching = FALSE;
  10755.       player->push_delay = 0;
  10756.  
  10757.       return MF_NO_ACTION;
  10758.     }
  10759.   }
  10760.  
  10761.   if (IS_MOVING(x, y) || IS_PLAYER(x, y))
  10762.     return MF_NO_ACTION;
  10763.  
  10764. #if 0
  10765.  
  10766. #if 0
  10767.   if (IS_TUBE(Feld[jx][jy]) || IS_TUBE(Back[jx][jy]))
  10768. #else
  10769.   if (IS_TUBE(Feld[jx][jy]) ||
  10770.       (IS_TUBE(Back[jx][jy]) && game.engine_version >= VERSION_IDENT(2,2,0,0)))
  10771. #endif
  10772.   {
  10773.     int i = 0;
  10774.     int tube_element = (IS_TUBE(Feld[jx][jy]) ? Feld[jx][jy] : Back[jx][jy]);
  10775.     int tube_leave_directions[][2] =
  10776.     {
  10777.       { EL_TUBE_ANY,            MV_LEFT | MV_RIGHT | MV_UP | MV_DOWN },
  10778.       { EL_TUBE_VERTICAL,                             MV_UP | MV_DOWN },
  10779.       { EL_TUBE_HORIZONTAL,        MV_LEFT | MV_RIGHT                   },
  10780.       { EL_TUBE_VERTICAL_LEFT,        MV_LEFT |            MV_UP | MV_DOWN },
  10781.       { EL_TUBE_VERTICAL_RIGHT,                  MV_RIGHT | MV_UP | MV_DOWN },
  10782.       { EL_TUBE_HORIZONTAL_UP,        MV_LEFT | MV_RIGHT | MV_UP           },
  10783.       { EL_TUBE_HORIZONTAL_DOWN,    MV_LEFT | MV_RIGHT |         MV_DOWN },
  10784.       { EL_TUBE_LEFT_UP,        MV_LEFT |            MV_UP           },
  10785.       { EL_TUBE_LEFT_DOWN,        MV_LEFT |                    MV_DOWN },
  10786.       { EL_TUBE_RIGHT_UP,                  MV_RIGHT | MV_UP           },
  10787.       { EL_TUBE_RIGHT_DOWN,                  MV_RIGHT |         MV_DOWN },
  10788.       { -1,                         MV_LEFT | MV_RIGHT | MV_UP | MV_DOWN }
  10789.     };
  10790.  
  10791.     while (tube_leave_directions[i][0] != tube_element)
  10792.     {
  10793.       i++;
  10794.       if (tube_leave_directions[i][0] == -1)    /* should not happen */
  10795.     break;
  10796.     }
  10797.  
  10798.     if (!(tube_leave_directions[i][1] & move_direction))
  10799.       return MF_NO_ACTION;    /* tube has no opening in this direction */
  10800.   }
  10801.  
  10802. #else
  10803.  
  10804.   if (IS_TUBE(Back[jx][jy]) && game.engine_version >= VERSION_IDENT(2,2,0,0))
  10805.     old_element = Back[jx][jy];
  10806.  
  10807. #endif
  10808.  
  10809.   if (IS_WALKABLE(old_element) && !ACCESS_FROM(old_element, move_direction))
  10810.     return MF_NO_ACTION;    /* field has no opening in this direction */
  10811.  
  10812.   if (IS_PASSABLE(old_element) && !ACCESS_FROM(old_element,opposite_direction))
  10813.     return MF_NO_ACTION;    /* field has no opening in this direction */
  10814.  
  10815.   element = Feld[x][y];
  10816.  
  10817.   if (!is_player && !IS_COLLECTIBLE(element))    /* penguin cannot collect it */
  10818.     return MF_NO_ACTION;
  10819.  
  10820.   if (mode == DF_SNAP && !IS_SNAPPABLE(element) &&
  10821.       game.engine_version >= VERSION_IDENT(2,2,0,0))
  10822.     return MF_NO_ACTION;
  10823.  
  10824. #if 1
  10825.   if (game.gravity && is_player && !player->is_auto_moving &&
  10826.       canFallDown(player) && move_direction != MV_DOWN &&
  10827.       !canMoveToValidFieldWithGravity(jx, jy, move_direction))
  10828.     return MF_NO_ACTION;    /* player cannot walk here due to gravity */
  10829. #endif
  10830.  
  10831. #if 0
  10832.   if (element == EL_EMPTY_SPACE &&
  10833.       game.gravity && !player->is_auto_moving &&
  10834.       canFallDown(player) && move_direction != MV_DOWN)
  10835.     return MF_NO_ACTION;    /* player cannot walk here due to gravity */
  10836. #endif
  10837.  
  10838.   switch (element)
  10839.   {
  10840. #if 0
  10841.     case EL_SP_PORT_LEFT:
  10842.     case EL_SP_PORT_RIGHT:
  10843.     case EL_SP_PORT_UP:
  10844.     case EL_SP_PORT_DOWN:
  10845.     case EL_SP_PORT_HORIZONTAL:
  10846.     case EL_SP_PORT_VERTICAL:
  10847.     case EL_SP_PORT_ANY:
  10848.     case EL_SP_GRAVITY_PORT_LEFT:
  10849.     case EL_SP_GRAVITY_PORT_RIGHT:
  10850.     case EL_SP_GRAVITY_PORT_UP:
  10851.     case EL_SP_GRAVITY_PORT_DOWN:
  10852. #if 1
  10853.       if (!canEnterSupaplexPort(x, y, dx, dy))
  10854.     return MF_NO_ACTION;
  10855. #else
  10856.       if ((dx == -1 &&
  10857.        element != EL_SP_PORT_LEFT &&
  10858.        element != EL_SP_GRAVITY_PORT_LEFT &&
  10859.        element != EL_SP_PORT_HORIZONTAL &&
  10860.        element != EL_SP_PORT_ANY) ||
  10861.       (dx == +1 &&
  10862.        element != EL_SP_PORT_RIGHT &&
  10863.        element != EL_SP_GRAVITY_PORT_RIGHT &&
  10864.        element != EL_SP_PORT_HORIZONTAL &&
  10865.        element != EL_SP_PORT_ANY) ||
  10866.       (dy == -1 &&
  10867.        element != EL_SP_PORT_UP &&
  10868.        element != EL_SP_GRAVITY_PORT_UP &&
  10869.        element != EL_SP_PORT_VERTICAL &&
  10870.        element != EL_SP_PORT_ANY) ||
  10871.       (dy == +1 &&
  10872.        element != EL_SP_PORT_DOWN &&
  10873.        element != EL_SP_GRAVITY_PORT_DOWN &&
  10874.        element != EL_SP_PORT_VERTICAL &&
  10875.        element != EL_SP_PORT_ANY) ||
  10876.       !IN_LEV_FIELD(nextx, nexty) ||
  10877.       !IS_FREE(nextx, nexty))
  10878.     return MF_NO_ACTION;
  10879. #endif
  10880.  
  10881.       if (element == EL_SP_GRAVITY_PORT_LEFT ||
  10882.       element == EL_SP_GRAVITY_PORT_RIGHT ||
  10883.       element == EL_SP_GRAVITY_PORT_UP ||
  10884.       element == EL_SP_GRAVITY_PORT_DOWN)
  10885.     game.gravity = !game.gravity;
  10886.  
  10887.       /* automatically move to the next field with double speed */
  10888.       player->programmed_action = move_direction;
  10889. #if 1
  10890.       if (player->move_delay_reset_counter == 0)
  10891.       {
  10892.     player->move_delay_reset_counter = 2;    /* two double speed steps */
  10893.  
  10894.     DOUBLE_PLAYER_SPEED(player);
  10895.       }
  10896. #else
  10897.       player->move_delay_reset_counter = 2;
  10898.  
  10899.       DOUBLE_PLAYER_SPEED(player);
  10900. #endif
  10901.  
  10902. #if 0
  10903.       printf("::: passing port %d,%d [%d]\n", x, y, FrameCounter);
  10904. #endif
  10905.  
  10906.       PlayLevelSound(x, y, SND_CLASS_SP_PORT_PASSING);
  10907.       break;
  10908. #endif
  10909.  
  10910. #if 0
  10911.     case EL_TUBE_ANY:
  10912.     case EL_TUBE_VERTICAL:
  10913.     case EL_TUBE_HORIZONTAL:
  10914.     case EL_TUBE_VERTICAL_LEFT:
  10915.     case EL_TUBE_VERTICAL_RIGHT:
  10916.     case EL_TUBE_HORIZONTAL_UP:
  10917.     case EL_TUBE_HORIZONTAL_DOWN:
  10918.     case EL_TUBE_LEFT_UP:
  10919.     case EL_TUBE_LEFT_DOWN:
  10920.     case EL_TUBE_RIGHT_UP:
  10921.     case EL_TUBE_RIGHT_DOWN:
  10922.       {
  10923.     int i = 0;
  10924.     int tube_enter_directions[][2] =
  10925.     {
  10926.       { EL_TUBE_ANY,        MV_LEFT | MV_RIGHT | MV_UP | MV_DOWN },
  10927.       { EL_TUBE_VERTICAL,                             MV_UP | MV_DOWN },
  10928.       { EL_TUBE_HORIZONTAL,        MV_LEFT | MV_RIGHT                   },
  10929.       { EL_TUBE_VERTICAL_LEFT,              MV_RIGHT | MV_UP | MV_DOWN },
  10930.       { EL_TUBE_VERTICAL_RIGHT,    MV_LEFT            | MV_UP | MV_DOWN },
  10931.       { EL_TUBE_HORIZONTAL_UP,    MV_LEFT | MV_RIGHT |         MV_DOWN },
  10932.       { EL_TUBE_HORIZONTAL_DOWN,    MV_LEFT | MV_RIGHT | MV_UP           },
  10933.       { EL_TUBE_LEFT_UP,              MV_RIGHT |         MV_DOWN },
  10934.       { EL_TUBE_LEFT_DOWN,              MV_RIGHT | MV_UP           },
  10935.       { EL_TUBE_RIGHT_UP,        MV_LEFT |                    MV_DOWN },
  10936.       { EL_TUBE_RIGHT_DOWN,        MV_LEFT |            MV_UP           },
  10937.       { -1,                MV_NO_MOVING                         }
  10938.     };
  10939.  
  10940.     while (tube_enter_directions[i][0] != element)
  10941.     {
  10942.       i++;
  10943.       if (tube_enter_directions[i][0] == -1)    /* should not happen */
  10944.         break;
  10945.     }
  10946.  
  10947.     if (!(tube_enter_directions[i][1] & move_direction))
  10948.       return MF_NO_ACTION;    /* tube has no opening in this direction */
  10949.  
  10950.     PlayLevelSound(x, y, SND_CLASS_TUBE_WALKING);
  10951.       }
  10952.       break;
  10953. #endif
  10954.  
  10955.     default:
  10956.  
  10957. #if 1
  10958.       if (IS_WALKABLE(element) && ACCESS_FROM(element, opposite_direction))
  10959. #else
  10960.       if (IS_WALKABLE(element))
  10961. #endif
  10962.       {
  10963.     int sound_element = SND_ELEMENT(element);
  10964.     int sound_action = ACTION_WALKING;
  10965.  
  10966. #if 0
  10967.     if (!ACCESS_FROM(element, opposite_direction))
  10968.       return MF_NO_ACTION;    /* field not accessible from this direction */
  10969. #endif
  10970.  
  10971. #if 0
  10972.     if (element == EL_EMPTY_SPACE &&
  10973.         game.gravity && !player->is_auto_moving &&
  10974.         canFallDown(player) && move_direction != MV_DOWN)
  10975.       return MF_NO_ACTION;    /* player cannot walk here due to gravity */
  10976. #endif
  10977.  
  10978.     if (IS_GATE(element))
  10979.     {
  10980.       if (!player->key[element - EL_GATE_1])
  10981.         return MF_NO_ACTION;
  10982.     }
  10983.     else if (IS_GATE_GRAY(element))
  10984.     {
  10985.       if (!player->key[element - EL_GATE_1_GRAY])
  10986.         return MF_NO_ACTION;
  10987.     }
  10988.     else if (element == EL_EXIT_OPEN ||
  10989.          element == EL_SP_EXIT_OPEN ||
  10990.          element == EL_SP_EXIT_OPENING)
  10991.     {
  10992.       sound_action = ACTION_PASSING;    /* player is passing exit */
  10993.     }
  10994.     else if (element == EL_EMPTY)
  10995.     {
  10996.       sound_action = ACTION_MOVING;        /* nothing to walk on */
  10997.     }
  10998.  
  10999.     /* play sound from background or player, whatever is available */
  11000.     if (element_info[sound_element].sound[sound_action] != SND_UNDEFINED)
  11001.       PlayLevelSoundElementAction(x, y, sound_element, sound_action);
  11002.     else
  11003.       PlayLevelSoundElementAction(x, y, player->element_nr, sound_action);
  11004.  
  11005.     break;
  11006.       }
  11007. #if 1
  11008.       else if (IS_PASSABLE(element) && canPassField(x, y, move_direction))
  11009. #else
  11010.       else if (IS_PASSABLE(element))
  11011. #endif
  11012.       {
  11013. #if 0
  11014.     if (!canPassField(x, y, move_direction))
  11015.       return MF_NO_ACTION;
  11016. #else
  11017.  
  11018. #if 0
  11019. #if 1
  11020.     if (!IN_LEV_FIELD(nextx, nexty) || IS_PLAYER(nextx, nexty) ||
  11021.         !IS_WALKABLE_FROM(Feld[nextx][nexty], move_direction) ||
  11022.         (!level.can_pass_to_walkable && !IS_FREE(nextx, nexty)))
  11023.       return MF_NO_ACTION;
  11024. #else
  11025.     if (!IN_LEV_FIELD(nextx, nexty) || !IS_FREE(nextx, nexty))
  11026.       return MF_NO_ACTION;
  11027. #endif
  11028. #endif
  11029.  
  11030. #if 1
  11031.     if (!ACCESS_FROM(element, opposite_direction))
  11032.       return MF_NO_ACTION;    /* field not accessible from this direction */
  11033. #else
  11034.     if (IS_CUSTOM_ELEMENT(element) &&
  11035.         !ACCESS_FROM(element, opposite_direction))
  11036.       return MF_NO_ACTION;    /* field not accessible from this direction */
  11037. #endif
  11038.  
  11039. #if 1
  11040.     if (CAN_MOVE(element))    /* only fixed elements can be passed! */
  11041.       return MF_NO_ACTION;
  11042. #endif
  11043.  
  11044. #endif
  11045.  
  11046.     if (IS_EM_GATE(element))
  11047.     {
  11048.       if (!player->key[element - EL_EM_GATE_1])
  11049.         return MF_NO_ACTION;
  11050.     }
  11051.     else if (IS_EM_GATE_GRAY(element))
  11052.     {
  11053.       if (!player->key[element - EL_EM_GATE_1_GRAY])
  11054.         return MF_NO_ACTION;
  11055.     }
  11056.     else if (IS_SP_PORT(element))
  11057.     {
  11058.       if (element == EL_SP_GRAVITY_PORT_LEFT ||
  11059.           element == EL_SP_GRAVITY_PORT_RIGHT ||
  11060.           element == EL_SP_GRAVITY_PORT_UP ||
  11061.           element == EL_SP_GRAVITY_PORT_DOWN)
  11062.         game.gravity = !game.gravity;
  11063.       else if (element == EL_SP_GRAVITY_ON_PORT_LEFT ||
  11064.            element == EL_SP_GRAVITY_ON_PORT_RIGHT ||
  11065.            element == EL_SP_GRAVITY_ON_PORT_UP ||
  11066.            element == EL_SP_GRAVITY_ON_PORT_DOWN)
  11067.         game.gravity = TRUE;
  11068.       else if (element == EL_SP_GRAVITY_OFF_PORT_LEFT ||
  11069.            element == EL_SP_GRAVITY_OFF_PORT_RIGHT ||
  11070.            element == EL_SP_GRAVITY_OFF_PORT_UP ||
  11071.            element == EL_SP_GRAVITY_OFF_PORT_DOWN)
  11072.         game.gravity = FALSE;
  11073.     }
  11074.  
  11075.     /* automatically move to the next field with double speed */
  11076.     player->programmed_action = move_direction;
  11077. #if 1
  11078.     if (player->move_delay_reset_counter == 0)
  11079.     {
  11080.       player->move_delay_reset_counter = 2;    /* two double speed steps */
  11081.  
  11082.       DOUBLE_PLAYER_SPEED(player);
  11083.     }
  11084. #else
  11085.     player->move_delay_reset_counter = 2;
  11086.  
  11087.     DOUBLE_PLAYER_SPEED(player);
  11088. #endif
  11089.  
  11090.     PlayLevelSoundAction(x, y, ACTION_PASSING);
  11091.  
  11092.     break;
  11093.       }
  11094.       else if (IS_DIGGABLE(element))
  11095.       {
  11096.     RemoveField(x, y);
  11097.  
  11098.     if (mode != DF_SNAP)
  11099.     {
  11100. #if 1
  11101.       GfxElement[x][y] = GFX_ELEMENT(element);
  11102. #else
  11103.       GfxElement[x][y] =
  11104.         (GFX_CRUMBLED(element) ? EL_SAND : GFX_ELEMENT(element));
  11105. #endif
  11106.       player->is_digging = TRUE;
  11107.     }
  11108.  
  11109.     PlayLevelSoundElementAction(x, y, element, ACTION_DIGGING);
  11110.  
  11111.     CheckTriggeredElementChangeByPlayer(x, y, element,CE_OTHER_GETS_DIGGED,
  11112.                         player->index_bit, dig_side);
  11113.  
  11114. #if 1
  11115.     if (mode == DF_SNAP)
  11116.       TestIfElementTouchesCustomElement(x, y);    /* for empty space */
  11117. #endif
  11118.  
  11119.     break;
  11120.       }
  11121.       else if (IS_COLLECTIBLE(element))
  11122.       {
  11123.     RemoveField(x, y);
  11124.  
  11125.     if (is_player && mode != DF_SNAP)
  11126.     {
  11127.       GfxElement[x][y] = element;
  11128.       player->is_collecting = TRUE;
  11129.     }
  11130.  
  11131.     if (element == EL_SPEED_PILL)
  11132.       player->move_delay_value = MOVE_DELAY_HIGH_SPEED;
  11133.     else if (element == EL_EXTRA_TIME && level.time > 0)
  11134.     {
  11135.       TimeLeft += 10;
  11136.       DrawGameValue_Time(TimeLeft);
  11137.     }
  11138.     else if (element == EL_SHIELD_NORMAL || element == EL_SHIELD_DEADLY)
  11139.     {
  11140.       player->shield_normal_time_left += 10;
  11141.       if (element == EL_SHIELD_DEADLY)
  11142.         player->shield_deadly_time_left += 10;
  11143.     }
  11144.     else if (element == EL_DYNAMITE || element == EL_SP_DISK_RED)
  11145.     {
  11146.       if (player->inventory_size < MAX_INVENTORY_SIZE)
  11147.         player->inventory_element[player->inventory_size++] = element;
  11148.  
  11149.       DrawGameValue_Dynamite(local_player->inventory_size);
  11150.     }
  11151.     else if (element == EL_DYNABOMB_INCREASE_NUMBER)
  11152.     {
  11153.       player->dynabomb_count++;
  11154.       player->dynabombs_left++;
  11155.     }
  11156.     else if (element == EL_DYNABOMB_INCREASE_SIZE)
  11157.     {
  11158.       player->dynabomb_size++;
  11159.     }
  11160.     else if (element == EL_DYNABOMB_INCREASE_POWER)
  11161.     {
  11162.       player->dynabomb_xl = TRUE;
  11163.     }
  11164.     else if ((element >= EL_KEY_1 && element <= EL_KEY_4) ||
  11165.          (element >= EL_EM_KEY_1 && element <= EL_EM_KEY_4))
  11166.     {
  11167.       int key_nr = (element >= EL_KEY_1 && element <= EL_KEY_4 ?
  11168.             element - EL_KEY_1 : element - EL_EM_KEY_1);
  11169.  
  11170.       player->key[key_nr] = TRUE;
  11171.  
  11172.       DrawGameValue_Keys(player);
  11173.  
  11174.       redraw_mask |= REDRAW_DOOR_1;
  11175.     }
  11176.     else if (IS_ENVELOPE(element))
  11177.     {
  11178. #if 1
  11179.       player->show_envelope = element;
  11180. #else
  11181.       ShowEnvelope(element - EL_ENVELOPE_1);
  11182. #endif
  11183.     }
  11184.     else if (IS_DROPPABLE(element) ||
  11185.          IS_THROWABLE(element))    /* can be collected and dropped */
  11186.     {
  11187.       int i;
  11188.  
  11189.       if (element_info[element].collect_count == 0)
  11190.         player->inventory_infinite_element = element;
  11191.       else
  11192.         for (i = 0; i < element_info[element].collect_count; i++)
  11193.           if (player->inventory_size < MAX_INVENTORY_SIZE)
  11194.         player->inventory_element[player->inventory_size++] = element;
  11195.  
  11196.       DrawGameValue_Dynamite(local_player->inventory_size);
  11197.     }
  11198.     else if (element_info[element].collect_count > 0)
  11199.     {
  11200.       local_player->gems_still_needed -=
  11201.         element_info[element].collect_count;
  11202.       if (local_player->gems_still_needed < 0)
  11203.         local_player->gems_still_needed = 0;
  11204.  
  11205.       DrawGameValue_Emeralds(local_player->gems_still_needed);
  11206.     }
  11207.  
  11208.     RaiseScoreElement(element);
  11209.     PlayLevelSoundElementAction(x, y, element, ACTION_COLLECTING);
  11210.  
  11211.     if (is_player)
  11212.       CheckTriggeredElementChangeByPlayer(x, y, element,
  11213.                           CE_OTHER_GETS_COLLECTED,
  11214.                           player->index_bit, dig_side);
  11215.  
  11216. #if 1
  11217.     if (mode == DF_SNAP)
  11218.       TestIfElementTouchesCustomElement(x, y);    /* for empty space */
  11219. #endif
  11220.  
  11221.     break;
  11222.       }
  11223.       else if (IS_PUSHABLE(element))
  11224.       {
  11225.     if (mode == DF_SNAP && element != EL_BD_ROCK)
  11226.       return MF_NO_ACTION;
  11227.  
  11228.     if (CAN_FALL(element) && dy)
  11229.       return MF_NO_ACTION;
  11230.  
  11231.     if (CAN_FALL(element) && IN_LEV_FIELD(x, y + 1) && IS_FREE(x, y + 1) &&
  11232.         !(element == EL_SPRING && level.use_spring_bug))
  11233.       return MF_NO_ACTION;
  11234.  
  11235. #if 1
  11236.     if (CAN_MOVE(element) && GET_MAX_MOVE_DELAY(element) == 0 &&
  11237.         ((move_direction & MV_VERTICAL &&
  11238.           ((element_info[element].move_pattern & MV_LEFT &&
  11239.         IN_LEV_FIELD(x - 1, y) && IS_FREE(x - 1, y)) ||
  11240.            (element_info[element].move_pattern & MV_RIGHT &&
  11241.         IN_LEV_FIELD(x + 1, y) && IS_FREE(x + 1, y)))) ||
  11242.          (move_direction & MV_HORIZONTAL &&
  11243.           ((element_info[element].move_pattern & MV_UP &&
  11244.         IN_LEV_FIELD(x, y - 1) && IS_FREE(x, y - 1)) ||
  11245.            (element_info[element].move_pattern & MV_DOWN &&
  11246.         IN_LEV_FIELD(x, y + 1) && IS_FREE(x, y + 1))))))
  11247.       return MF_NO_ACTION;
  11248. #endif
  11249.  
  11250. #if 1
  11251.     /* do not push elements already moving away faster than player */
  11252.     if (CAN_MOVE(element) && MovDir[x][y] == move_direction &&
  11253.         ABS(getElementMoveStepsize(x, y)) > MOVE_STEPSIZE_NORMAL)
  11254.       return MF_NO_ACTION;
  11255. #else
  11256.     if (element == EL_SPRING && MovDir[x][y] != MV_NO_MOVING)
  11257.       return MF_NO_ACTION;
  11258. #endif
  11259.  
  11260. #if 1
  11261.  
  11262. #if 1
  11263.     if (game.engine_version >= VERSION_IDENT(3,1,0,0))
  11264.     {
  11265.       if (player->push_delay_value == -1 || !player_was_pushing)
  11266.         player->push_delay_value = GET_NEW_PUSH_DELAY(element);
  11267.     }
  11268.     else if (game.engine_version >= VERSION_IDENT(3,0,7,1))
  11269.     {
  11270.       if (player->push_delay_value == -1)
  11271.         player->push_delay_value = GET_NEW_PUSH_DELAY(element);
  11272.     }
  11273. #else
  11274.     if (game.engine_version >= VERSION_IDENT(3,0,7,1))
  11275.     {
  11276.       if (player->push_delay_value == -1 || !player_was_pushing)
  11277.         player->push_delay_value = GET_NEW_PUSH_DELAY(element);
  11278.     }
  11279. #endif
  11280.     else if (game.engine_version >= VERSION_IDENT(2,2,0,7))
  11281.     {
  11282.       if (!player->is_pushing)
  11283.         player->push_delay_value = GET_NEW_PUSH_DELAY(element);
  11284.     }
  11285.  
  11286.     /*
  11287.     if (game.engine_version >= VERSION_IDENT(2,2,0,7) &&
  11288.         (game.engine_version < VERSION_IDENT(3,0,7,1) ||
  11289.          !player_is_pushing))
  11290.       player->push_delay_value = GET_NEW_PUSH_DELAY(element);
  11291.     */
  11292. #else
  11293.     if (!player->is_pushing &&
  11294.         game.engine_version >= VERSION_IDENT(2,2,0,7))
  11295.       player->push_delay_value = GET_NEW_PUSH_DELAY(element);
  11296. #endif
  11297.  
  11298. #if 0
  11299.     printf("::: push delay: %ld -> %ld [%d, %d] [%d / %d] [%d '%s': %d]\n",
  11300.            player->push_delay, player->push_delay_value,
  11301.            FrameCounter, game.engine_version,
  11302.            player_was_pushing, player->is_pushing,
  11303.            element, element_info[element].token_name,
  11304.            GET_NEW_PUSH_DELAY(element));
  11305. #endif
  11306.  
  11307.     player->is_pushing = TRUE;
  11308.  
  11309.     if (!(IN_LEV_FIELD(nextx, nexty) &&
  11310.           (IS_FREE(nextx, nexty) ||
  11311.            (Feld[nextx][nexty] == EL_SOKOBAN_FIELD_EMPTY &&
  11312.         IS_SB_ELEMENT(element)))))
  11313.       return MF_NO_ACTION;
  11314.  
  11315.     if (!checkDiagonalPushing(player, x, y, real_dx, real_dy))
  11316.       return MF_NO_ACTION;
  11317.  
  11318.     if (player->push_delay == 0)    /* new pushing; restart delay */
  11319.       player->push_delay = FrameCounter;
  11320.  
  11321.     if (!FrameReached(&player->push_delay, player->push_delay_value) &&
  11322.         !(tape.playing && tape.file_version < FILE_VERSION_2_0) &&
  11323.         element != EL_SPRING && element != EL_BALLOON)
  11324.     {
  11325.       /* make sure that there is no move delay before next try to push */
  11326.       if (game.engine_version >= VERSION_IDENT(3,0,7,1))
  11327.         player->move_delay = INITIAL_MOVE_DELAY_OFF;
  11328.  
  11329.       return MF_NO_ACTION;
  11330.     }
  11331.  
  11332. #if 0
  11333.     printf("::: NOW PUSHING... [%d]\n", FrameCounter);
  11334. #endif
  11335.  
  11336.     if (IS_SB_ELEMENT(element))
  11337.     {
  11338.       if (element == EL_SOKOBAN_FIELD_FULL)
  11339.       {
  11340.         Back[x][y] = EL_SOKOBAN_FIELD_EMPTY;
  11341.         local_player->sokobanfields_still_needed++;
  11342.       }
  11343.  
  11344.       if (Feld[nextx][nexty] == EL_SOKOBAN_FIELD_EMPTY)
  11345.       {
  11346.         Back[nextx][nexty] = EL_SOKOBAN_FIELD_EMPTY;
  11347.         local_player->sokobanfields_still_needed--;
  11348.       }
  11349.  
  11350.       Feld[x][y] = EL_SOKOBAN_OBJECT;
  11351.  
  11352.       if (Back[x][y] == Back[nextx][nexty])
  11353.         PlayLevelSoundAction(x, y, ACTION_PUSHING);
  11354.       else if (Back[x][y] != 0)
  11355.         PlayLevelSoundElementAction(x, y, EL_SOKOBAN_FIELD_FULL,
  11356.                     ACTION_EMPTYING);
  11357.       else
  11358.         PlayLevelSoundElementAction(nextx, nexty, EL_SOKOBAN_FIELD_EMPTY,
  11359.                     ACTION_FILLING);
  11360.  
  11361.       if (local_player->sokobanfields_still_needed == 0 &&
  11362.           game.emulation == EMU_SOKOBAN)
  11363.       {
  11364.         player->LevelSolved = player->GameOver = TRUE;
  11365.         PlayLevelSound(x, y, SND_GAME_SOKOBAN_SOLVING);
  11366.       }
  11367.     }
  11368.     else
  11369.       PlayLevelSoundElementAction(x, y, element, ACTION_PUSHING);
  11370.  
  11371.     InitMovingField(x, y, move_direction);
  11372.     GfxAction[x][y] = ACTION_PUSHING;
  11373.  
  11374.     if (mode == DF_SNAP)
  11375.       ContinueMoving(x, y);
  11376.     else
  11377.       MovPos[x][y] = (dx != 0 ? dx : dy);
  11378.  
  11379.     Pushed[x][y] = TRUE;
  11380.     Pushed[nextx][nexty] = TRUE;
  11381.  
  11382.     if (game.engine_version < VERSION_IDENT(2,2,0,7))
  11383.       player->push_delay_value = GET_NEW_PUSH_DELAY(element);
  11384.     else
  11385.       player->push_delay_value = -1;    /* get new value later */
  11386.  
  11387. #if 1
  11388.     /* check for element change _after_ element has been pushed! */
  11389. #else
  11390.  
  11391. #if 1
  11392.       /* !!! TEST ONLY !!! */
  11393.     CheckElementChangeByPlayer(x, y, element, CE_PUSHED_BY_PLAYER,
  11394.                    player->index_bit, dig_side);
  11395.     CheckTriggeredElementChangeByPlayer(x, y, element,CE_OTHER_GETS_PUSHED,
  11396.                         player->index_bit, dig_side);
  11397. #else
  11398.     CheckTriggeredElementChangeByPlayer(x, y, element,CE_OTHER_GETS_PUSHED,
  11399.                         player->index_bit, dig_side);
  11400.     CheckElementChangeByPlayer(x, y, element, CE_PUSHED_BY_PLAYER,
  11401.                    player->index_bit, dig_side);
  11402. #endif
  11403. #endif
  11404.  
  11405.     break;
  11406.       }
  11407.       else if (IS_SWITCHABLE(element))
  11408.       {
  11409.     if (PLAYER_SWITCHING(player, x, y))
  11410.     {
  11411.       CheckTriggeredElementChangeByPlayer(x,y, element,
  11412.                           CE_OTHER_GETS_PRESSED,
  11413.                           player->index_bit, dig_side);
  11414.  
  11415.       return MF_ACTION;
  11416.     }
  11417.  
  11418.     player->is_switching = TRUE;
  11419.     player->switch_x = x;
  11420.     player->switch_y = y;
  11421.  
  11422.     PlayLevelSoundElementAction(x, y, element, ACTION_ACTIVATING);
  11423.  
  11424.     if (element == EL_ROBOT_WHEEL)
  11425.     {
  11426.       Feld[x][y] = EL_ROBOT_WHEEL_ACTIVE;
  11427.       ZX = x;
  11428.       ZY = y;
  11429.  
  11430.       DrawLevelField(x, y);
  11431.     }
  11432.     else if (element == EL_SP_TERMINAL)
  11433.     {
  11434.       int xx, yy;
  11435.  
  11436.       for (yy = 0; yy < lev_fieldy; yy++) for (xx=0; xx < lev_fieldx; xx++)
  11437.       {
  11438.         if (Feld[xx][yy] == EL_SP_DISK_YELLOW)
  11439.           Bang(xx, yy);
  11440.         else if (Feld[xx][yy] == EL_SP_TERMINAL)
  11441.           Feld[xx][yy] = EL_SP_TERMINAL_ACTIVE;
  11442.       }
  11443.     }
  11444.     else if (IS_BELT_SWITCH(element))
  11445.     {
  11446.       ToggleBeltSwitch(x, y);
  11447.     }
  11448.     else if (element == EL_SWITCHGATE_SWITCH_UP ||
  11449.          element == EL_SWITCHGATE_SWITCH_DOWN)
  11450.     {
  11451.       ToggleSwitchgateSwitch(x, y);
  11452.     }
  11453.     else if (element == EL_LIGHT_SWITCH ||
  11454.          element == EL_LIGHT_SWITCH_ACTIVE)
  11455.     {
  11456.       ToggleLightSwitch(x, y);
  11457.  
  11458. #if 0
  11459.       PlayLevelSound(x, y, element == EL_LIGHT_SWITCH ?
  11460.              SND_LIGHT_SWITCH_ACTIVATING :
  11461.              SND_LIGHT_SWITCH_DEACTIVATING);
  11462. #endif
  11463.     }
  11464.     else if (element == EL_TIMEGATE_SWITCH)
  11465.     {
  11466.       ActivateTimegateSwitch(x, y);
  11467.     }
  11468.     else if (element == EL_BALLOON_SWITCH_LEFT ||
  11469.          element == EL_BALLOON_SWITCH_RIGHT ||
  11470.          element == EL_BALLOON_SWITCH_UP ||
  11471.          element == EL_BALLOON_SWITCH_DOWN ||
  11472.          element == EL_BALLOON_SWITCH_ANY)
  11473.     {
  11474.       if (element == EL_BALLOON_SWITCH_ANY)
  11475.         game.balloon_dir = move_direction;
  11476.       else
  11477.         game.balloon_dir = (element == EL_BALLOON_SWITCH_LEFT  ? MV_LEFT :
  11478.                 element == EL_BALLOON_SWITCH_RIGHT ? MV_RIGHT :
  11479.                 element == EL_BALLOON_SWITCH_UP    ? MV_UP :
  11480.                 element == EL_BALLOON_SWITCH_DOWN  ? MV_DOWN :
  11481.                 MV_NO_MOVING);
  11482.     }
  11483.     else if (element == EL_LAMP)
  11484.     {
  11485.       Feld[x][y] = EL_LAMP_ACTIVE;
  11486.       local_player->lights_still_needed--;
  11487.  
  11488.       DrawLevelField(x, y);
  11489.     }
  11490.     else if (element == EL_TIME_ORB_FULL)
  11491.     {
  11492.       Feld[x][y] = EL_TIME_ORB_EMPTY;
  11493.       TimeLeft += 10;
  11494.       DrawGameValue_Time(TimeLeft);
  11495.  
  11496.       DrawLevelField(x, y);
  11497.  
  11498. #if 0
  11499.       PlaySoundStereo(SND_TIME_ORB_FULL_COLLECTING, SOUND_MIDDLE);
  11500. #endif
  11501.     }
  11502.  
  11503.     CheckTriggeredElementChangeByPlayer(x, y, element,
  11504.                         CE_OTHER_IS_SWITCHING,
  11505.                         player->index_bit, dig_side);
  11506.  
  11507.     CheckTriggeredElementChangeByPlayer(x,y, element,CE_OTHER_GETS_PRESSED,
  11508.                         player->index_bit, dig_side);
  11509.  
  11510.     return MF_ACTION;
  11511.       }
  11512.       else
  11513.       {
  11514.     if (!PLAYER_SWITCHING(player, x, y))
  11515.     {
  11516.       player->is_switching = TRUE;
  11517.       player->switch_x = x;
  11518.       player->switch_y = y;
  11519.  
  11520. #if 1
  11521.       /* !!! TEST ONLY !!! */
  11522.       CheckElementChangeByPlayer(x, y, element, CE_SWITCHED,
  11523.                      player->index_bit, dig_side);
  11524.       CheckTriggeredElementChangeByPlayer(x, y, element,
  11525.                           CE_OTHER_IS_SWITCHING,
  11526.                           player->index_bit, dig_side);
  11527. #else
  11528.       CheckTriggeredElementChangeByPlayer(x, y, element,
  11529.                           CE_OTHER_IS_SWITCHING,
  11530.                           player->index_bit, dig_side);
  11531.       CheckElementChangeByPlayer(x, y, element, CE_SWITCHED,
  11532.                      player->index_bit, dig_side);
  11533. #endif
  11534.     }
  11535.  
  11536. #if 1
  11537.     /* !!! TEST ONLY !!! (this breaks "machine", level 000) */
  11538.     CheckElementChangeByPlayer(x, y, element, CE_PRESSED_BY_PLAYER,
  11539.                    player->index_bit, dig_side);
  11540.     CheckTriggeredElementChangeByPlayer(x,y, element,CE_OTHER_GETS_PRESSED,
  11541.                         player->index_bit, dig_side);
  11542. #else
  11543.     CheckTriggeredElementChangeByPlayer(x,y, element,CE_OTHER_GETS_PRESSED,
  11544.                         player->index_bit, dig_side);
  11545.     CheckElementChangeByPlayer(x, y, element, CE_PRESSED_BY_PLAYER,
  11546.                    player->index_bit, dig_side);
  11547. #endif
  11548.       }
  11549.  
  11550.       return MF_NO_ACTION;
  11551.   }
  11552.  
  11553.   player->push_delay = 0;
  11554.  
  11555.   if (Feld[x][y] != element)        /* really digged/collected something */
  11556.     player->is_collecting = !player->is_digging;
  11557.  
  11558.   return MF_MOVING;
  11559. }
  11560.  
  11561. boolean SnapField(struct PlayerInfo *player, int dx, int dy)
  11562. {
  11563.   int jx = player->jx, jy = player->jy;
  11564.   int x = jx + dx, y = jy + dy;
  11565.   int snap_direction = (dx == -1 ? MV_LEFT :
  11566.             dx == +1 ? MV_RIGHT :
  11567.             dy == -1 ? MV_UP :
  11568.             dy == +1 ? MV_DOWN : MV_NO_MOVING);
  11569.  
  11570. #if 0
  11571.   if (player->MovPos != 0)
  11572.     return FALSE;
  11573. #else
  11574.   if (player->MovPos != 0 && game.engine_version >= VERSION_IDENT(2,2,0,0))
  11575.     return FALSE;
  11576. #endif
  11577.  
  11578.   if (!player->active || !IN_LEV_FIELD(x, y))
  11579.     return FALSE;
  11580.  
  11581.   if (dx && dy)
  11582.     return FALSE;
  11583.  
  11584.   if (!dx && !dy)
  11585.   {
  11586.     if (player->MovPos == 0)
  11587.       player->is_pushing = FALSE;
  11588.  
  11589.     player->is_snapping = FALSE;
  11590.  
  11591.     if (player->MovPos == 0)
  11592.     {
  11593.       player->is_moving = FALSE;
  11594.       player->is_digging = FALSE;
  11595.       player->is_collecting = FALSE;
  11596.     }
  11597.  
  11598.     return FALSE;
  11599.   }
  11600.  
  11601.   if (player->is_snapping)
  11602.     return FALSE;
  11603.  
  11604.   player->MovDir = snap_direction;
  11605.  
  11606. #if 1
  11607.   if (player->MovPos == 0)
  11608. #endif
  11609.   {
  11610.     player->is_moving = FALSE;
  11611.     player->is_digging = FALSE;
  11612.     player->is_collecting = FALSE;
  11613.   }
  11614.  
  11615.   player->is_dropping = FALSE;
  11616.  
  11617.   if (DigField(player, jx, jy, x, y, 0, 0, DF_SNAP) == MF_NO_ACTION)
  11618.     return FALSE;
  11619.  
  11620.   player->is_snapping = TRUE;
  11621.  
  11622. #if 1
  11623.   if (player->MovPos == 0)
  11624. #endif
  11625.   {
  11626.     player->is_moving = FALSE;
  11627.     player->is_digging = FALSE;
  11628.     player->is_collecting = FALSE;
  11629.   }
  11630.  
  11631. #if 1
  11632.   if (player->MovPos != 0)    /* prevent graphic bugs in versions < 2.2.0 */
  11633.     DrawLevelField(player->last_jx, player->last_jy);
  11634. #endif
  11635.  
  11636.   DrawLevelField(x, y);
  11637.  
  11638. #if 0
  11639.   BackToFront();
  11640. #endif
  11641.  
  11642.   return TRUE;
  11643. }
  11644.  
  11645. boolean DropElement(struct PlayerInfo *player)
  11646. {
  11647.   int old_element, new_element;
  11648.   int dropx = player->jx, dropy = player->jy;
  11649.   int drop_direction = player->MovDir;
  11650. #if 1
  11651.   int drop_side = drop_direction;
  11652. #else
  11653.   static int trigger_sides[4] =
  11654.   {
  11655.     CH_SIDE_LEFT,    /* dropping left  */
  11656.     CH_SIDE_RIGHT,    /* dropping right */
  11657.     CH_SIDE_TOP,    /* dropping up    */
  11658.     CH_SIDE_BOTTOM,    /* dropping down  */
  11659.   };
  11660.   int drop_side = trigger_sides[MV_DIR_BIT(drop_direction)];
  11661. #endif
  11662.   int drop_element = (player->inventory_size > 0 ?
  11663.               player->inventory_element[player->inventory_size - 1] :
  11664.               player->inventory_infinite_element != EL_UNDEFINED ?
  11665.               player->inventory_infinite_element :
  11666.               player->dynabombs_left > 0 ?
  11667.               EL_DYNABOMB_PLAYER_1_ACTIVE + player->index_nr :
  11668.               EL_UNDEFINED);
  11669.  
  11670.   if (IS_THROWABLE(drop_element))
  11671.   {
  11672.     dropx += GET_DX_FROM_DIR(drop_direction);
  11673.     dropy += GET_DY_FROM_DIR(drop_direction);
  11674.  
  11675.     if (!IN_LEV_FIELD(dropx, dropy))
  11676.       return FALSE;
  11677.   }
  11678.  
  11679.   old_element = Feld[dropx][dropy];    /* old element at dropping position */
  11680.   new_element = drop_element;        /* default: no change when dropping */
  11681.  
  11682.   /* check if player is active, not moving and ready to drop */
  11683.   if (!player->active || player->MovPos || player->drop_delay > 0)
  11684.     return FALSE;
  11685.  
  11686.   /* check if player has anything that can be dropped */
  11687. #if 1
  11688.   if (new_element == EL_UNDEFINED)
  11689.     return FALSE;
  11690. #else
  11691.   if (player->inventory_size == 0 &&
  11692.       player->inventory_infinite_element == EL_UNDEFINED &&
  11693.       player->dynabombs_left == 0)
  11694.     return FALSE;
  11695. #endif
  11696.  
  11697.   /* check if anything can be dropped at the current position */
  11698.   if (IS_ACTIVE_BOMB(old_element) || old_element == EL_EXPLOSION)
  11699.     return FALSE;
  11700.  
  11701.   /* collected custom elements can only be dropped on empty fields */
  11702. #if 1
  11703.   if (IS_CUSTOM_ELEMENT(new_element) && old_element != EL_EMPTY)
  11704.     return FALSE;
  11705. #else
  11706.   if (player->inventory_size > 0 &&
  11707.       IS_CUSTOM_ELEMENT(player->inventory_element[player->inventory_size - 1])
  11708.       && old_element != EL_EMPTY)
  11709.     return FALSE;
  11710. #endif
  11711.  
  11712.   if (old_element != EL_EMPTY)
  11713.     Back[dropx][dropy] = old_element;    /* store old element on this field */
  11714.  
  11715.   ResetGfxAnimation(dropx, dropy);
  11716.   ResetRandomAnimationValue(dropx, dropy);
  11717.  
  11718.   if (player->inventory_size > 0 ||
  11719.       player->inventory_infinite_element != EL_UNDEFINED)
  11720.   {
  11721.     if (player->inventory_size > 0)
  11722.     {
  11723.       player->inventory_size--;
  11724.  
  11725. #if 0
  11726.       new_element = player->inventory_element[player->inventory_size];
  11727. #endif
  11728.  
  11729.       DrawGameValue_Dynamite(local_player->inventory_size);
  11730.  
  11731.       if (new_element == EL_DYNAMITE)
  11732.     new_element = EL_DYNAMITE_ACTIVE;
  11733.       else if (new_element == EL_SP_DISK_RED)
  11734.     new_element = EL_SP_DISK_RED_ACTIVE;
  11735.     }
  11736.  
  11737.     Feld[dropx][dropy] = new_element;
  11738.  
  11739.     if (IN_SCR_FIELD(SCREENX(dropx), SCREENY(dropy)))
  11740.       DrawGraphicThruMask(SCREENX(dropx), SCREENY(dropy),
  11741.               el2img(Feld[dropx][dropy]), 0);
  11742.  
  11743.     PlayLevelSoundAction(dropx, dropy, ACTION_DROPPING);
  11744.  
  11745. #if 1
  11746.     /* needed if previous element just changed to "empty" in the last frame */
  11747.     Changed[dropx][dropy] = 0;        /* allow another change */
  11748. #endif
  11749.  
  11750. #if 1
  11751.     /* !!! TEST ONLY !!! */
  11752.     CheckElementChangeByPlayer(dropx, dropy, new_element, CE_DROPPED_BY_PLAYER,
  11753.                    player->index_bit, drop_side);
  11754.     CheckTriggeredElementChangeByPlayer(dropx, dropy, new_element,
  11755.                     CE_OTHER_GETS_DROPPED,
  11756.                     player->index_bit, drop_side);
  11757. #else
  11758.     CheckTriggeredElementChangeByPlayer(dropx, dropy, new_element,
  11759.                     CE_OTHER_GETS_DROPPED,
  11760.                     player->index_bit, drop_side);
  11761.     CheckElementChangeByPlayer(dropx, dropy, new_element, CE_DROPPED_BY_PLAYER,
  11762.                    player->index_bit, drop_side);
  11763. #endif
  11764.  
  11765.     TestIfElementTouchesCustomElement(dropx, dropy);
  11766.   }
  11767.   else        /* player is dropping a dyna bomb */
  11768.   {
  11769.     player->dynabombs_left--;
  11770.  
  11771. #if 0
  11772.     new_element = EL_DYNABOMB_PLAYER_1_ACTIVE + player->index_nr;
  11773. #endif
  11774.  
  11775.     Feld[dropx][dropy] = new_element;
  11776.  
  11777.     if (IN_SCR_FIELD(SCREENX(dropx), SCREENY(dropy)))
  11778.       DrawGraphicThruMask(SCREENX(dropx), SCREENY(dropy),
  11779.               el2img(Feld[dropx][dropy]), 0);
  11780.  
  11781.     PlayLevelSoundAction(dropx, dropy, ACTION_DROPPING);
  11782.   }
  11783.  
  11784.  
  11785.  
  11786. #if 1
  11787.  
  11788.   if (Feld[dropx][dropy] == new_element) /* uninitialized unless CE change */
  11789.   {
  11790. #if 1
  11791.     InitField_WithBug1(dropx, dropy, FALSE);
  11792. #else
  11793.     InitField(dropx, dropy, FALSE);
  11794.     if (CAN_MOVE(Feld[dropx][dropy]))
  11795.       InitMovDir(dropx, dropy);
  11796. #endif
  11797.   }
  11798.  
  11799.   new_element = Feld[dropx][dropy];    /* element might have changed */
  11800.  
  11801.   if (IS_CUSTOM_ELEMENT(new_element) && CAN_MOVE(new_element) &&
  11802.       element_info[new_element].move_pattern == MV_WHEN_DROPPED)
  11803.   {
  11804. #if 0
  11805.     int move_stepsize = element_info[new_element].move_stepsize;
  11806. #endif
  11807.     int move_direction, nextx, nexty;
  11808.  
  11809.     if (element_info[new_element].move_direction_initial == MV_START_AUTOMATIC)
  11810.       MovDir[dropx][dropy] = drop_direction;
  11811.  
  11812.     move_direction = MovDir[dropx][dropy];
  11813.     nextx = dropx + GET_DX_FROM_DIR(move_direction);
  11814.     nexty = dropy + GET_DY_FROM_DIR(move_direction);
  11815.  
  11816. #if 1
  11817.     Changed[dropx][dropy] = 0;        /* allow another change */
  11818.     CheckCollision[dropx][dropy] = 2;
  11819. #else
  11820.  
  11821.     if (IN_LEV_FIELD_AND_IS_FREE(nextx, nexty))
  11822.     {
  11823. #if 0
  11824.       WasJustMoving[dropx][dropy] = 3;
  11825. #else
  11826. #if 1
  11827.       InitMovingField(dropx, dropy, move_direction);
  11828.       ContinueMoving(dropx, dropy);
  11829. #endif
  11830. #endif
  11831.     }
  11832. #if 0
  11833.     /* !!! commented out from 3.1.0-4 to 3.1.0-5 !!! */
  11834.     else
  11835.     {
  11836.       Changed[dropx][dropy] = 0;    /* allow another change */
  11837.  
  11838. #if 1
  11839.       TestIfElementHitsCustomElement(dropx, dropy, move_direction);
  11840. #else
  11841.       CheckElementChangeBySide(dropx, dropy, new_element, touched_element,
  11842.                    CE_HITTING_SOMETHING, move_direction);
  11843. #endif
  11844.     }
  11845. #endif
  11846.  
  11847. #endif
  11848.  
  11849. #if 0
  11850.     player->drop_delay = 2 * TILEX / move_stepsize + 1;
  11851. #endif
  11852.   }
  11853.  
  11854. #if 0
  11855.   player->drop_delay = 8 + 8 + 8;
  11856. #endif
  11857.  
  11858. #if 1
  11859.   player->drop_delay = GET_NEW_DROP_DELAY(drop_element);
  11860. #endif
  11861.  
  11862. #endif
  11863.  
  11864.   player->is_dropping = TRUE;
  11865.  
  11866.  
  11867.   return TRUE;
  11868. }
  11869.  
  11870. /* ------------------------------------------------------------------------- */
  11871. /* game sound playing functions                                              */
  11872. /* ------------------------------------------------------------------------- */
  11873.  
  11874. static int *loop_sound_frame = NULL;
  11875. static int *loop_sound_volume = NULL;
  11876.  
  11877. void InitPlayLevelSound()
  11878. {
  11879.   int num_sounds = getSoundListSize();
  11880.  
  11881.   checked_free(loop_sound_frame);
  11882.   checked_free(loop_sound_volume);
  11883.  
  11884.   loop_sound_frame  = checked_calloc(num_sounds * sizeof(int));
  11885.   loop_sound_volume = checked_calloc(num_sounds * sizeof(int));
  11886. }
  11887.  
  11888. static void PlayLevelSound(int x, int y, int nr)
  11889. {
  11890.   int sx = SCREENX(x), sy = SCREENY(y);
  11891.   int volume, stereo_position;
  11892.   int max_distance = 8;
  11893.   int type = (IS_LOOP_SOUND(nr) ? SND_CTRL_PLAY_LOOP : SND_CTRL_PLAY_SOUND);
  11894.  
  11895.   if ((!setup.sound_simple && !IS_LOOP_SOUND(nr)) ||
  11896.       (!setup.sound_loops && IS_LOOP_SOUND(nr)))
  11897.     return;
  11898.  
  11899.   if (!IN_LEV_FIELD(x, y) ||
  11900.       sx < -max_distance || sx >= SCR_FIELDX + max_distance ||
  11901.       sy < -max_distance || sy >= SCR_FIELDY + max_distance)
  11902.     return;
  11903.  
  11904.   volume = SOUND_MAX_VOLUME;
  11905.  
  11906.   if (!IN_SCR_FIELD(sx, sy))
  11907.   {
  11908.     int dx = ABS(sx - SCR_FIELDX / 2) - SCR_FIELDX / 2;
  11909.     int dy = ABS(sy - SCR_FIELDY / 2) - SCR_FIELDY / 2;
  11910.  
  11911.     volume -= volume * (dx > dy ? dx : dy) / max_distance;
  11912.   }
  11913.  
  11914.   stereo_position = (SOUND_MAX_LEFT +
  11915.              (sx + max_distance) * SOUND_MAX_LEFT2RIGHT /
  11916.              (SCR_FIELDX + 2 * max_distance));
  11917.  
  11918.   if (IS_LOOP_SOUND(nr))
  11919.   {
  11920.     /* This assures that quieter loop sounds do not overwrite louder ones,
  11921.        while restarting sound volume comparison with each new game frame. */
  11922.  
  11923.     if (loop_sound_volume[nr] > volume && loop_sound_frame[nr] == FrameCounter)
  11924.       return;
  11925.  
  11926.     loop_sound_volume[nr] = volume;
  11927.     loop_sound_frame[nr] = FrameCounter;
  11928.   }
  11929.  
  11930.   PlaySoundExt(nr, volume, stereo_position, type);
  11931. }
  11932.  
  11933. static void PlayLevelSoundNearest(int x, int y, int sound_action)
  11934. {
  11935.   PlayLevelSound(x < LEVELX(BX1) ? LEVELX(BX1) :
  11936.          x > LEVELX(BX2) ? LEVELX(BX2) : x,
  11937.          y < LEVELY(BY1) ? LEVELY(BY1) :
  11938.          y > LEVELY(BY2) ? LEVELY(BY2) : y,
  11939.          sound_action);
  11940. }
  11941.  
  11942. static void PlayLevelSoundAction(int x, int y, int action)
  11943. {
  11944.   PlayLevelSoundElementAction(x, y, Feld[x][y], action);
  11945. }
  11946.  
  11947. static void PlayLevelSoundElementAction(int x, int y, int element, int action)
  11948. {
  11949.   int sound_effect = element_info[SND_ELEMENT(element)].sound[action];
  11950.  
  11951.   if (sound_effect != SND_UNDEFINED)
  11952.     PlayLevelSound(x, y, sound_effect);
  11953. }
  11954.  
  11955. static void PlayLevelSoundElementActionIfLoop(int x, int y, int element,
  11956.                           int action)
  11957. {
  11958.   int sound_effect = element_info[SND_ELEMENT(element)].sound[action];
  11959.  
  11960.   if (sound_effect != SND_UNDEFINED && IS_LOOP_SOUND(sound_effect))
  11961.     PlayLevelSound(x, y, sound_effect);
  11962. }
  11963.  
  11964. static void PlayLevelSoundActionIfLoop(int x, int y, int action)
  11965. {
  11966.   int sound_effect = element_info[SND_ELEMENT(Feld[x][y])].sound[action];
  11967.  
  11968.   if (sound_effect != SND_UNDEFINED && IS_LOOP_SOUND(sound_effect))
  11969.     PlayLevelSound(x, y, sound_effect);
  11970. }
  11971.  
  11972. static void StopLevelSoundActionIfLoop(int x, int y, int action)
  11973. {
  11974.   int sound_effect = element_info[SND_ELEMENT(Feld[x][y])].sound[action];
  11975.  
  11976.   if (sound_effect != SND_UNDEFINED && IS_LOOP_SOUND(sound_effect))
  11977.     StopSound(sound_effect);
  11978. }
  11979.  
  11980. static void PlayLevelMusic()
  11981. {
  11982.   if (levelset.music[level_nr] != MUS_UNDEFINED)
  11983.     PlayMusic(levelset.music[level_nr]);    /* from config file */
  11984.   else
  11985.     PlayMusic(MAP_NOCONF_MUSIC(level_nr));    /* from music dir */
  11986. }
  11987.  
  11988. void RaiseScore(int value)
  11989. {
  11990.   local_player->score += value;
  11991.  
  11992.   DrawGameValue_Score(local_player->score);
  11993. }
  11994.  
  11995. void RaiseScoreElement(int element)
  11996. {
  11997.   switch(element)
  11998.   {
  11999.     case EL_EMERALD:
  12000.     case EL_BD_DIAMOND:
  12001.     case EL_EMERALD_YELLOW:
  12002.     case EL_EMERALD_RED:
  12003.     case EL_EMERALD_PURPLE:
  12004.     case EL_SP_INFOTRON:
  12005.       RaiseScore(level.score[SC_EMERALD]);
  12006.       break;
  12007.     case EL_DIAMOND:
  12008.       RaiseScore(level.score[SC_DIAMOND]);
  12009.       break;
  12010.     case EL_CRYSTAL:
  12011.       RaiseScore(level.score[SC_CRYSTAL]);
  12012.       break;
  12013.     case EL_PEARL:
  12014.       RaiseScore(level.score[SC_PEARL]);
  12015.       break;
  12016.     case EL_BUG:
  12017.     case EL_BD_BUTTERFLY:
  12018.     case EL_SP_ELECTRON:
  12019.       RaiseScore(level.score[SC_BUG]);
  12020.       break;
  12021.     case EL_SPACESHIP:
  12022.     case EL_BD_FIREFLY:
  12023.     case EL_SP_SNIKSNAK:
  12024.       RaiseScore(level.score[SC_SPACESHIP]);
  12025.       break;
  12026.     case EL_YAMYAM:
  12027.     case EL_DARK_YAMYAM:
  12028.       RaiseScore(level.score[SC_YAMYAM]);
  12029.       break;
  12030.     case EL_ROBOT:
  12031.       RaiseScore(level.score[SC_ROBOT]);
  12032.       break;
  12033.     case EL_PACMAN:
  12034.       RaiseScore(level.score[SC_PACMAN]);
  12035.       break;
  12036.     case EL_NUT:
  12037.       RaiseScore(level.score[SC_NUT]);
  12038.       break;
  12039.     case EL_DYNAMITE:
  12040.     case EL_SP_DISK_RED:
  12041.     case EL_DYNABOMB_INCREASE_NUMBER:
  12042.     case EL_DYNABOMB_INCREASE_SIZE:
  12043.     case EL_DYNABOMB_INCREASE_POWER:
  12044.       RaiseScore(level.score[SC_DYNAMITE]);
  12045.       break;
  12046.     case EL_SHIELD_NORMAL:
  12047.     case EL_SHIELD_DEADLY:
  12048.       RaiseScore(level.score[SC_SHIELD]);
  12049.       break;
  12050.     case EL_EXTRA_TIME:
  12051.       RaiseScore(level.score[SC_TIME_BONUS]);
  12052.       break;
  12053.     case EL_KEY_1:
  12054.     case EL_KEY_2:
  12055.     case EL_KEY_3:
  12056.     case EL_KEY_4:
  12057.       RaiseScore(level.score[SC_KEY]);
  12058.       break;
  12059.     default:
  12060.       RaiseScore(element_info[element].collect_score);
  12061.       break;
  12062.   }
  12063. }
  12064.  
  12065. void RequestQuitGame(boolean ask_if_really_quit)
  12066. {
  12067.   if (AllPlayersGone ||
  12068.       !ask_if_really_quit ||
  12069.       level_editor_test_game ||
  12070.       Request("Do you really want to quit the game ?",
  12071.           REQ_ASK | REQ_STAY_CLOSED))
  12072.   {
  12073. #if defined(NETWORK_AVALIABLE)
  12074.     if (options.network)
  12075.       SendToServer_StopPlaying();
  12076.     else
  12077. #endif
  12078.     {
  12079.       game_status = GAME_MODE_MAIN;
  12080.       DrawMainMenu();
  12081.     }
  12082.   }
  12083.   else
  12084.   {
  12085.  
  12086. #if 1
  12087.     if (tape.playing && tape.deactivate_display)
  12088.       TapeDeactivateDisplayOff(TRUE);
  12089. #endif
  12090.  
  12091.     OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
  12092.  
  12093. #if 1
  12094.     if (tape.playing && tape.deactivate_display)
  12095.       TapeDeactivateDisplayOn();
  12096. #endif
  12097.  
  12098.   }
  12099. }
  12100.  
  12101.  
  12102. /* ---------- new game button stuff ---------------------------------------- */
  12103.  
  12104. /* graphic position values for game buttons */
  12105. #define GAME_BUTTON_XSIZE    30
  12106. #define GAME_BUTTON_YSIZE    30
  12107. #define GAME_BUTTON_XPOS    5
  12108. #define GAME_BUTTON_YPOS    215
  12109. #define SOUND_BUTTON_XPOS    5
  12110. #define SOUND_BUTTON_YPOS    (GAME_BUTTON_YPOS + GAME_BUTTON_YSIZE)
  12111.  
  12112. #define GAME_BUTTON_STOP_XPOS    (GAME_BUTTON_XPOS + 0 * GAME_BUTTON_XSIZE)
  12113. #define GAME_BUTTON_PAUSE_XPOS    (GAME_BUTTON_XPOS + 1 * GAME_BUTTON_XSIZE)
  12114. #define GAME_BUTTON_PLAY_XPOS    (GAME_BUTTON_XPOS + 2 * GAME_BUTTON_XSIZE)
  12115. #define SOUND_BUTTON_MUSIC_XPOS    (SOUND_BUTTON_XPOS + 0 * GAME_BUTTON_XSIZE)
  12116. #define SOUND_BUTTON_LOOPS_XPOS    (SOUND_BUTTON_XPOS + 1 * GAME_BUTTON_XSIZE)
  12117. #define SOUND_BUTTON_SIMPLE_XPOS (SOUND_BUTTON_XPOS + 2 * GAME_BUTTON_XSIZE)
  12118.  
  12119. static struct
  12120. {
  12121.   int x, y;
  12122.   int gadget_id;
  12123.   char *infotext;
  12124. } gamebutton_info[NUM_GAME_BUTTONS] =
  12125. {
  12126.   {
  12127.     GAME_BUTTON_STOP_XPOS,    GAME_BUTTON_YPOS,
  12128.     GAME_CTRL_ID_STOP,
  12129.     "stop game"
  12130.   },
  12131.   {
  12132.     GAME_BUTTON_PAUSE_XPOS,    GAME_BUTTON_YPOS,
  12133.     GAME_CTRL_ID_PAUSE,
  12134.     "pause game"
  12135.   },
  12136.   {
  12137.     GAME_BUTTON_PLAY_XPOS,    GAME_BUTTON_YPOS,
  12138.     GAME_CTRL_ID_PLAY,
  12139.     "play game"
  12140.   },
  12141.   {
  12142.     SOUND_BUTTON_MUSIC_XPOS,    SOUND_BUTTON_YPOS,
  12143.     SOUND_CTRL_ID_MUSIC,
  12144.     "background music on/off"
  12145.   },
  12146.   {
  12147.     SOUND_BUTTON_LOOPS_XPOS,    SOUND_BUTTON_YPOS,
  12148.     SOUND_CTRL_ID_LOOPS,
  12149.     "sound loops on/off"
  12150.   },
  12151.   {
  12152.     SOUND_BUTTON_SIMPLE_XPOS,    SOUND_BUTTON_YPOS,
  12153.     SOUND_CTRL_ID_SIMPLE,
  12154.     "normal sounds on/off"
  12155.   }
  12156. };
  12157.  
  12158. void CreateGameButtons()
  12159. {
  12160.   int i;
  12161.  
  12162.   for (i = 0; i < NUM_GAME_BUTTONS; i++)
  12163.   {
  12164.     Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
  12165.     struct GadgetInfo *gi;
  12166.     int button_type;
  12167.     boolean checked;
  12168.     unsigned long event_mask;
  12169.     int gd_xoffset, gd_yoffset;
  12170.     int gd_x1, gd_x2, gd_y1, gd_y2;
  12171.     int id = i;
  12172.  
  12173.     gd_xoffset = gamebutton_info[i].x;
  12174.     gd_yoffset = gamebutton_info[i].y;
  12175.     gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
  12176.     gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
  12177.  
  12178.     if (id == GAME_CTRL_ID_STOP ||
  12179.     id == GAME_CTRL_ID_PAUSE ||
  12180.     id == GAME_CTRL_ID_PLAY)
  12181.     {
  12182.       button_type = GD_TYPE_NORMAL_BUTTON;
  12183.       checked = FALSE;
  12184.       event_mask = GD_EVENT_RELEASED;
  12185.       gd_y1  = DOOR_GFX_PAGEY1 + gd_yoffset - GAME_BUTTON_YSIZE;
  12186.       gd_y2  = DOOR_GFX_PAGEY1 + gd_yoffset - GAME_BUTTON_YSIZE;
  12187.     }
  12188.     else
  12189.     {
  12190.       button_type = GD_TYPE_CHECK_BUTTON;
  12191.       checked =
  12192.     ((id == SOUND_CTRL_ID_MUSIC && setup.sound_music) ||
  12193.      (id == SOUND_CTRL_ID_LOOPS && setup.sound_loops) ||
  12194.      (id == SOUND_CTRL_ID_SIMPLE && setup.sound_simple) ? TRUE : FALSE);
  12195.       event_mask = GD_EVENT_PRESSED;
  12196.       gd_y1  = DOOR_GFX_PAGEY1 + gd_yoffset;
  12197.       gd_y2  = DOOR_GFX_PAGEY1 + gd_yoffset - GAME_BUTTON_YSIZE;
  12198.     }
  12199.  
  12200.     gi = CreateGadget(GDI_CUSTOM_ID, id,
  12201.               GDI_INFO_TEXT, gamebutton_info[i].infotext,
  12202.               GDI_X, DX + gd_xoffset,
  12203.               GDI_Y, DY + gd_yoffset,
  12204.               GDI_WIDTH, GAME_BUTTON_XSIZE,
  12205.               GDI_HEIGHT, GAME_BUTTON_YSIZE,
  12206.               GDI_TYPE, button_type,
  12207.               GDI_STATE, GD_BUTTON_UNPRESSED,
  12208.               GDI_CHECKED, checked,
  12209.               GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y1,
  12210.               GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y1,
  12211.               GDI_ALT_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y2,
  12212.               GDI_ALT_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y2,
  12213.               GDI_EVENT_MASK, event_mask,
  12214.               GDI_CALLBACK_ACTION, HandleGameButtons,
  12215.               GDI_END);
  12216.  
  12217.     if (gi == NULL)
  12218.       Error(ERR_EXIT, "cannot create gadget");
  12219.  
  12220.     game_gadget[id] = gi;
  12221.   }
  12222. }
  12223.  
  12224. void FreeGameButtons()
  12225. {
  12226.   int i;
  12227.  
  12228.   for (i = 0; i < NUM_GAME_BUTTONS; i++)
  12229.     FreeGadget(game_gadget[i]);
  12230. }
  12231.  
  12232. static void MapGameButtons()
  12233. {
  12234.   int i;
  12235.  
  12236.   for (i = 0; i < NUM_GAME_BUTTONS; i++)
  12237.     MapGadget(game_gadget[i]);
  12238. }
  12239.  
  12240. void UnmapGameButtons()
  12241. {
  12242.   int i;
  12243.  
  12244.   for (i = 0; i < NUM_GAME_BUTTONS; i++)
  12245.     UnmapGadget(game_gadget[i]);
  12246. }
  12247.  
  12248. static void HandleGameButtons(struct GadgetInfo *gi)
  12249. {
  12250.   int id = gi->custom_id;
  12251.  
  12252.   if (game_status != GAME_MODE_PLAYING)
  12253.     return;
  12254.  
  12255.   switch (id)
  12256.   {
  12257.     case GAME_CTRL_ID_STOP:
  12258.       RequestQuitGame(TRUE);
  12259.       break;
  12260.  
  12261.     case GAME_CTRL_ID_PAUSE:
  12262.       if (options.network)
  12263.       {
  12264. #if defined(NETWORK_AVALIABLE)
  12265.     if (tape.pausing)
  12266.       SendToServer_ContinuePlaying();
  12267.     else
  12268.       SendToServer_PausePlaying();
  12269. #endif
  12270.       }
  12271.       else
  12272.     TapeTogglePause(TAPE_TOGGLE_MANUAL);
  12273.       break;
  12274.  
  12275.     case GAME_CTRL_ID_PLAY:
  12276.       if (tape.pausing)
  12277.       {
  12278. #if defined(NETWORK_AVALIABLE)
  12279.     if (options.network)
  12280.       SendToServer_ContinuePlaying();
  12281.     else
  12282. #endif
  12283.     {
  12284.       tape.pausing = FALSE;
  12285.       DrawVideoDisplay(VIDEO_STATE_PAUSE_OFF,0);
  12286.     }
  12287.       }
  12288.       break;
  12289.  
  12290.     case SOUND_CTRL_ID_MUSIC:
  12291.       if (setup.sound_music)
  12292.       { 
  12293.     setup.sound_music = FALSE;
  12294.     FadeMusic();
  12295.       }
  12296.       else if (audio.music_available)
  12297.       { 
  12298.     setup.sound = setup.sound_music = TRUE;
  12299.  
  12300.     SetAudioMode(setup.sound);
  12301.  
  12302.     PlayLevelMusic();
  12303.       }
  12304.       break;
  12305.  
  12306.     case SOUND_CTRL_ID_LOOPS:
  12307.       if (setup.sound_loops)
  12308.     setup.sound_loops = FALSE;
  12309.       else if (audio.loops_available)
  12310.       {
  12311.     setup.sound = setup.sound_loops = TRUE;
  12312.     SetAudioMode(setup.sound);
  12313.       }
  12314.       break;
  12315.  
  12316.     case SOUND_CTRL_ID_SIMPLE:
  12317.       if (setup.sound_simple)
  12318.     setup.sound_simple = FALSE;
  12319.       else if (audio.sound_available)
  12320.       {
  12321.     setup.sound = setup.sound_simple = TRUE;
  12322.     SetAudioMode(setup.sound);
  12323.       }
  12324.       break;
  12325.  
  12326.     default:
  12327.       break;
  12328.   }
  12329. }
  12330.