1fbb21a5cef1115e2672f62d0f3dd47f907f9da4
[rocksndiamonds.git] / src / game.c
1 /***********************************************************
2 *  Rocks'n'Diamonds -- McDuffin Strikes Back!              *
3 *----------------------------------------------------------*
4 *  (c) 1995-98 Artsoft Entertainment                       *
5 *              Holger Schemel                              *
6 *              Oststrasse 11a                              *
7 *              33604 Bielefeld                             *
8 *              phone: ++49 +521 290471                     *
9 *              email: aeglos@valinor.owl.de                *
10 *----------------------------------------------------------*
11 *  game.c                                                  *
12 ***********************************************************/
13
14 #include "game.h"
15 #include "misc.h"
16 #include "tools.h"
17 #include "screens.h"
18 #include "sound.h"
19 #include "init.h"
20 #include "buttons.h"
21 #include "files.h"
22 #include "tape.h"
23 #include "joystick.h"
24 #include "network.h"
25
26 /* for DigField() */
27 #define DF_NO_PUSH              0
28 #define DF_DIG                  1
29 #define DF_SNAP                 2
30
31 /* for MoveFigure() */
32 #define MF_NO_ACTION            0
33 #define MF_MOVING               1
34 #define MF_ACTION               2
35
36 /* for ScrollFigure() */
37 #define SCROLL_INIT             0
38 #define SCROLL_GO_ON            1
39
40 /* for Explode() */
41 #define EX_PHASE_START          0
42 #define EX_NORMAL               0
43 #define EX_CENTER               1
44 #define EX_BORDER               2
45
46 /* special positions in the game control window (relative to control window) */
47 #define XX_LEVEL                37
48 #define YY_LEVEL                20
49 #define XX_EMERALDS             29
50 #define YY_EMERALDS             54
51 #define XX_DYNAMITE             29
52 #define YY_DYNAMITE             89
53 #define XX_KEYS                 18
54 #define YY_KEYS                 123
55 #define XX_SCORE                15
56 #define YY_SCORE                159
57 #define XX_TIME                 29
58 #define YY_TIME                 194
59
60 /* special positions in the game control window (relative to main window) */
61 #define DX_LEVEL                (DX + XX_LEVEL)
62 #define DY_LEVEL                (DY + YY_LEVEL)
63 #define DX_EMERALDS             (DX + XX_EMERALDS)
64 #define DY_EMERALDS             (DY + YY_EMERALDS)
65 #define DX_DYNAMITE             (DX + XX_DYNAMITE)
66 #define DY_DYNAMITE             (DY + YY_DYNAMITE)
67 #define DX_KEYS                 (DX + XX_KEYS)
68 #define DY_KEYS                 (DY + YY_KEYS)
69 #define DX_SCORE                (DX + XX_SCORE)
70 #define DY_SCORE                (DY + YY_SCORE)
71 #define DX_TIME                 (DX + XX_TIME)
72 #define DY_TIME                 (DY + YY_TIME)
73
74 #define IS_LOOP_SOUND(s)        ((s)==SND_KLAPPER || (s)==SND_ROEHR ||  \
75                                  (s)==SND_NJAM || (s)==SND_MIEP)
76 #define IS_MUSIC_SOUND(s)       ((s)==SND_ALCHEMY || (s)==SND_CHASE || \
77                                  (s)==SND_NETWORK || (s)==SND_CZARDASZ || \
78                                  (s)==SND_TYGER || (s)==SND_VOYAGER || \
79                                  (s)==SND_TWILIGHT)
80
81 /* values for player movement speed (which is in fact a delay value) */
82 #define MOVE_DELAY_NORMAL_SPEED 8
83 #define MOVE_DELAY_HIGH_SPEED   4
84
85 #define DOUBLE_MOVE_DELAY(x)    (x = (x <= MOVE_DELAY_HIGH_SPEED ? x * 2 : x))
86 #define HALVE_MOVE_DELAY(x)     (x = (x >= MOVE_DELAY_HIGH_SPEED ? x / 2 : x))
87 #define DOUBLE_PLAYER_SPEED(p)  (HALVE_MOVE_DELAY((p)->move_delay_value))
88 #define HALVE_PLAYER_SPEED(p)   (DOUBLE_MOVE_DELAY((p)->move_delay_value))
89
90 /* game button identifiers */
91 #define GAME_CTRL_ID_STOP               0
92 #define GAME_CTRL_ID_PAUSE              1
93 #define GAME_CTRL_ID_PLAY               2
94 #define SOUND_CTRL_ID_MUSIC             3
95 #define SOUND_CTRL_ID_LOOPS             4
96 #define SOUND_CTRL_ID_SIMPLE            5
97
98 #define NUM_GAME_BUTTONS                6
99
100 /* forward declaration for internal use */
101 static void CheckGravityMovement(struct PlayerInfo *);
102
103 static void MapGameButtons();
104 static void HandleGameButtons(struct GadgetInfo *);
105
106 static struct GadgetInfo *game_gadget[NUM_GAME_BUTTONS];
107
108
109
110 #ifdef DEBUG
111 #if 0
112 static unsigned int getStateCheckSum(int counter)
113 {
114   int x, y;
115   unsigned int mult = 1;
116   unsigned int checksum = 0;
117   /*
118   static short lastFeld[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
119   */
120   static boolean first_game = TRUE;
121
122   for (y=0; y<lev_fieldy; y++) for(x=0; x<lev_fieldx; x++)
123   {
124     /*
125     if (counter == 3)
126     {
127       if (first_game)
128         lastFeld[x][y] = Feld[x][y];
129       else if (lastFeld[x][y] != Feld[x][y])
130         printf("DIFF: [%d][%d]: lastFeld == %d != %d == Feld\n",
131                x, y, lastFeld[x][y], Feld[x][y]);
132     }
133     */
134
135     checksum += mult++ * Ur[x][y];
136     checksum += mult++ * Feld[x][y];
137
138     /*
139     checksum += mult++ * MovPos[x][y];
140     checksum += mult++ * MovDir[x][y];
141     checksum += mult++ * MovDelay[x][y];
142     checksum += mult++ * Store[x][y];
143     checksum += mult++ * Store2[x][y];
144     checksum += mult++ * StorePlayer[x][y];
145     checksum += mult++ * Frame[x][y];
146     checksum += mult++ * AmoebaNr[x][y];
147     checksum += mult++ * JustHit[x][y];
148     checksum += mult++ * Stop[x][y];
149     */
150   }
151
152   if (counter == 3 && first_game)
153     first_game = FALSE;
154
155   return checksum;
156 }
157 #endif
158 #endif
159
160
161
162
163 void GetPlayerConfig()
164 {
165   if (sound_status == SOUND_OFF)
166     setup.sound = FALSE;
167
168   if (!sound_loops_allowed)
169   {
170     setup.sound_loops = FALSE;
171     setup.sound_music = FALSE;
172   }
173
174   setup.sound_simple = setup.sound;
175
176   InitJoysticks();
177 }
178
179 static void InitField(int x, int y, boolean init_game)
180 {
181   switch (Feld[x][y])
182   {
183     case EL_SPIELFIGUR:
184     case EL_SP_MURPHY:
185       if (init_game)
186         Feld[x][y] = EL_SPIELER1;
187       /* no break! */
188     case EL_SPIELER1:
189     case EL_SPIELER2:
190     case EL_SPIELER3:
191     case EL_SPIELER4:
192       if (init_game)
193       {
194         struct PlayerInfo *player = &stored_player[Feld[x][y] - EL_SPIELER1];
195         int jx = player->jx, jy = player->jy;
196
197         player->present = TRUE;
198
199         if (!options.network || player->connected)
200         {
201           player->active = TRUE;
202
203           /* remove potentially duplicate players */
204           if (StorePlayer[jx][jy] == Feld[x][y])
205             StorePlayer[jx][jy] = 0;
206
207           StorePlayer[x][y] = Feld[x][y];
208
209           if (options.verbose)
210           {
211             printf("Player %d activated.\n", player->element_nr);
212             printf("[Local player is %d and currently %s.]\n",
213                    local_player->element_nr,
214                    local_player->active ? "active" : "not active");
215           }
216         }
217
218         Feld[x][y] = EL_LEERRAUM;
219         player->jx = player->last_jx = x;
220         player->jy = player->last_jy = y;
221       }
222       break;
223
224     case EL_BADEWANNE:
225       if (x < lev_fieldx-1 && Feld[x+1][y] == EL_SALZSAEURE)
226         Feld[x][y] = EL_BADEWANNE1;
227       else if (x > 0 && Feld[x-1][y] == EL_SALZSAEURE)
228         Feld[x][y] = EL_BADEWANNE2;
229       else if (y > 0 && Feld[x][y-1] == EL_BADEWANNE1)
230         Feld[x][y] = EL_BADEWANNE3;
231       else if (y > 0 && Feld[x][y-1] == EL_SALZSAEURE)
232         Feld[x][y] = EL_BADEWANNE4;
233       else if (y > 0 && Feld[x][y-1] == EL_BADEWANNE2)
234         Feld[x][y] = EL_BADEWANNE5;
235       break;
236
237     case EL_KAEFER_R:
238     case EL_KAEFER_O:
239     case EL_KAEFER_L:
240     case EL_KAEFER_U:
241     case EL_KAEFER:
242     case EL_FLIEGER_R:
243     case EL_FLIEGER_O:
244     case EL_FLIEGER_L:
245     case EL_FLIEGER_U:
246     case EL_FLIEGER:
247     case EL_BUTTERFLY_R:
248     case EL_BUTTERFLY_O:
249     case EL_BUTTERFLY_L:
250     case EL_BUTTERFLY_U:
251     case EL_BUTTERFLY:
252     case EL_FIREFLY_R:
253     case EL_FIREFLY_O:
254     case EL_FIREFLY_L:
255     case EL_FIREFLY_U:
256     case EL_FIREFLY:
257     case EL_PACMAN_R:
258     case EL_PACMAN_O:
259     case EL_PACMAN_L:
260     case EL_PACMAN_U:
261     case EL_MAMPFER:
262     case EL_MAMPFER2:
263     case EL_ROBOT:
264     case EL_PACMAN:
265     case EL_SP_SNIKSNAK:
266     case EL_SP_ELECTRON:
267       InitMovDir(x, y);
268       break;
269
270     case EL_AMOEBE_VOLL:
271     case EL_AMOEBE_BD:
272       InitAmoebaNr(x, y);
273       break;
274
275     case EL_TROPFEN:
276       if (y == lev_fieldy - 1)
277       {
278         Feld[x][y] = EL_AMOEBING;
279         Store[x][y] = EL_AMOEBE_NASS;
280       }
281       break;
282
283     case EL_DYNAMITE_ACTIVE:
284       MovDelay[x][y] = 96;
285       break;
286
287     case EL_BIRNE_AUS:
288       local_player->lights_still_needed++;
289       break;
290
291     case EL_SOKOBAN_FELD_LEER:
292       local_player->sokobanfields_still_needed++;
293       break;
294
295     case EL_MAULWURF:
296     case EL_PINGUIN:
297       local_player->friends_still_needed++;
298       break;
299
300     case EL_SCHWEIN:
301     case EL_DRACHE:
302       MovDir[x][y] = 1 << RND(4);
303       break;
304
305     case EL_SP_EMPTY:
306       Feld[x][y] = EL_LEERRAUM;
307       break;
308
309     case EL_EM_KEY_1_FILE:
310       Feld[x][y] = EL_EM_KEY_1;
311       break;
312     case EL_EM_KEY_2_FILE:
313       Feld[x][y] = EL_EM_KEY_2;
314       break;
315     case EL_EM_KEY_3_FILE:
316       Feld[x][y] = EL_EM_KEY_3;
317       break;
318     case EL_EM_KEY_4_FILE:
319       Feld[x][y] = EL_EM_KEY_4;
320       break;
321
322     default:
323       break;
324   }
325 }
326
327 void InitGame()
328 {
329   int i, j, x, y;
330   boolean emulate_bd = TRUE;    /* unless non-BOULDERDASH elements found */
331   boolean emulate_sb = TRUE;    /* unless non-SOKOBAN     elements found */
332   boolean emulate_sp = TRUE;    /* unless non-SUPAPLEX    elements found */
333
334   /* don't play tapes over network */
335   network_playing = (options.network && !tape.playing);
336
337   for (i=0; i<MAX_PLAYERS; i++)
338   {
339     struct PlayerInfo *player = &stored_player[i];
340
341     player->index_nr = i;
342     player->element_nr = EL_SPIELER1 + i;
343
344     player->present = FALSE;
345     player->active = FALSE;
346
347     player->action = 0;
348     player->effective_action = 0;
349     player->programmed_action = 0;
350
351     player->score = 0;
352     player->gems_still_needed = level.gems_needed;
353     player->sokobanfields_still_needed = 0;
354     player->lights_still_needed = 0;
355     player->friends_still_needed = 0;
356
357     for (j=0; j<4; j++)
358       player->key[j] = FALSE;
359
360     player->dynamite = 0;
361     player->dynabomb_count = 0;
362     player->dynabomb_size = 1;
363     player->dynabombs_left = 0;
364     player->dynabomb_xl = FALSE;
365
366     player->MovDir = MV_NO_MOVING;
367     player->MovPos = 0;
368     player->Pushing = FALSE;
369     player->GfxPos = 0;
370     player->Frame = 0;
371
372     player->actual_frame_counter = 0;
373
374     player->frame_reset_delay = 0;
375
376     player->push_delay = 0;
377     player->push_delay_value = 5;
378
379     player->move_delay = 0;
380     player->last_move_dir = MV_NO_MOVING;
381
382     player->move_delay_value =
383       (level.double_speed ? MOVE_DELAY_HIGH_SPEED : MOVE_DELAY_NORMAL_SPEED);
384
385     player->snapped = FALSE;
386
387     player->last_jx = player->last_jy = 0;
388     player->jx = player->jy = 0;
389
390     DigField(player, 0, 0, 0, 0, DF_NO_PUSH);
391     SnapField(player, 0, 0);
392
393     player->LevelSolved = FALSE;
394     player->GameOver = FALSE;
395   }
396
397   network_player_action_received = FALSE;
398
399 #ifndef MSDOS
400   /* initial null action */
401   if (network_playing)
402     SendToServer_MovePlayer(MV_NO_MOVING);
403 #endif
404
405   ZX = ZY = -1;
406
407   game.yam_content_nr = 0;
408   FrameCounter = 0;
409   TimeFrames = 0;
410   TimePlayed = 0;
411   TimeLeft = level.time;
412
413   ScreenMovDir = MV_NO_MOVING;
414   ScreenMovPos = 0;
415   ScreenGfxPos = 0;
416
417   ScrollStepSize = 0;   /* will be correctly initialized by ScrollScreen() */
418
419   AllPlayersGone = FALSE;
420   game.magic_wall_active = FALSE;
421   game.magic_wall_time_left = 0;
422
423   for (i=0; i<MAX_NUM_AMOEBA; i++)
424     AmoebaCnt[i] = AmoebaCnt2[i] = 0;
425
426   for (x=0; x<lev_fieldx; x++)
427   {
428     for (y=0; y<lev_fieldy; y++)
429     {
430       Feld[x][y] = Ur[x][y];
431       MovPos[x][y] = MovDir[x][y] = MovDelay[x][y] = 0;
432       Store[x][y] = Store2[x][y] = StorePlayer[x][y] = 0;
433       Frame[x][y] = 0;
434       AmoebaNr[x][y] = 0;
435       JustHit[x][y] = 0;
436       Stop[x][y] = FALSE;
437     }
438   }
439
440   for(y=0; y<lev_fieldy; y++)
441   {
442     for(x=0; x<lev_fieldx; x++)
443     {
444       if (emulate_bd && !IS_BD_ELEMENT(Feld[x][y]))
445         emulate_bd = FALSE;
446       if (emulate_sb && !IS_SB_ELEMENT(Feld[x][y]))
447         emulate_sb = FALSE;
448       if (emulate_sp && !IS_SP_ELEMENT(Feld[x][y]))
449         emulate_sp = FALSE;
450
451       InitField(x, y, TRUE);
452     }
453   }
454
455   /* check if any connected player was not found in playfield */
456   for (i=0; i<MAX_PLAYERS; i++)
457   {
458     struct PlayerInfo *player = &stored_player[i];
459
460     if (player->connected && !player->present)
461     {
462       for (j=0; j<MAX_PLAYERS; j++)
463       {
464         struct PlayerInfo *some_player = &stored_player[j];
465         int jx = some_player->jx, jy = some_player->jy;
466
467         /* assign first free player found that is present in the playfield */
468         if (some_player->present && !some_player->connected)
469         {
470           player->present = TRUE;
471           player->active = TRUE;
472           some_player->present = FALSE;
473
474           StorePlayer[jx][jy] = player->element_nr;
475           player->jx = player->last_jx = jx;
476           player->jy = player->last_jy = jy;
477
478           break;
479         }
480       }
481     }
482   }
483
484   if (tape.playing)
485   {
486     /* when playing a tape, eliminate all players who do not participate */
487
488     for (i=0; i<MAX_PLAYERS; i++)
489     {
490       if (stored_player[i].active && !tape.player_participates[i])
491       {
492         struct PlayerInfo *player = &stored_player[i];
493         int jx = player->jx, jy = player->jy;
494
495         player->active = FALSE;
496         StorePlayer[jx][jy] = 0;
497         Feld[jx][jy] = EL_LEERRAUM;
498       }
499     }
500   }
501   else if (!options.network && !setup.team_mode)        /* && !tape.playing */
502   {
503     /* when in single player mode, eliminate all but the first active player */
504
505     for (i=0; i<MAX_PLAYERS; i++)
506     {
507       if (stored_player[i].active)
508       {
509         for (j=i+1; j<MAX_PLAYERS; j++)
510         {
511           if (stored_player[j].active)
512           {
513             struct PlayerInfo *player = &stored_player[j];
514             int jx = player->jx, jy = player->jy;
515
516             player->active = FALSE;
517             StorePlayer[jx][jy] = 0;
518             Feld[jx][jy] = EL_LEERRAUM;
519           }
520         }
521       }
522     }
523   }
524
525   /* when recording the game, store which players take part in the game */
526   if (tape.recording)
527   {
528     for (i=0; i<MAX_PLAYERS; i++)
529       if (stored_player[i].active)
530         tape.player_participates[i] = TRUE;
531   }
532
533   if (options.verbose)
534   {
535     for (i=0; i<MAX_PLAYERS; i++)
536     {
537       struct PlayerInfo *player = &stored_player[i];
538
539       printf("Player %d: present == %d, connected == %d, active == %d.\n",
540              i+1,
541              player->present,
542              player->connected,
543              player->active);
544       if (local_player == player)
545         printf("Player  %d is local player.\n", i+1);
546     }
547   }
548
549   game.emulation = (emulate_bd ? EMU_BOULDERDASH :
550                     emulate_sb ? EMU_SOKOBAN :
551                     emulate_sp ? EMU_SUPAPLEX : EMU_NONE);
552
553   if (BorderElement == EL_LEERRAUM)
554   {
555     SBX_Left = 0;
556     SBX_Right = lev_fieldx - SCR_FIELDX;
557     SBY_Upper = 0;
558     SBY_Lower = lev_fieldy - SCR_FIELDY;
559   }
560   else
561   {
562     SBX_Left = -1;
563     SBX_Right = lev_fieldx - SCR_FIELDX + 1;
564     SBY_Upper = -1;
565     SBY_Lower = lev_fieldy - SCR_FIELDY + 1;
566   }
567
568   if (lev_fieldx + (SBX_Left == -1 ? 2 : 0) <= SCR_FIELDX)
569     SBX_Left = SBX_Right = -1 * (SCR_FIELDX - lev_fieldx) / 2;
570
571   if (lev_fieldy + (SBY_Upper == -1 ? 2 : 0) <= SCR_FIELDY)
572     SBY_Upper = SBY_Lower = -1 * (SCR_FIELDY - lev_fieldy) / 2;
573
574   scroll_x = SBX_Left;
575   scroll_y = SBY_Upper;
576   if (local_player->jx >= SBX_Left + MIDPOSX)
577     scroll_x = (local_player->jx <= SBX_Right + MIDPOSX ?
578                 local_player->jx - MIDPOSX :
579                 SBX_Right);
580   if (local_player->jy >= SBY_Upper + MIDPOSY)
581     scroll_y = (local_player->jy <= SBY_Lower + MIDPOSY ?
582                 local_player->jy - MIDPOSY :
583                 SBY_Lower);
584
585   CloseDoor(DOOR_CLOSE_1);
586
587   DrawLevel();
588   DrawAllPlayers();
589   FadeToFront();
590
591   if (setup.soft_scrolling)
592     XCopyArea(display, fieldbuffer, backbuffer, gc,
593               FX, FY, SXSIZE, SYSIZE, SX, SY);
594
595   redraw_mask |= REDRAW_FROM_BACKBUFFER;
596
597   /* copy default game door content to main double buffer */
598   XCopyArea(display, pix[PIX_DOOR], drawto, gc,
599             DOOR_GFX_PAGEX5, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE, DX, DY);
600
601   if (level_nr < 100)
602     DrawText(DX + XX_LEVEL, DY + YY_LEVEL,
603              int2str(level_nr, 2), FS_SMALL, FC_YELLOW);
604   else
605   {
606     DrawTextExt(drawto, gc, DX + XX_EMERALDS, DY + YY_EMERALDS,
607                 int2str(level_nr, 3), FS_SMALL, FC_SPECIAL3);
608     XCopyArea(display, drawto, drawto, gc,
609               DX + XX_EMERALDS, DY + YY_EMERALDS + 1,
610               FONT5_XSIZE * 3, FONT5_YSIZE - 1,
611               DX + XX_LEVEL - 1, DY + YY_LEVEL + 1);
612   }
613
614   DrawText(DX + XX_EMERALDS, DY + YY_EMERALDS,
615            int2str(local_player->gems_still_needed, 3), FS_SMALL, FC_YELLOW);
616   DrawText(DX + XX_DYNAMITE, DY + YY_DYNAMITE,
617            int2str(local_player->dynamite, 3), FS_SMALL, FC_YELLOW);
618   DrawText(DX + XX_SCORE, DY + YY_SCORE,
619            int2str(local_player->score, 5), FS_SMALL, FC_YELLOW);
620   DrawText(DX + XX_TIME, DY + YY_TIME,
621            int2str(TimeLeft, 3), FS_SMALL, FC_YELLOW);
622
623   UnmapGameButtons();
624   game_gadget[SOUND_CTRL_ID_MUSIC]->checked = setup.sound_music;
625   game_gadget[SOUND_CTRL_ID_LOOPS]->checked = setup.sound_loops;
626   game_gadget[SOUND_CTRL_ID_SIMPLE]->checked = setup.sound_simple;
627   MapGameButtons();
628   MapTapeButtons();
629
630   /* copy actual game door content to door double buffer for OpenDoor() */
631   XCopyArea(display, drawto, pix[PIX_DB_DOOR], gc,
632             DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
633
634   OpenDoor(DOOR_OPEN_ALL);
635
636   if (setup.sound_music)
637     PlaySoundLoop(background_loop[level_nr % num_bg_loops]);
638
639   XAutoRepeatOff(display);
640
641   if (options.verbose)
642   {
643     for (i=0; i<4; i++)
644       printf("Player %d %sactive.\n",
645              i + 1, (stored_player[i].active ? "" : "not "));
646   }
647 }
648
649 void InitMovDir(int x, int y)
650 {
651   int i, element = Feld[x][y];
652   static int xy[4][2] =
653   {
654     {  0, +1 },
655     { +1,  0 },
656     {  0, -1 },
657     { -1,  0 }
658   };
659   static int direction[2][4] =
660   {
661     { MV_RIGHT, MV_UP,   MV_LEFT,  MV_DOWN },
662     { MV_LEFT,  MV_DOWN, MV_RIGHT, MV_UP }
663   };
664
665   switch(element)
666   {
667     case EL_KAEFER_R:
668     case EL_KAEFER_O:
669     case EL_KAEFER_L:
670     case EL_KAEFER_U:
671       Feld[x][y] = EL_KAEFER;
672       MovDir[x][y] = direction[0][element - EL_KAEFER_R];
673       break;
674
675     case EL_FLIEGER_R:
676     case EL_FLIEGER_O:
677     case EL_FLIEGER_L:
678     case EL_FLIEGER_U:
679       Feld[x][y] = EL_FLIEGER;
680       MovDir[x][y] = direction[0][element - EL_FLIEGER_R];
681       break;
682
683     case EL_BUTTERFLY_R:
684     case EL_BUTTERFLY_O:
685     case EL_BUTTERFLY_L:
686     case EL_BUTTERFLY_U:
687       Feld[x][y] = EL_BUTTERFLY;
688       MovDir[x][y] = direction[0][element - EL_BUTTERFLY_R];
689       break;
690
691     case EL_FIREFLY_R:
692     case EL_FIREFLY_O:
693     case EL_FIREFLY_L:
694     case EL_FIREFLY_U:
695       Feld[x][y] = EL_FIREFLY;
696       MovDir[x][y] = direction[0][element - EL_FIREFLY_R];
697       break;
698
699     case EL_PACMAN_R:
700     case EL_PACMAN_O:
701     case EL_PACMAN_L:
702     case EL_PACMAN_U:
703       Feld[x][y] = EL_PACMAN;
704       MovDir[x][y] = direction[0][element - EL_PACMAN_R];
705       break;
706
707     case EL_SP_SNIKSNAK:
708       MovDir[x][y] = MV_UP;
709       break;
710
711     case EL_SP_ELECTRON:
712       MovDir[x][y] = MV_LEFT;
713       break;
714
715     default:
716       MovDir[x][y] = 1 << RND(4);
717       if (element != EL_KAEFER &&
718           element != EL_FLIEGER &&
719           element != EL_BUTTERFLY &&
720           element != EL_FIREFLY)
721         break;
722
723       for (i=0; i<4; i++)
724       {
725         int x1 = x + xy[i][0];
726         int y1 = y + xy[i][1];
727
728         if (!IN_LEV_FIELD(x1, y1) || !IS_FREE(x1, y1))
729         {
730           if (element == EL_KAEFER || element == EL_BUTTERFLY)
731           {
732             MovDir[x][y] = direction[0][i];
733             break;
734           }
735           else if (element == EL_FLIEGER || element == EL_FIREFLY ||
736                    element == EL_SP_SNIKSNAK || element == EL_SP_ELECTRON)
737           {
738             MovDir[x][y] = direction[1][i];
739             break;
740           }
741         }
742       }
743       break;
744   }
745 }
746
747 void InitAmoebaNr(int x, int y)
748 {
749   int i;
750   int group_nr = AmoebeNachbarNr(x, y);
751
752   if (group_nr == 0)
753   {
754     for (i=1; i<MAX_NUM_AMOEBA; i++)
755     {
756       if (AmoebaCnt[i] == 0)
757       {
758         group_nr = i;
759         break;
760       }
761     }
762   }
763
764   AmoebaNr[x][y] = group_nr;
765   AmoebaCnt[group_nr]++;
766   AmoebaCnt2[group_nr]++;
767 }
768
769 void GameWon()
770 {
771   int hi_pos;
772   int bumplevel = FALSE;
773
774   if (local_player->MovPos)
775     return;
776
777   local_player->LevelSolved = FALSE;
778
779   if (TimeLeft)
780   {
781     if (setup.sound_loops)
782       PlaySoundExt(SND_SIRR, PSND_MAX_VOLUME, PSND_MAX_RIGHT, PSND_LOOP);
783
784     while(TimeLeft > 0)
785     {
786       if (!setup.sound_loops)
787         PlaySoundStereo(SND_SIRR, PSND_MAX_RIGHT);
788       if (TimeLeft > 0 && !(TimeLeft % 10))
789         RaiseScore(level.score[SC_ZEITBONUS]);
790       if (TimeLeft > 100 && !(TimeLeft % 10))
791         TimeLeft -= 10;
792       else
793         TimeLeft--;
794       DrawText(DX_TIME, DY_TIME, int2str(TimeLeft, 3), FS_SMALL, FC_YELLOW);
795       BackToFront();
796       Delay(10);
797     }
798
799     if (setup.sound_loops)
800       StopSound(SND_SIRR);
801   }
802   else if (level.time == 0)             /* level without time limit */
803   {
804     if (setup.sound_loops)
805       PlaySoundExt(SND_SIRR, PSND_MAX_VOLUME, PSND_MAX_RIGHT, PSND_LOOP);
806
807     while(TimePlayed < 999)
808     {
809       if (!setup.sound_loops)
810         PlaySoundStereo(SND_SIRR, PSND_MAX_RIGHT);
811       if (TimePlayed < 999 && !(TimePlayed % 10))
812         RaiseScore(level.score[SC_ZEITBONUS]);
813       if (TimePlayed < 900 && !(TimePlayed % 10))
814         TimePlayed += 10;
815       else
816         TimePlayed++;
817       DrawText(DX_TIME, DY_TIME, int2str(TimePlayed, 3), FS_SMALL, FC_YELLOW);
818       BackToFront();
819       Delay(10);
820     }
821
822     if (setup.sound_loops)
823       StopSound(SND_SIRR);
824   }
825
826   FadeSounds();
827
828   /* Hero disappears */
829   DrawLevelField(ExitX, ExitY);
830   BackToFront();
831
832   if (tape.playing)
833     return;
834
835   CloseDoor(DOOR_CLOSE_1);
836
837   if (tape.recording)
838   {
839     TapeStop();
840     SaveTape(tape.level_nr);            /* Ask to save tape */
841   }
842
843   if ((hi_pos = NewHiScore()) >= 0) 
844   {
845     game_status = HALLOFFAME;
846     DrawHallOfFame(hi_pos);
847     if (bumplevel && TAPE_IS_EMPTY(tape))
848       level_nr++;
849   }
850   else
851   {
852     game_status = MAINMENU;
853     if (bumplevel && TAPE_IS_EMPTY(tape))
854       level_nr++;
855     DrawMainMenu();
856   }
857
858   BackToFront();
859 }
860
861 int NewHiScore()
862 {
863   int k, l;
864   int position = -1;
865
866   LoadScore(level_nr);
867
868   if (strcmp(setup.player_name, EMPTY_PLAYER_NAME) == 0 ||
869       local_player->score < highscore[MAX_SCORE_ENTRIES - 1].Score) 
870     return -1;
871
872   for (k=0; k<MAX_SCORE_ENTRIES; k++) 
873   {
874     if (local_player->score > highscore[k].Score)
875     {
876       /* player has made it to the hall of fame */
877
878       if (k < MAX_SCORE_ENTRIES - 1)
879       {
880         int m = MAX_SCORE_ENTRIES - 1;
881
882 #ifdef ONE_PER_NAME
883         for (l=k; l<MAX_SCORE_ENTRIES; l++)
884           if (!strcmp(setup.player_name, highscore[l].Name))
885             m = l;
886         if (m == k)     /* player's new highscore overwrites his old one */
887           goto put_into_list;
888 #endif
889
890         for (l=m; l>k; l--)
891         {
892           strcpy(highscore[l].Name, highscore[l - 1].Name);
893           highscore[l].Score = highscore[l - 1].Score;
894         }
895       }
896
897 #ifdef ONE_PER_NAME
898       put_into_list:
899 #endif
900       strncpy(highscore[k].Name, setup.player_name, MAX_NAMELEN - 1);
901       highscore[k].Name[MAX_NAMELEN - 1] = '\0';
902       highscore[k].Score = local_player->score; 
903       position = k;
904       break;
905     }
906
907 #ifdef ONE_PER_NAME
908     else if (!strncmp(setup.player_name, highscore[k].Name, MAX_NAMELEN - 1))
909       break;    /* player already there with a higher score */
910 #endif
911
912   }
913
914   if (position >= 0) 
915     SaveScore(level_nr);
916
917   return position;
918 }
919
920 void InitMovingField(int x, int y, int direction)
921 {
922   int newx = x + (direction == MV_LEFT ? -1 : direction == MV_RIGHT ? +1 : 0);
923   int newy = y + (direction == MV_UP   ? -1 : direction == MV_DOWN  ? +1 : 0);
924
925   MovDir[x][y] = direction;
926   MovDir[newx][newy] = direction;
927   if (Feld[newx][newy] == EL_LEERRAUM)
928     Feld[newx][newy] = EL_BLOCKED;
929 }
930
931 void Moving2Blocked(int x, int y, int *goes_to_x, int *goes_to_y)
932 {
933   int direction = MovDir[x][y];
934   int newx = x + (direction == MV_LEFT ? -1 : direction == MV_RIGHT ? +1 : 0);
935   int newy = y + (direction == MV_UP   ? -1 : direction == MV_DOWN  ? +1 : 0);
936
937   *goes_to_x = newx;
938   *goes_to_y = newy;
939 }
940
941 void Blocked2Moving(int x, int y, int *comes_from_x, int *comes_from_y)
942 {
943   int oldx = x, oldy = y;
944   int direction = MovDir[x][y];
945
946   if (direction == MV_LEFT)
947     oldx++;
948   else if (direction == MV_RIGHT)
949     oldx--;
950   else if (direction == MV_UP)
951     oldy++;
952   else if (direction == MV_DOWN)
953     oldy--;
954
955   *comes_from_x = oldx;
956   *comes_from_y = oldy;
957 }
958
959 int MovingOrBlocked2Element(int x, int y)
960 {
961   int element = Feld[x][y];
962
963   if (element == EL_BLOCKED)
964   {
965     int oldx, oldy;
966
967     Blocked2Moving(x, y, &oldx, &oldy);
968     return Feld[oldx][oldy];
969   }
970   else
971     return element;
972 }
973
974 static int MovingOrBlocked2ElementIfNotLeaving(int x, int y)
975 {
976   /* like MovingOrBlocked2Element(), but if element is moving
977      and (x,y) is the field the moving element is just leaving,
978      return EL_BLOCKED instead of the element value */
979   int element = Feld[x][y];
980
981   if (IS_MOVING(x, y))
982   {
983     if (element == EL_BLOCKED)
984     {
985       int oldx, oldy;
986
987       Blocked2Moving(x, y, &oldx, &oldy);
988       return Feld[oldx][oldy];
989     }
990     else
991       return EL_BLOCKED;
992   }
993   else
994     return element;
995 }
996
997 static void RemoveField(int x, int y)
998 {
999   Feld[x][y] = EL_LEERRAUM;
1000   MovPos[x][y] = 0;
1001   MovDir[x][y] = 0;
1002   MovDelay[x][y] = 0;
1003 }
1004
1005 void RemoveMovingField(int x, int y)
1006 {
1007   int oldx = x, oldy = y, newx = x, newy = y;
1008
1009   if (Feld[x][y] != EL_BLOCKED && !IS_MOVING(x, y))
1010     return;
1011
1012   if (IS_MOVING(x, y))
1013   {
1014     Moving2Blocked(x, y, &newx, &newy);
1015     if (Feld[newx][newy] != EL_BLOCKED)
1016       return;
1017   }
1018   else if (Feld[x][y] == EL_BLOCKED)
1019   {
1020     Blocked2Moving(x, y, &oldx, &oldy);
1021     if (!IS_MOVING(oldx, oldy))
1022       return;
1023   }
1024
1025   if (Feld[x][y] == EL_BLOCKED &&
1026       (Store[oldx][oldy] == EL_MORAST_LEER ||
1027        Store[oldx][oldy] == EL_SIEB_LEER ||
1028        Store[oldx][oldy] == EL_SIEB2_LEER ||
1029        Store[oldx][oldy] == EL_AMOEBE_NASS))
1030   {
1031     Feld[oldx][oldy] = Store[oldx][oldy];
1032     Store[oldx][oldy] = Store2[oldx][oldy] = 0;
1033   }
1034   else
1035     Feld[oldx][oldy] = EL_LEERRAUM;
1036
1037   Feld[newx][newy] = EL_LEERRAUM;
1038   MovPos[oldx][oldy] = MovDir[oldx][oldy] = MovDelay[oldx][oldy] = 0;
1039   MovPos[newx][newy] = MovDir[newx][newy] = MovDelay[newx][newy] = 0;
1040
1041   DrawLevelField(oldx, oldy);
1042   DrawLevelField(newx, newy);
1043 }
1044
1045 void DrawDynamite(int x, int y)
1046 {
1047   int sx = SCREENX(x), sy = SCREENY(y);
1048   int graphic = el2gfx(Feld[x][y]);
1049   int phase;
1050
1051   if (!IN_SCR_FIELD(sx, sy) || IS_PLAYER(x, y))
1052     return;
1053
1054   if (Store[x][y])
1055     DrawGraphic(sx, sy, el2gfx(Store[x][y]));
1056
1057   if (Feld[x][y] == EL_DYNAMITE_ACTIVE)
1058   {
1059     if ((phase = (96 - MovDelay[x][y]) / 12) > 6)
1060       phase = 6;
1061   }
1062   else
1063   {
1064     if ((phase = ((96 - MovDelay[x][y]) / 6) % 8) > 3)
1065       phase = 7 - phase;
1066   }
1067
1068   if (game.emulation == EMU_SUPAPLEX)
1069     DrawGraphic(sx, sy, GFX_SP_DISK_RED);
1070   else if (Store[x][y])
1071     DrawGraphicThruMask(sx, sy, graphic + phase);
1072   else
1073     DrawGraphic(sx, sy, graphic + phase);
1074 }
1075
1076 void CheckDynamite(int x, int y)
1077 {
1078   if (MovDelay[x][y])           /* dynamite is still waiting to explode */
1079   {
1080     MovDelay[x][y]--;
1081     if (MovDelay[x][y])
1082     {
1083       if (!(MovDelay[x][y] % 12))
1084         PlaySoundLevel(x, y, SND_ZISCH);
1085
1086       if (IS_ACTIVE_BOMB(Feld[x][y]))
1087       {
1088         int delay = (Feld[x][y] == EL_DYNAMITE_ACTIVE ? 12 : 6);
1089
1090         if (!(MovDelay[x][y] % delay))
1091           DrawDynamite(x, y);
1092       }
1093
1094       return;
1095     }
1096   }
1097
1098   StopSound(SND_ZISCH);
1099   Bang(x, y);
1100 }
1101
1102 void Explode(int ex, int ey, int phase, int mode)
1103 {
1104   int x, y;
1105   int num_phase = 9, delay = 2;
1106   int last_phase = num_phase * delay;
1107   int half_phase = (num_phase / 2) * delay;
1108   int first_phase_after_start = EX_PHASE_START + 1;
1109
1110   if (phase == EX_PHASE_START)          /* initialize 'Store[][]' field */
1111   {
1112     int center_element = Feld[ex][ey];
1113
1114     if (IS_MOVING(ex, ey) || IS_BLOCKED(ex, ey))
1115     {
1116       center_element = MovingOrBlocked2Element(ex, ey);
1117       RemoveMovingField(ex, ey);
1118     }
1119
1120     for (y=ey-1; y<ey+2; y++) for(x=ex-1; x<ex+2; x++)
1121     {
1122       int element = Feld[x][y];
1123
1124       if (IS_MOVING(x, y) || IS_BLOCKED(x, y))
1125       {
1126         element = MovingOrBlocked2Element(x, y);
1127         RemoveMovingField(x, y);
1128       }
1129
1130       if (!IN_LEV_FIELD(x, y) || IS_MASSIVE(element) || element == EL_BURNING)
1131         continue;
1132
1133       if ((mode != EX_NORMAL || center_element == EL_AMOEBA2DIAM) &&
1134           (x != ex || y != ey))
1135         continue;
1136
1137       if (element == EL_EXPLODING)
1138         element = Store2[x][y];
1139
1140       if (IS_PLAYER(ex, ey))
1141       {
1142         switch(StorePlayer[ex][ey])
1143         {
1144           case EL_SPIELER2:
1145             Store[x][y] = EL_EDELSTEIN_ROT;
1146             break;
1147           case EL_SPIELER3:
1148             Store[x][y] = EL_EDELSTEIN;
1149             break;
1150           case EL_SPIELER4:
1151             Store[x][y] = EL_EDELSTEIN_LILA;
1152             break;
1153           case EL_SPIELER1:
1154           default:
1155             Store[x][y] = EL_EDELSTEIN_GELB;
1156             break;
1157         }
1158
1159         if (game.emulation == EMU_SUPAPLEX)
1160           Store[x][y] = EL_LEERRAUM;
1161       }
1162       else if (center_element == EL_MAULWURF)
1163         Store[x][y] = EL_EDELSTEIN_ROT;
1164       else if (center_element == EL_PINGUIN)
1165         Store[x][y] = EL_EDELSTEIN_LILA;
1166       else if (center_element == EL_KAEFER)
1167         Store[x][y] = ((x == ex && y == ey) ? EL_DIAMANT : EL_EDELSTEIN);
1168       else if (center_element == EL_BUTTERFLY)
1169         Store[x][y] = EL_EDELSTEIN_BD;
1170       else if (center_element == EL_SP_ELECTRON)
1171         Store[x][y] = EL_SP_INFOTRON;
1172       else if (center_element == EL_MAMPFER)
1173         Store[x][y] = level.yam_content[game.yam_content_nr][x-ex+1][y-ey+1];
1174       else if (center_element == EL_AMOEBA2DIAM)
1175         Store[x][y] = level.amoeba_content;
1176       else if (element == EL_ERZ_EDEL)
1177         Store[x][y] = EL_EDELSTEIN;
1178       else if (element == EL_ERZ_DIAM)
1179         Store[x][y] = EL_DIAMANT;
1180       else if (element == EL_ERZ_EDEL_BD)
1181         Store[x][y] = EL_EDELSTEIN_BD;
1182       else if (element == EL_ERZ_EDEL_GELB)
1183         Store[x][y] = EL_EDELSTEIN_GELB;
1184       else if (element == EL_ERZ_EDEL_ROT)
1185         Store[x][y] = EL_EDELSTEIN_ROT;
1186       else if (element == EL_ERZ_EDEL_LILA)
1187         Store[x][y] = EL_EDELSTEIN_LILA;
1188       else if (!IS_PFORTE(Store[x][y]))
1189         Store[x][y] = EL_LEERRAUM;
1190
1191       if (x != ex || y != ey ||
1192           center_element == EL_AMOEBA2DIAM || mode == EX_BORDER)
1193         Store2[x][y] = element;
1194
1195       if (AmoebaNr[x][y] &&
1196           (element == EL_AMOEBE_VOLL ||
1197            element == EL_AMOEBE_BD ||
1198            element == EL_AMOEBING))
1199       {
1200         AmoebaCnt[AmoebaNr[x][y]]--;
1201         AmoebaCnt2[AmoebaNr[x][y]]--;
1202       }
1203
1204       Feld[x][y] = EL_EXPLODING;
1205       MovDir[x][y] = MovPos[x][y] = 0;
1206       AmoebaNr[x][y] = 0;
1207       Frame[x][y] = 1;
1208       Stop[x][y] = TRUE;
1209     }
1210
1211     if (center_element == EL_MAMPFER)
1212       game.yam_content_nr = (game.yam_content_nr + 1) % level.num_yam_contents;
1213
1214     return;
1215   }
1216
1217   if (Stop[ex][ey])
1218     return;
1219
1220   x = ex;
1221   y = ey;
1222
1223   Frame[x][y] = (phase < last_phase ? phase + 1 : 0);
1224
1225   if (phase == first_phase_after_start)
1226   {
1227     int element = Store2[x][y];
1228
1229     if (element == EL_BLACK_ORB)
1230     {
1231       Feld[x][y] = Store2[x][y];
1232       Store2[x][y] = 0;
1233       Bang(x, y);
1234     }
1235   }
1236   else if (phase == half_phase)
1237   {
1238     int element = Store2[x][y];
1239
1240     if (IS_PLAYER(x, y))
1241       KillHero(PLAYERINFO(x, y));
1242     else if (IS_EXPLOSIVE(element))
1243     {
1244       Feld[x][y] = Store2[x][y];
1245       Store2[x][y] = 0;
1246       Bang(x, y);
1247     }
1248     else if (element == EL_AMOEBA2DIAM)
1249       AmoebeUmwandeln(x, y);
1250   }
1251
1252   if (phase == last_phase)
1253   {
1254     int element;
1255
1256     element = Feld[x][y] = Store[x][y];
1257     Store[x][y] = Store2[x][y] = 0;
1258     MovDir[x][y] = MovPos[x][y] = MovDelay[x][y] = 0;
1259     InitField(x, y, FALSE);
1260     if (CAN_MOVE(element) || COULD_MOVE(element))
1261       InitMovDir(x, y);
1262     DrawLevelField(x, y);
1263   }
1264   else if (!(phase % delay) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1265   {
1266     int graphic = GFX_EXPLOSION;
1267
1268     if (game.emulation == EMU_SUPAPLEX)
1269       graphic = (Store[x][y] == EL_SP_INFOTRON ?
1270                  GFX_SP_EXPLODE_INFOTRON :
1271                  GFX_SP_EXPLODE_EMPTY);
1272
1273     if (phase == delay)
1274       ErdreichAnbroeckeln(SCREENX(x), SCREENY(y));
1275
1276     DrawGraphic(SCREENX(x), SCREENY(y), graphic + (phase / delay - 1));
1277   }
1278 }
1279
1280 void DynaExplode(int ex, int ey)
1281 {
1282   int i, j;
1283   int dynabomb_size = 1;
1284   boolean dynabomb_xl = FALSE;
1285   struct PlayerInfo *player;
1286   static int xy[4][2] =
1287   {
1288     { 0, -1 },
1289     { -1, 0 },
1290     { +1, 0 },
1291     { 0, +1 }
1292   };
1293
1294   if (IS_ACTIVE_BOMB(Feld[ex][ey]))
1295   {
1296     player = &stored_player[Feld[ex][ey] - EL_DYNABOMB_ACTIVE_1];
1297     dynabomb_size = player->dynabomb_size;
1298     dynabomb_xl = player->dynabomb_xl;
1299     player->dynabombs_left++;
1300   }
1301
1302   Explode(ex, ey, EX_PHASE_START, EX_CENTER);
1303
1304   for (i=0; i<4; i++)
1305   {
1306     for (j=1; j<=dynabomb_size; j++)
1307     {
1308       int x = ex + j * xy[i % 4][0];
1309       int y = ey + j * xy[i % 4][1];
1310       int element;
1311
1312       if (!IN_LEV_FIELD(x, y) || IS_MASSIVE(Feld[x][y]))
1313         break;
1314
1315       element = Feld[x][y];
1316       Explode(x, y, EX_PHASE_START, EX_BORDER);
1317
1318       if (element != EL_LEERRAUM &&
1319           element != EL_ERDREICH &&
1320           element != EL_EXPLODING &&
1321           !dynabomb_xl)
1322         break;
1323     }
1324   }
1325 }
1326
1327 void Bang(int x, int y)
1328 {
1329   int element = Feld[x][y];
1330
1331   if (game.emulation == EMU_SUPAPLEX)
1332     PlaySoundLevel(x, y, SND_SP_BOOOM);
1333   else
1334     PlaySoundLevel(x, y, SND_ROAAAR);
1335
1336   if (IS_PLAYER(x, y))  /* remove objects that might cause smaller explosion */
1337     element = EL_LEERRAUM;
1338
1339   switch(element)
1340   {
1341     case EL_KAEFER:
1342     case EL_FLIEGER:
1343     case EL_BUTTERFLY:
1344     case EL_FIREFLY:
1345     case EL_MAMPFER:
1346     case EL_MAMPFER2:
1347     case EL_ROBOT:
1348     case EL_PACMAN:
1349       RaiseScoreElement(element);
1350       Explode(x, y, EX_PHASE_START, EX_NORMAL);
1351       break;
1352     case EL_DYNABOMB_ACTIVE_1:
1353     case EL_DYNABOMB_ACTIVE_2:
1354     case EL_DYNABOMB_ACTIVE_3:
1355     case EL_DYNABOMB_ACTIVE_4:
1356     case EL_DYNABOMB_NR:
1357     case EL_DYNABOMB_SZ:
1358     case EL_DYNABOMB_XL:
1359       DynaExplode(x, y);
1360       break;
1361     case EL_MAULWURF:
1362     case EL_PINGUIN:
1363     case EL_BIRNE_AUS:
1364     case EL_BIRNE_EIN:
1365       Explode(x, y, EX_PHASE_START, EX_CENTER);
1366       break;
1367     default:
1368       Explode(x, y, EX_PHASE_START, EX_NORMAL);
1369       break;
1370   }
1371 }
1372
1373 void Blurb(int x, int y)
1374 {
1375   int element = Feld[x][y];
1376
1377   if (element != EL_BLURB_LEFT && element != EL_BLURB_RIGHT)    /* start */
1378   {
1379     PlaySoundLevel(x, y, SND_BLURB);
1380     if (IN_LEV_FIELD(x-1, y) && IS_FREE(x-1, y) &&
1381         (!IN_LEV_FIELD(x-1, y-1) ||
1382          !CAN_FALL(MovingOrBlocked2Element(x-1, y-1))))
1383     {
1384       Feld[x-1][y] = EL_BLURB_LEFT;
1385     }
1386     if (IN_LEV_FIELD(x+1, y) && IS_FREE(x+1, y) &&
1387         (!IN_LEV_FIELD(x+1, y-1) ||
1388          !CAN_FALL(MovingOrBlocked2Element(x+1, y-1))))
1389     {
1390       Feld[x+1][y] = EL_BLURB_RIGHT;
1391     }
1392   }
1393   else                                                          /* go on */
1394   {
1395     int graphic = (element==EL_BLURB_LEFT ? GFX_BLURB_LEFT : GFX_BLURB_RIGHT);
1396
1397     if (!MovDelay[x][y])        /* initialize animation counter */
1398       MovDelay[x][y] = 9;
1399
1400     if (MovDelay[x][y])         /* continue animation */
1401     {
1402       MovDelay[x][y]--;
1403       if (MovDelay[x][y]/2 && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1404         DrawGraphic(SCREENX(x), SCREENY(y), graphic+4-MovDelay[x][y]/2);
1405
1406       if (!MovDelay[x][y])
1407       {
1408         Feld[x][y] = EL_LEERRAUM;
1409         DrawLevelField(x, y);
1410       }
1411     }
1412   }
1413 }
1414
1415 void Impact(int x, int y)
1416 {
1417   boolean lastline = (y == lev_fieldy-1);
1418   boolean object_hit = FALSE;
1419   int element = Feld[x][y];
1420   int smashed = 0;
1421
1422   if (!lastline)        /* check if element below was hit */
1423   {
1424     if (Feld[x][y+1] == EL_PLAYER_IS_LEAVING)
1425       return;
1426
1427     object_hit = (!IS_FREE(x, y+1) && (!IS_MOVING(x, y+1) ||
1428                                       MovDir[x][y+1]!=MV_DOWN ||
1429                                       MovPos[x][y+1]<=TILEY/2));
1430     if (object_hit)
1431       smashed = MovingOrBlocked2Element(x, y+1);
1432   }
1433
1434   if (!lastline && smashed == EL_SALZSAEURE)    /* element falls into acid */
1435   {
1436     Blurb(x, y);
1437     return;
1438   }
1439
1440   if ((element == EL_BOMBE || element == EL_SP_DISK_ORANGE) &&
1441       (lastline || object_hit)) /* element is bomb */
1442   {
1443     Bang(x, y);
1444     return;
1445   }
1446
1447   if (element == EL_TROPFEN && (lastline || object_hit))        /* acid drop */
1448   {
1449     if (object_hit && IS_PLAYER(x, y+1))
1450       KillHero(PLAYERINFO(x, y+1));
1451     else if (object_hit && (smashed == EL_MAULWURF || smashed == EL_PINGUIN))
1452       Bang(x, y+1);
1453     else
1454     {
1455       Feld[x][y] = EL_AMOEBING;
1456       Store[x][y] = EL_AMOEBE_NASS;
1457     }
1458     return;
1459   }
1460
1461   if (!lastline && object_hit)          /* check which object was hit */
1462   {
1463     if (CAN_CHANGE(element) && 
1464         (smashed == EL_SIEB_INAKTIV || smashed == EL_SIEB2_INAKTIV))
1465     {
1466       int x, y;
1467       int activated_magic_wall =
1468         (smashed == EL_SIEB_INAKTIV ? EL_SIEB_LEER : EL_SIEB2_LEER);
1469
1470       /* activate magic wall / mill */
1471
1472       for (y=0; y<lev_fieldy; y++)
1473         for (x=0; x<lev_fieldx; x++)
1474           if (Feld[x][y] == smashed)
1475             Feld[x][y] = activated_magic_wall;
1476
1477       game.magic_wall_time_left = level.time_magic_wall * FRAMES_PER_SECOND;
1478       game.magic_wall_active = TRUE;
1479     }
1480
1481     if (IS_PLAYER(x, y+1))
1482     {
1483       KillHero(PLAYERINFO(x, y+1));
1484       return;
1485     }
1486     else if (smashed == EL_MAULWURF || smashed == EL_PINGUIN)
1487     {
1488       Bang(x, y+1);
1489       return;
1490     }
1491     else if (element == EL_EDELSTEIN_BD)
1492     {
1493       if (IS_ENEMY(smashed) && IS_BD_ELEMENT(smashed))
1494       {
1495         Bang(x, y+1);
1496         return;
1497       }
1498     }
1499     else if (element == EL_FELSBROCKEN || element == EL_SP_ZONK)
1500     {
1501       if (IS_ENEMY(smashed) ||
1502           smashed == EL_BOMBE || smashed == EL_SP_DISK_ORANGE ||
1503           smashed == EL_SONDE || smashed == EL_SCHWEIN || smashed == EL_DRACHE)
1504       {
1505         Bang(x, y+1);
1506         return;
1507       }
1508       else if (!IS_MOVING(x, y+1))
1509       {
1510         if (smashed == EL_BIRNE_AUS || smashed == EL_BIRNE_EIN)
1511         {
1512           Bang(x, y+1);
1513           return;
1514         }
1515         else if (smashed == EL_KOKOSNUSS)
1516         {
1517           Feld[x][y+1] = EL_CRACKINGNUT;
1518           PlaySoundLevel(x, y, SND_KNACK);
1519           RaiseScoreElement(EL_KOKOSNUSS);
1520           return;
1521         }
1522         else if (smashed == EL_DIAMANT)
1523         {
1524           Feld[x][y+1] = EL_LEERRAUM;
1525           PlaySoundLevel(x, y, SND_QUIRK);
1526           return;
1527         }
1528       }
1529     }
1530   }
1531
1532   /* play sound of magic wall / mill */
1533   if (!lastline &&
1534       (Feld[x][y+1] == EL_SIEB_LEER || Feld[x][y+1] == EL_SIEB2_LEER))
1535   {
1536     PlaySoundLevel(x, y, SND_QUIRK);
1537     return;
1538   }
1539
1540   /* play sound of object that hits the ground */
1541   if (lastline || object_hit)
1542   {
1543     int sound;
1544
1545     switch(element)
1546     {
1547       case EL_EDELSTEIN:
1548       case EL_EDELSTEIN_BD:
1549       case EL_EDELSTEIN_GELB:
1550       case EL_EDELSTEIN_ROT:
1551       case EL_EDELSTEIN_LILA:
1552       case EL_DIAMANT:
1553       case EL_SP_INFOTRON:
1554         sound = SND_PLING;
1555         break;
1556       case EL_KOKOSNUSS:
1557         sound = SND_KLUMPF;
1558         break;
1559       case EL_FELSBROCKEN:
1560         sound = SND_KLOPF;
1561         break;
1562       case EL_SP_ZONK:
1563         sound = SND_SP_ZONKDOWN;
1564         break;
1565       case EL_SCHLUESSEL:
1566       case EL_SCHLUESSEL1:
1567       case EL_SCHLUESSEL2:
1568       case EL_SCHLUESSEL3:
1569       case EL_SCHLUESSEL4:
1570       case EL_EM_KEY_1:
1571       case EL_EM_KEY_2:
1572       case EL_EM_KEY_3:
1573       case EL_EM_KEY_4:
1574         sound = SND_KINK;
1575         break;
1576       case EL_ZEIT_VOLL:
1577       case EL_ZEIT_LEER:
1578         sound = SND_DENG;
1579         break;
1580       default:
1581         sound = -1;
1582         break;
1583     }
1584
1585     if (sound>=0)
1586       PlaySoundLevel(x, y, sound);
1587   }
1588 }
1589
1590 void TurnRound(int x, int y)
1591 {
1592   static struct
1593   {
1594     int x, y;
1595   } move_xy[] =
1596   {
1597     { 0, 0 },
1598     {-1, 0 },
1599     {+1, 0 },
1600     { 0, 0 },
1601     { 0, -1 },
1602     { 0, 0 }, { 0, 0 }, { 0, 0 },
1603     { 0, +1 }
1604   };
1605   static struct
1606   {
1607     int left, right, back;
1608   } turn[] =
1609   {
1610     { 0,        0,              0 },
1611     { MV_DOWN,  MV_UP,          MV_RIGHT },
1612     { MV_UP,    MV_DOWN,        MV_LEFT },
1613     { 0,        0,              0 },
1614     { MV_LEFT,  MV_RIGHT,       MV_DOWN },
1615     { 0,0,0 },  { 0,0,0 },      { 0,0,0 },
1616     { MV_RIGHT, MV_LEFT,        MV_UP }
1617   };
1618
1619   int element = Feld[x][y];
1620   int old_move_dir = MovDir[x][y];
1621   int left_dir = turn[old_move_dir].left;
1622   int right_dir = turn[old_move_dir].right;
1623   int back_dir = turn[old_move_dir].back;
1624
1625   int left_dx = move_xy[left_dir].x, left_dy = move_xy[left_dir].y;
1626   int right_dx = move_xy[right_dir].x, right_dy = move_xy[right_dir].y;
1627   int move_dx = move_xy[old_move_dir].x, move_dy = move_xy[old_move_dir].y;
1628   int back_dx = move_xy[back_dir].x, back_dy = move_xy[back_dir].y;
1629
1630   int left_x = x+left_dx, left_y = y+left_dy;
1631   int right_x = x+right_dx, right_y = y+right_dy;
1632   int move_x = x+move_dx, move_y = y+move_dy;
1633
1634   if (element == EL_KAEFER || element == EL_BUTTERFLY)
1635   {
1636     TestIfBadThingHitsOtherBadThing(x, y);
1637
1638     if (IN_LEV_FIELD(right_x, right_y) &&
1639         IS_FREE_OR_PLAYER(right_x, right_y))
1640       MovDir[x][y] = right_dir;
1641     else if (!IN_LEV_FIELD(move_x, move_y) ||
1642              !IS_FREE_OR_PLAYER(move_x, move_y))
1643       MovDir[x][y] = left_dir;
1644
1645     if (element == EL_KAEFER && MovDir[x][y] != old_move_dir)
1646       MovDelay[x][y] = 9;
1647     else if (element == EL_BUTTERFLY)   /* && MovDir[x][y] == left_dir) */
1648       MovDelay[x][y] = 1;
1649   }
1650   else if (element == EL_FLIEGER || element == EL_FIREFLY ||
1651            element == EL_SP_SNIKSNAK || element == EL_SP_ELECTRON)
1652   {
1653     TestIfBadThingHitsOtherBadThing(x, y);
1654
1655     if (IN_LEV_FIELD(left_x, left_y) &&
1656         IS_FREE_OR_PLAYER(left_x, left_y))
1657       MovDir[x][y] = left_dir;
1658     else if (!IN_LEV_FIELD(move_x, move_y) ||
1659              !IS_FREE_OR_PLAYER(move_x, move_y))
1660       MovDir[x][y] = right_dir;
1661
1662     if ((element == EL_FLIEGER ||
1663          element == EL_SP_SNIKSNAK || element == EL_SP_ELECTRON)
1664         && MovDir[x][y] != old_move_dir)
1665       MovDelay[x][y] = 9;
1666     else if (element == EL_FIREFLY)     /* && MovDir[x][y] == right_dir) */
1667       MovDelay[x][y] = 1;
1668   }
1669   else if (element == EL_MAMPFER)
1670   {
1671     boolean can_turn_left = FALSE, can_turn_right = FALSE;
1672
1673     if (IN_LEV_FIELD(left_x, left_y) &&
1674         (IS_FREE_OR_PLAYER(left_x, left_y) ||
1675          Feld[left_x][left_y] == EL_DIAMANT))
1676       can_turn_left = TRUE;
1677     if (IN_LEV_FIELD(right_x, right_y) &&
1678         (IS_FREE_OR_PLAYER(right_x, right_y) ||
1679          Feld[right_x][right_y] == EL_DIAMANT))
1680       can_turn_right = TRUE;
1681
1682     if (can_turn_left && can_turn_right)
1683       MovDir[x][y] = (RND(3) ? (RND(2) ? left_dir : right_dir) : back_dir);
1684     else if (can_turn_left)
1685       MovDir[x][y] = (RND(2) ? left_dir : back_dir);
1686     else if (can_turn_right)
1687       MovDir[x][y] = (RND(2) ? right_dir : back_dir);
1688     else
1689       MovDir[x][y] = back_dir;
1690
1691     MovDelay[x][y] = 16+16*RND(3);
1692   }
1693   else if (element == EL_MAMPFER2)
1694   {
1695     boolean can_turn_left = FALSE, can_turn_right = FALSE;
1696
1697     if (IN_LEV_FIELD(left_x, left_y) &&
1698         (IS_FREE_OR_PLAYER(left_x, left_y) ||
1699          IS_MAMPF2(Feld[left_x][left_y])))
1700       can_turn_left = TRUE;
1701     if (IN_LEV_FIELD(right_x, right_y) &&
1702         (IS_FREE_OR_PLAYER(right_x, right_y) ||
1703          IS_MAMPF2(Feld[right_x][right_y])))
1704       can_turn_right = TRUE;
1705
1706     if (can_turn_left && can_turn_right)
1707       MovDir[x][y] = (RND(3) ? (RND(2) ? left_dir : right_dir) : back_dir);
1708     else if (can_turn_left)
1709       MovDir[x][y] = (RND(2) ? left_dir : back_dir);
1710     else if (can_turn_right)
1711       MovDir[x][y] = (RND(2) ? right_dir : back_dir);
1712     else
1713       MovDir[x][y] = back_dir;
1714
1715     MovDelay[x][y] = 16+16*RND(3);
1716   }
1717   else if (element == EL_PACMAN)
1718   {
1719     boolean can_turn_left = FALSE, can_turn_right = FALSE;
1720
1721     if (IN_LEV_FIELD(left_x, left_y) &&
1722         (IS_FREE_OR_PLAYER(left_x, left_y) ||
1723          IS_AMOEBOID(Feld[left_x][left_y])))
1724       can_turn_left = TRUE;
1725     if (IN_LEV_FIELD(right_x, right_y) &&
1726         (IS_FREE_OR_PLAYER(right_x, right_y) ||
1727          IS_AMOEBOID(Feld[right_x][right_y])))
1728       can_turn_right = TRUE;
1729
1730     if (can_turn_left && can_turn_right)
1731       MovDir[x][y] = (RND(3) ? (RND(2) ? left_dir : right_dir) : back_dir);
1732     else if (can_turn_left)
1733       MovDir[x][y] = (RND(2) ? left_dir : back_dir);
1734     else if (can_turn_right)
1735       MovDir[x][y] = (RND(2) ? right_dir : back_dir);
1736     else
1737       MovDir[x][y] = back_dir;
1738
1739     MovDelay[x][y] = 6+RND(40);
1740   }
1741   else if (element == EL_SCHWEIN)
1742   {
1743     boolean can_turn_left = FALSE, can_turn_right = FALSE, can_move_on = FALSE;
1744     boolean should_turn_left = FALSE, should_turn_right = FALSE;
1745     boolean should_move_on = FALSE;
1746     int rnd_value = 24;
1747     int rnd = RND(rnd_value);
1748
1749     if (IN_LEV_FIELD(left_x, left_y) &&
1750         (IS_FREE(left_x, left_y) || IS_GEM(Feld[left_x][left_y])))
1751       can_turn_left = TRUE;
1752     if (IN_LEV_FIELD(right_x, right_y) &&
1753         (IS_FREE(right_x, right_y) || IS_GEM(Feld[right_x][right_y])))
1754       can_turn_right = TRUE;
1755     if (IN_LEV_FIELD(move_x, move_y) &&
1756         (IS_FREE(move_x, move_y) || IS_GEM(Feld[move_x][move_y])))
1757       can_move_on = TRUE;
1758
1759     if (can_turn_left &&
1760         (!can_move_on ||
1761          (IN_LEV_FIELD(x+back_dx+left_dx, y+back_dy+left_dy) &&
1762           !IS_FREE(x+back_dx+left_dx, y+back_dy+left_dy))))
1763       should_turn_left = TRUE;
1764     if (can_turn_right &&
1765         (!can_move_on ||
1766          (IN_LEV_FIELD(x+back_dx+right_dx, y+back_dy+right_dy) &&
1767           !IS_FREE(x+back_dx+right_dx, y+back_dy+right_dy))))
1768       should_turn_right = TRUE;
1769     if (can_move_on &&
1770         (!can_turn_left || !can_turn_right ||
1771          (IN_LEV_FIELD(x+move_dx+left_dx, y+move_dy+left_dy) &&
1772           !IS_FREE(x+move_dx+left_dx, y+move_dy+left_dy)) ||
1773          (IN_LEV_FIELD(x+move_dx+right_dx, y+move_dy+right_dy) &&
1774           !IS_FREE(x+move_dx+right_dx, y+move_dy+right_dy))))
1775       should_move_on = TRUE;
1776
1777     if (should_turn_left || should_turn_right || should_move_on)
1778     {
1779       if (should_turn_left && should_turn_right && should_move_on)
1780         MovDir[x][y] = (rnd < rnd_value/3 ? left_dir :
1781                         rnd < 2*rnd_value/3 ? right_dir :
1782                         old_move_dir);
1783       else if (should_turn_left && should_turn_right)
1784         MovDir[x][y] = (rnd < rnd_value/2 ? left_dir : right_dir);
1785       else if (should_turn_left && should_move_on)
1786         MovDir[x][y] = (rnd < rnd_value/2 ? left_dir : old_move_dir);
1787       else if (should_turn_right && should_move_on)
1788         MovDir[x][y] = (rnd < rnd_value/2 ? right_dir : old_move_dir);
1789       else if (should_turn_left)
1790         MovDir[x][y] = left_dir;
1791       else if (should_turn_right)
1792         MovDir[x][y] = right_dir;
1793       else if (should_move_on)
1794         MovDir[x][y] = old_move_dir;
1795     }
1796     else if (can_move_on && rnd > rnd_value/8)
1797       MovDir[x][y] = old_move_dir;
1798     else if (can_turn_left && can_turn_right)
1799       MovDir[x][y] = (rnd < rnd_value/2 ? left_dir : right_dir);
1800     else if (can_turn_left && rnd > rnd_value/8)
1801       MovDir[x][y] = left_dir;
1802     else if (can_turn_right && rnd > rnd_value/8)
1803       MovDir[x][y] = right_dir;
1804     else
1805       MovDir[x][y] = back_dir;
1806
1807     if (!IS_FREE(x+move_xy[MovDir[x][y]].x, y+move_xy[MovDir[x][y]].y) &&
1808         !IS_GEM(Feld[x+move_xy[MovDir[x][y]].x][y+move_xy[MovDir[x][y]].y]))
1809       MovDir[x][y] = old_move_dir;
1810
1811     MovDelay[x][y] = 0;
1812   }
1813   else if (element == EL_DRACHE)
1814   {
1815     boolean can_turn_left = FALSE, can_turn_right = FALSE, can_move_on = FALSE;
1816     int rnd_value = 24;
1817     int rnd = RND(rnd_value);
1818
1819     if (IN_LEV_FIELD(left_x, left_y) && IS_FREE(left_x, left_y))
1820       can_turn_left = TRUE;
1821     if (IN_LEV_FIELD(right_x, right_y) && IS_FREE(right_x, right_y))
1822       can_turn_right = TRUE;
1823     if (IN_LEV_FIELD(move_x, move_y) && IS_FREE(move_x, move_y))
1824       can_move_on = TRUE;
1825
1826     if (can_move_on && rnd > rnd_value/8)
1827       MovDir[x][y] = old_move_dir;
1828     else if (can_turn_left && can_turn_right)
1829       MovDir[x][y] = (rnd < rnd_value/2 ? left_dir : right_dir);
1830     else if (can_turn_left && rnd > rnd_value/8)
1831       MovDir[x][y] = left_dir;
1832     else if (can_turn_right && rnd > rnd_value/8)
1833       MovDir[x][y] = right_dir;
1834     else
1835       MovDir[x][y] = back_dir;
1836
1837     if (!IS_FREE(x+move_xy[MovDir[x][y]].x, y+move_xy[MovDir[x][y]].y))
1838       MovDir[x][y] = old_move_dir;
1839
1840     MovDelay[x][y] = 0;
1841   }
1842   else if (element == EL_ROBOT || element == EL_SONDE ||
1843            element == EL_MAULWURF || element == EL_PINGUIN)
1844   {
1845     int attr_x = -1, attr_y = -1;
1846
1847     if (AllPlayersGone)
1848     {
1849       attr_x = ExitX;
1850       attr_y = ExitY;
1851     }
1852     else
1853     {
1854       int i;
1855
1856       for (i=0; i<MAX_PLAYERS; i++)
1857       {
1858         struct PlayerInfo *player = &stored_player[i];
1859         int jx = player->jx, jy = player->jy;
1860
1861         if (!player->active)
1862           continue;
1863
1864         if (attr_x == -1 || ABS(jx-x)+ABS(jy-y) < ABS(attr_x-x)+ABS(attr_y-y))
1865         {
1866           attr_x = jx;
1867           attr_y = jy;
1868         }
1869       }
1870     }
1871
1872     if (element == EL_ROBOT && ZX>=0 && ZY>=0)
1873     {
1874       attr_x = ZX;
1875       attr_y = ZY;
1876     }
1877
1878     if (element == EL_MAULWURF || element == EL_PINGUIN)
1879     {
1880       int i;
1881       static int xy[4][2] =
1882       {
1883         { 0, -1 },
1884         { -1, 0 },
1885         { +1, 0 },
1886         { 0, +1 }
1887       };
1888
1889       for (i=0; i<4; i++)
1890       {
1891         int ex = x + xy[i%4][0];
1892         int ey = y + xy[i%4][1];
1893
1894         if (IN_LEV_FIELD(ex, ey) && Feld[ex][ey] == EL_AUSGANG_AUF)
1895         {
1896           attr_x = ex;
1897           attr_y = ey;
1898           break;
1899         }
1900       }
1901     }
1902
1903     MovDir[x][y] = MV_NO_MOVING;
1904     if (attr_x<x)
1905       MovDir[x][y] |= (AllPlayersGone ? MV_RIGHT : MV_LEFT);
1906     else if (attr_x>x)
1907       MovDir[x][y] |= (AllPlayersGone ? MV_LEFT : MV_RIGHT);
1908     if (attr_y<y)
1909       MovDir[x][y] |= (AllPlayersGone ? MV_DOWN : MV_UP);
1910     else if (attr_y>y)
1911       MovDir[x][y] |= (AllPlayersGone ? MV_UP : MV_DOWN);
1912
1913     if (element == EL_ROBOT)
1914     {
1915       int newx, newy;
1916
1917       if ((MovDir[x][y]&(MV_LEFT|MV_RIGHT)) && (MovDir[x][y]&(MV_UP|MV_DOWN)))
1918         MovDir[x][y] &= (RND(2) ? (MV_LEFT|MV_RIGHT) : (MV_UP|MV_DOWN));
1919       Moving2Blocked(x, y, &newx, &newy);
1920
1921       if (IN_LEV_FIELD(newx, newy) && IS_FREE_OR_PLAYER(newx, newy))
1922         MovDelay[x][y] = 8+8*!RND(3);
1923       else
1924         MovDelay[x][y] = 16;
1925     }
1926     else
1927     {
1928       int newx, newy;
1929
1930       MovDelay[x][y] = 1;
1931
1932       if ((MovDir[x][y]&(MV_LEFT|MV_RIGHT)) && (MovDir[x][y]&(MV_UP|MV_DOWN)))
1933       {
1934         boolean first_horiz = RND(2);
1935         int new_move_dir = MovDir[x][y];
1936
1937         MovDir[x][y] =
1938           new_move_dir & (first_horiz ? (MV_LEFT|MV_RIGHT) : (MV_UP|MV_DOWN));
1939         Moving2Blocked(x, y, &newx, &newy);
1940
1941         if (IN_LEV_FIELD(newx, newy) &&
1942             (IS_FREE(newx, newy) ||
1943              Feld[newx][newy] == EL_SALZSAEURE ||
1944              ((element == EL_MAULWURF || element == EL_PINGUIN) &&
1945               (Feld[newx][newy] == EL_AUSGANG_AUF ||
1946                IS_MAMPF3(Feld[newx][newy])))))
1947           return;
1948
1949         MovDir[x][y] =
1950           new_move_dir & (!first_horiz ? (MV_LEFT|MV_RIGHT) : (MV_UP|MV_DOWN));
1951         Moving2Blocked(x, y, &newx, &newy);
1952
1953         if (IN_LEV_FIELD(newx, newy) &&
1954             (IS_FREE(newx, newy) ||
1955              Feld[newx][newy] == EL_SALZSAEURE ||
1956              ((element == EL_MAULWURF || element == EL_PINGUIN) &&
1957               (Feld[newx][newy] == EL_AUSGANG_AUF ||
1958                IS_MAMPF3(Feld[newx][newy])))))
1959           return;
1960
1961         MovDir[x][y] = old_move_dir;
1962         return;
1963       }
1964     }
1965   }
1966 }
1967
1968 static boolean JustBeingPushed(int x, int y)
1969 {
1970   int i;
1971
1972   for (i=0; i<MAX_PLAYERS; i++)
1973   {
1974     struct PlayerInfo *player = &stored_player[i];
1975
1976     if (player->active && player->Pushing && player->MovPos)
1977     {
1978       int next_jx = player->jx + (player->jx - player->last_jx);
1979       int next_jy = player->jy + (player->jy - player->last_jy);
1980
1981       if (x == next_jx && y == next_jy)
1982         return TRUE;
1983     }
1984   }
1985
1986   return FALSE;
1987 }
1988
1989 void StartMoving(int x, int y)
1990 {
1991   int element = Feld[x][y];
1992
1993   if (Stop[x][y])
1994     return;
1995
1996   if (CAN_FALL(element) && y<lev_fieldy-1)
1997   {
1998     if ((x>0 && IS_PLAYER(x-1, y)) || (x<lev_fieldx-1 && IS_PLAYER(x+1, y)))
1999       if (JustBeingPushed(x, y))
2000         return;
2001
2002     if (element == EL_MORAST_VOLL)
2003     {
2004       if (IS_FREE(x, y+1))
2005       {
2006         InitMovingField(x, y, MV_DOWN);
2007         Feld[x][y] = EL_FELSBROCKEN;
2008         Store[x][y] = EL_MORAST_LEER;
2009       }
2010       else if (Feld[x][y+1] == EL_MORAST_LEER)
2011       {
2012         if (!MovDelay[x][y])
2013           MovDelay[x][y] = TILEY + 1;
2014
2015         if (MovDelay[x][y])
2016         {
2017           MovDelay[x][y]--;
2018           if (MovDelay[x][y])
2019             return;
2020         }
2021
2022         Feld[x][y] = EL_MORAST_LEER;
2023         Feld[x][y+1] = EL_MORAST_VOLL;
2024       }
2025     }
2026     else if (element == EL_FELSBROCKEN && Feld[x][y+1] == EL_MORAST_LEER)
2027     {
2028       InitMovingField(x, y, MV_DOWN);
2029       Store[x][y] = EL_MORAST_VOLL;
2030     }
2031     else if (element == EL_SIEB_VOLL)
2032     {
2033       if (IS_FREE(x, y+1))
2034       {
2035         InitMovingField(x, y, MV_DOWN);
2036         Feld[x][y] = EL_CHANGED(Store2[x][y]);
2037         Store[x][y] = EL_SIEB_LEER;
2038       }
2039       else if (Feld[x][y+1] == EL_SIEB_LEER)
2040       {
2041         if (!MovDelay[x][y])
2042           MovDelay[x][y] = TILEY/4 + 1;
2043
2044         if (MovDelay[x][y])
2045         {
2046           MovDelay[x][y]--;
2047           if (MovDelay[x][y])
2048             return;
2049         }
2050
2051         Feld[x][y] = EL_SIEB_LEER;
2052         Feld[x][y+1] = EL_SIEB_VOLL;
2053         Store2[x][y+1] = EL_CHANGED(Store2[x][y]);
2054         Store2[x][y] = 0;
2055       }
2056     }
2057     else if (element == EL_SIEB2_VOLL)
2058     {
2059       if (IS_FREE(x, y+1))
2060       {
2061         InitMovingField(x, y, MV_DOWN);
2062         Feld[x][y] = EL_CHANGED2(Store2[x][y]);
2063         Store[x][y] = EL_SIEB2_LEER;
2064       }
2065       else if (Feld[x][y+1] == EL_SIEB2_LEER)
2066       {
2067         if (!MovDelay[x][y])
2068           MovDelay[x][y] = TILEY/4 + 1;
2069
2070         if (MovDelay[x][y])
2071         {
2072           MovDelay[x][y]--;
2073           if (MovDelay[x][y])
2074             return;
2075         }
2076
2077         Feld[x][y] = EL_SIEB2_LEER;
2078         Feld[x][y+1] = EL_SIEB2_VOLL;
2079         Store2[x][y+1] = EL_CHANGED2(Store2[x][y]);
2080         Store2[x][y] = 0;
2081       }
2082     }
2083     else if (CAN_CHANGE(element) &&
2084              (Feld[x][y+1] == EL_SIEB_LEER || Feld[x][y+1] == EL_SIEB2_LEER))
2085     {
2086       InitMovingField(x, y, MV_DOWN);
2087       Store[x][y] =
2088         (Feld[x][y+1] == EL_SIEB_LEER ? EL_SIEB_VOLL : EL_SIEB2_VOLL);
2089       Store2[x][y+1] = element;
2090     }
2091     else if (CAN_SMASH(element) && Feld[x][y+1] == EL_SALZSAEURE)
2092     {
2093       Blurb(x, y);
2094       InitMovingField(x, y, MV_DOWN);
2095       Store[x][y] = EL_SALZSAEURE;
2096     }
2097     else if (CAN_SMASH(element) && Feld[x][y+1] == EL_BLOCKED && JustHit[x][y])
2098     {
2099       Impact(x, y);
2100     }
2101     else if (IS_FREE(x, y+1))
2102     {
2103       InitMovingField(x, y, MV_DOWN);
2104     }
2105     else if (element == EL_TROPFEN)
2106     {
2107       Feld[x][y] = EL_AMOEBING;
2108       Store[x][y] = EL_AMOEBE_NASS;
2109     }
2110     else if (IS_SLIPPERY(Feld[x][y+1]) && !Store[x][y+1])
2111     {
2112       boolean left  = (x>0 && IS_FREE(x-1, y) &&
2113                        (IS_FREE(x-1, y+1) || Feld[x-1][y+1] == EL_SALZSAEURE));
2114       boolean right = (x<lev_fieldx-1 && IS_FREE(x+1, y) &&
2115                        (IS_FREE(x+1, y+1) || Feld[x+1][y+1] == EL_SALZSAEURE));
2116
2117       if (left || right)
2118       {
2119         if (left && right && game.emulation != EMU_BOULDERDASH)
2120           left = !(right = RND(2));
2121
2122         InitMovingField(x, y, left ? MV_LEFT : MV_RIGHT);
2123       }
2124     }
2125   }
2126   else if (CAN_MOVE(element))
2127   {
2128     int newx, newy;
2129
2130     if (element == EL_SONDE && JustBeingPushed(x, y))
2131       return;
2132
2133     if (!MovDelay[x][y])        /* start new movement phase */
2134     {
2135       /* all objects that can change their move direction after each step */
2136       /* (MAMPFER, MAMPFER2 and PACMAN go straight until they hit a wall  */
2137
2138       if (element!=EL_MAMPFER && element!=EL_MAMPFER2 && element!=EL_PACMAN)
2139       {
2140         TurnRound(x, y);
2141         if (MovDelay[x][y] && (element == EL_KAEFER || element == EL_FLIEGER ||
2142                                element == EL_SP_SNIKSNAK ||
2143                                element == EL_SP_ELECTRON))
2144           DrawLevelField(x, y);
2145       }
2146     }
2147
2148     if (MovDelay[x][y])         /* wait some time before next movement */
2149     {
2150       MovDelay[x][y]--;
2151
2152       if (element == EL_ROBOT ||
2153           element == EL_MAMPFER || element == EL_MAMPFER2)
2154       {
2155         int phase = MovDelay[x][y] % 8;
2156
2157         if (phase>3)
2158           phase = 7-phase;
2159
2160         if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
2161           DrawGraphic(SCREENX(x), SCREENY(y), el2gfx(element)+phase);
2162
2163         if ((element == EL_MAMPFER || element == EL_MAMPFER2)
2164             && MovDelay[x][y]%4 == 3)
2165           PlaySoundLevel(x, y, SND_NJAM);
2166       }
2167       else if (element == EL_SP_ELECTRON)
2168         DrawGraphicAnimation(x, y, GFX2_SP_ELECTRON, 8, 2, ANIM_NORMAL);
2169       else if (element == EL_DRACHE)
2170       {
2171         int i;
2172         int dir = MovDir[x][y];
2173         int dx = (dir == MV_LEFT ? -1 : dir == MV_RIGHT ? +1 : 0);
2174         int dy = (dir == MV_UP   ? -1 : dir == MV_DOWN  ? +1 : 0);
2175         int graphic = (dir == MV_LEFT   ? GFX_FLAMMEN_LEFT :
2176                        dir == MV_RIGHT  ? GFX_FLAMMEN_RIGHT :
2177                        dir == MV_UP     ? GFX_FLAMMEN_UP :
2178                        dir == MV_DOWN   ? GFX_FLAMMEN_DOWN : GFX_LEERRAUM);
2179         int phase = FrameCounter % 2;
2180
2181         for (i=1; i<=3; i++)
2182         {
2183           int xx = x + i*dx, yy = y + i*dy;
2184           int sx = SCREENX(xx), sy = SCREENY(yy);
2185
2186           if (!IN_LEV_FIELD(xx, yy) ||
2187               IS_SOLID(Feld[xx][yy]) || Feld[xx][yy] == EL_EXPLODING)
2188             break;
2189
2190           if (MovDelay[x][y])
2191           {
2192             int flamed = MovingOrBlocked2Element(xx, yy);
2193
2194             if (IS_ENEMY(flamed) || IS_EXPLOSIVE(flamed))
2195               Bang(xx, yy);
2196             else
2197               RemoveMovingField(xx, yy);
2198
2199             Feld[xx][yy] = EL_BURNING;
2200             if (IN_SCR_FIELD(sx, sy))
2201               DrawGraphic(sx, sy, graphic + phase*3 + i-1);
2202           }
2203           else
2204           {
2205             if (Feld[xx][yy] == EL_BURNING)
2206               Feld[xx][yy] = EL_LEERRAUM;
2207             DrawLevelField(xx, yy);
2208           }
2209         }
2210       }
2211
2212       if (MovDelay[x][y])
2213         return;
2214     }
2215
2216     if (element == EL_KAEFER || element == EL_BUTTERFLY)
2217     {
2218       PlaySoundLevel(x, y, SND_KLAPPER);
2219     }
2220     else if (element == EL_FLIEGER || element == EL_FIREFLY)
2221     {
2222       PlaySoundLevel(x, y, SND_ROEHR);
2223     }
2224
2225     /* now make next step */
2226
2227     Moving2Blocked(x, y, &newx, &newy); /* get next screen position */
2228
2229     if (IS_ENEMY(element) && IS_PLAYER(newx, newy))
2230     {
2231       /* enemy got the player */
2232       MovDir[x][y] = 0;
2233       KillHero(PLAYERINFO(newx, newy));
2234       return;
2235     }
2236     else if ((element == EL_MAULWURF || element == EL_PINGUIN ||
2237               element == EL_ROBOT || element == EL_SONDE) &&
2238              IN_LEV_FIELD(newx, newy) &&
2239              MovDir[x][y] == MV_DOWN && Feld[newx][newy] == EL_SALZSAEURE)
2240     {
2241       Blurb(x, y);
2242       Store[x][y] = EL_SALZSAEURE;
2243     }
2244     else if ((element == EL_MAULWURF || element == EL_PINGUIN) &&
2245              IN_LEV_FIELD(newx, newy))
2246     {
2247       if (Feld[newx][newy] == EL_AUSGANG_AUF)
2248       {
2249         Feld[x][y] = EL_LEERRAUM;
2250         DrawLevelField(x, y);
2251
2252         PlaySoundLevel(newx, newy, SND_BUING);
2253         if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
2254           DrawGraphicThruMask(SCREENX(newx), SCREENY(newy), el2gfx(element));
2255
2256         local_player->friends_still_needed--;
2257         if (!local_player->friends_still_needed &&
2258             !local_player->GameOver && AllPlayersGone)
2259           local_player->LevelSolved = local_player->GameOver = TRUE;
2260
2261         return;
2262       }
2263       else if (IS_MAMPF3(Feld[newx][newy]))
2264       {
2265         if (DigField(local_player, newx, newy, 0, 0, DF_DIG) == MF_MOVING)
2266           DrawLevelField(newx, newy);
2267         else
2268           MovDir[x][y] = MV_NO_MOVING;
2269       }
2270       else if (!IS_FREE(newx, newy))
2271       {
2272         if (IS_PLAYER(x, y))
2273           DrawPlayerField(x, y);
2274         else
2275           DrawLevelField(x, y);
2276         return;
2277       }
2278     }
2279     else if (element == EL_SCHWEIN && IN_LEV_FIELD(newx, newy))
2280     {
2281       if (IS_GEM(Feld[newx][newy]))
2282       {
2283         if (IS_MOVING(newx, newy))
2284           RemoveMovingField(newx, newy);
2285         else
2286         {
2287           Feld[newx][newy] = EL_LEERRAUM;
2288           DrawLevelField(newx, newy);
2289         }
2290       }
2291       else if (!IS_FREE(newx, newy))
2292       {
2293         if (IS_PLAYER(x, y))
2294           DrawPlayerField(x, y);
2295         else
2296           DrawLevelField(x, y);
2297         return;
2298       }
2299     }
2300     else if (element == EL_DRACHE && IN_LEV_FIELD(newx, newy))
2301     {
2302       if (!IS_FREE(newx, newy))
2303       {
2304         if (IS_PLAYER(x, y))
2305           DrawPlayerField(x, y);
2306         else
2307           DrawLevelField(x, y);
2308         return;
2309       }
2310       else
2311       {
2312         boolean wanna_flame = !RND(10);
2313         int dx = newx - x, dy = newy - y;
2314         int newx1 = newx+1*dx, newy1 = newy+1*dy;
2315         int newx2 = newx+2*dx, newy2 = newy+2*dy;
2316         int element1 = (IN_LEV_FIELD(newx1, newy1) ?
2317                         MovingOrBlocked2Element(newx1, newy1) : EL_BETON);
2318         int element2 = (IN_LEV_FIELD(newx2, newy2) ?
2319                         MovingOrBlocked2Element(newx2, newy2) : EL_BETON);
2320
2321         if ((wanna_flame || IS_ENEMY(element1) || IS_ENEMY(element2)) &&
2322             element1 != EL_DRACHE && element2 != EL_DRACHE &&
2323             element1 != EL_BURNING && element2 != EL_BURNING)
2324         {
2325           if (IS_PLAYER(x, y))
2326             DrawPlayerField(x, y);
2327           else
2328             DrawLevelField(x, y);
2329
2330           MovDelay[x][y] = 50;
2331           Feld[newx][newy] = EL_BURNING;
2332           if (IN_LEV_FIELD(newx1, newy1) && Feld[newx1][newy1] == EL_LEERRAUM)
2333             Feld[newx1][newy1] = EL_BURNING;
2334           if (IN_LEV_FIELD(newx2, newy2) && Feld[newx2][newy2] == EL_LEERRAUM)
2335             Feld[newx2][newy2] = EL_BURNING;
2336           return;
2337         }
2338       }
2339     }
2340     else if (element == EL_MAMPFER && IN_LEV_FIELD(newx, newy) &&
2341              Feld[newx][newy] == EL_DIAMANT)
2342     {
2343       if (IS_MOVING(newx, newy))
2344         RemoveMovingField(newx, newy);
2345       else
2346       {
2347         Feld[newx][newy] = EL_LEERRAUM;
2348         DrawLevelField(newx, newy);
2349       }
2350     }
2351     else if (element == EL_MAMPFER2 && IN_LEV_FIELD(newx, newy) &&
2352              IS_MAMPF2(Feld[newx][newy]))
2353     {
2354       if (AmoebaNr[newx][newy])
2355       {
2356         AmoebaCnt2[AmoebaNr[newx][newy]]--;
2357         if (Feld[newx][newy] == EL_AMOEBE_VOLL ||
2358             Feld[newx][newy] == EL_AMOEBE_BD)
2359           AmoebaCnt[AmoebaNr[newx][newy]]--;
2360       }
2361
2362       if (IS_MOVING(newx, newy))
2363         RemoveMovingField(newx, newy);
2364       else
2365       {
2366         Feld[newx][newy] = EL_LEERRAUM;
2367         DrawLevelField(newx, newy);
2368       }
2369     }
2370     else if (element == EL_PACMAN && IN_LEV_FIELD(newx, newy) &&
2371              IS_AMOEBOID(Feld[newx][newy]))
2372     {
2373       if (AmoebaNr[newx][newy])
2374       {
2375         AmoebaCnt2[AmoebaNr[newx][newy]]--;
2376         if (Feld[newx][newy] == EL_AMOEBE_VOLL ||
2377             Feld[newx][newy] == EL_AMOEBE_BD)
2378           AmoebaCnt[AmoebaNr[newx][newy]]--;
2379       }
2380
2381       Feld[newx][newy] = EL_LEERRAUM;
2382       DrawLevelField(newx, newy);
2383     }
2384     else if (!IN_LEV_FIELD(newx, newy) || !IS_FREE(newx, newy))
2385     {
2386       /* object was running against a wall */
2387
2388       TurnRound(x, y);
2389
2390       if (element == EL_KAEFER || element == EL_FLIEGER ||
2391           element == EL_SP_SNIKSNAK)
2392         DrawLevelField(x, y);
2393       else if (element == EL_BUTTERFLY || element == EL_FIREFLY)
2394         DrawGraphicAnimation(x, y, el2gfx(element), 2, 4, ANIM_NORMAL);
2395       else if (element == EL_SONDE)
2396         DrawGraphicAnimation(x, y, GFX_SONDE_START, 8, 2, ANIM_NORMAL);
2397       else if (element == EL_SP_ELECTRON)
2398         DrawGraphicAnimation(x, y, GFX2_SP_ELECTRON, 8, 2, ANIM_NORMAL);
2399
2400       return;
2401     }
2402
2403     if (element == EL_ROBOT && IN_SCR_FIELD(x, y))
2404       PlaySoundLevel(x, y, SND_SCHLURF);
2405
2406     InitMovingField(x, y, MovDir[x][y]);
2407   }
2408
2409   if (MovDir[x][y])
2410     ContinueMoving(x, y);
2411 }
2412
2413 void ContinueMoving(int x, int y)
2414 {
2415   int element = Feld[x][y];
2416   int direction = MovDir[x][y];
2417   int dx = (direction == MV_LEFT ? -1 : direction == MV_RIGHT ? +1 : 0);
2418   int dy = (direction == MV_UP   ? -1 : direction == MV_DOWN  ? +1 : 0);
2419   int horiz_move = (dx!=0);
2420   int newx = x + dx, newy = y + dy;
2421   int step = (horiz_move ? dx : dy) * TILEX/8;
2422
2423   if (CAN_FALL(element) && horiz_move && !IS_SP_ELEMENT(element))
2424     step*=2;
2425   else if (element == EL_TROPFEN)
2426     step/=2;
2427   else if (Store[x][y] == EL_MORAST_VOLL || Store[x][y] == EL_MORAST_LEER)
2428     step/=4;
2429
2430   MovPos[x][y] += step;
2431
2432   if (ABS(MovPos[x][y])>=TILEX)         /* object reached its destination */
2433   {
2434     Feld[x][y] = EL_LEERRAUM;
2435     Feld[newx][newy] = element;
2436
2437     if (Store[x][y] == EL_MORAST_VOLL)
2438     {
2439       Store[x][y] = 0;
2440       Feld[newx][newy] = EL_MORAST_VOLL;
2441       element = EL_MORAST_VOLL;
2442     }
2443     else if (Store[x][y] == EL_MORAST_LEER)
2444     {
2445       Store[x][y] = 0;
2446       Feld[x][y] = EL_MORAST_LEER;
2447     }
2448     else if (Store[x][y] == EL_SIEB_VOLL)
2449     {
2450       Store[x][y] = 0;
2451       element = Feld[newx][newy] =
2452         (game.magic_wall_active ? EL_SIEB_VOLL : EL_SIEB_TOT);
2453     }
2454     else if (Store[x][y] == EL_SIEB_LEER)
2455     {
2456       Store[x][y] = Store2[x][y] = 0;
2457       Feld[x][y] = (game.magic_wall_active ? EL_SIEB_LEER : EL_SIEB_TOT);
2458     }
2459     else if (Store[x][y] == EL_SIEB2_VOLL)
2460     {
2461       Store[x][y] = 0;
2462       element = Feld[newx][newy] =
2463         (game.magic_wall_active ? EL_SIEB2_VOLL : EL_SIEB2_TOT);
2464     }
2465     else if (Store[x][y] == EL_SIEB2_LEER)
2466     {
2467       Store[x][y] = Store2[x][y] = 0;
2468       Feld[x][y] = (game.magic_wall_active ? EL_SIEB2_LEER : EL_SIEB2_TOT);
2469     }
2470     else if (Store[x][y] == EL_SALZSAEURE)
2471     {
2472       Store[x][y] = 0;
2473       Feld[newx][newy] = EL_SALZSAEURE;
2474       element = EL_SALZSAEURE;
2475     }
2476     else if (Store[x][y] == EL_AMOEBE_NASS)
2477     {
2478       Store[x][y] = 0;
2479       Feld[x][y] = EL_AMOEBE_NASS;
2480     }
2481
2482     MovPos[x][y] = MovDir[x][y] = MovDelay[x][y] = 0;
2483     MovDelay[newx][newy] = 0;
2484
2485     if (!CAN_MOVE(element))
2486       MovDir[newx][newy] = 0;
2487
2488     DrawLevelField(x, y);
2489     DrawLevelField(newx, newy);
2490
2491     Stop[newx][newy] = TRUE;
2492     JustHit[x][newy] = 3;
2493
2494     if (DONT_TOUCH(element))    /* object may be nasty to player or others */
2495     {
2496       TestIfBadThingHitsHero(newx, newy);
2497       TestIfBadThingHitsFriend(newx, newy);
2498       TestIfBadThingHitsOtherBadThing(newx, newy);
2499     }
2500     else if (element == EL_PINGUIN)
2501       TestIfFriendHitsBadThing(newx, newy);
2502
2503     if (CAN_SMASH(element) && direction == MV_DOWN &&
2504         (newy == lev_fieldy-1 || !IS_FREE(x, newy+1)))
2505       Impact(x, newy);
2506   }
2507   else                          /* still moving on */
2508     DrawLevelField(x, y);
2509 }
2510
2511 int AmoebeNachbarNr(int ax, int ay)
2512 {
2513   int i;
2514   int element = Feld[ax][ay];
2515   int group_nr = 0;
2516   static int xy[4][2] =
2517   {
2518     { 0, -1 },
2519     { -1, 0 },
2520     { +1, 0 },
2521     { 0, +1 }
2522   };
2523
2524   for (i=0; i<4; i++)
2525   {
2526     int x = ax + xy[i][0];
2527     int y = ay + xy[i][1];
2528
2529     if (!IN_LEV_FIELD(x, y))
2530       continue;
2531
2532     if (Feld[x][y] == element && AmoebaNr[x][y] > 0)
2533       group_nr = AmoebaNr[x][y];
2534   }
2535
2536   return group_nr;
2537 }
2538
2539 void AmoebenVereinigen(int ax, int ay)
2540 {
2541   int i, x, y, xx, yy;
2542   int new_group_nr = AmoebaNr[ax][ay];
2543   static int xy[4][2] =
2544   {
2545     { 0, -1 },
2546     { -1, 0 },
2547     { +1, 0 },
2548     { 0, +1 }
2549   };
2550
2551   if (new_group_nr == 0)
2552     return;
2553
2554   for (i=0; i<4; i++)
2555   {
2556     x = ax + xy[i][0];
2557     y = ay + xy[i][1];
2558
2559     if (!IN_LEV_FIELD(x, y))
2560       continue;
2561
2562     if ((Feld[x][y] == EL_AMOEBE_VOLL ||
2563          Feld[x][y] == EL_AMOEBE_BD ||
2564          Feld[x][y] == EL_AMOEBE_TOT) &&
2565         AmoebaNr[x][y] != new_group_nr)
2566     {
2567       int old_group_nr = AmoebaNr[x][y];
2568
2569       if (old_group_nr == 0)
2570         return;
2571
2572       AmoebaCnt[new_group_nr] += AmoebaCnt[old_group_nr];
2573       AmoebaCnt[old_group_nr] = 0;
2574       AmoebaCnt2[new_group_nr] += AmoebaCnt2[old_group_nr];
2575       AmoebaCnt2[old_group_nr] = 0;
2576
2577       for (yy=0; yy<lev_fieldy; yy++)
2578       {
2579         for (xx=0; xx<lev_fieldx; xx++)
2580         {
2581           if (AmoebaNr[xx][yy] == old_group_nr)
2582             AmoebaNr[xx][yy] = new_group_nr;
2583         }
2584       }
2585     }
2586   }
2587 }
2588
2589 void AmoebeUmwandeln(int ax, int ay)
2590 {
2591   int i, x, y;
2592
2593   if (Feld[ax][ay] == EL_AMOEBE_TOT)
2594   {
2595     int group_nr = AmoebaNr[ax][ay];
2596
2597 #ifdef DEBUG
2598     if (group_nr == 0)
2599     {
2600       printf("AmoebeUmwandeln(): ax = %d, ay = %d\n", ax, ay);
2601       printf("AmoebeUmwandeln(): This should never happen!\n");
2602       return;
2603     }
2604 #endif
2605
2606     for (y=0; y<lev_fieldy; y++)
2607     {
2608       for (x=0; x<lev_fieldx; x++)
2609       {
2610         if (Feld[x][y] == EL_AMOEBE_TOT && AmoebaNr[x][y] == group_nr)
2611         {
2612           AmoebaNr[x][y] = 0;
2613           Feld[x][y] = EL_AMOEBA2DIAM;
2614         }
2615       }
2616     }
2617     Bang(ax, ay);
2618   }
2619   else
2620   {
2621     static int xy[4][2] =
2622     {
2623       { 0, -1 },
2624       { -1, 0 },
2625       { +1, 0 },
2626       { 0, +1 }
2627     };
2628
2629     for (i=0; i<4; i++)
2630     {
2631       x = ax + xy[i][0];
2632       y = ay + xy[i][1];
2633
2634       if (!IN_LEV_FIELD(x, y))
2635         continue;
2636
2637       if (Feld[x][y] == EL_AMOEBA2DIAM)
2638         Bang(x, y);
2639     }
2640   }
2641 }
2642
2643 void AmoebeUmwandelnBD(int ax, int ay, int new_element)
2644 {
2645   int x, y;
2646   int group_nr = AmoebaNr[ax][ay];
2647   boolean done = FALSE;
2648
2649 #ifdef DEBUG
2650   if (group_nr == 0)
2651   {
2652     printf("AmoebeUmwandelnBD(): ax = %d, ay = %d\n", ax, ay);
2653     printf("AmoebeUmwandelnBD(): This should never happen!\n");
2654     return;
2655   }
2656 #endif
2657
2658   for (y=0; y<lev_fieldy; y++)
2659   {
2660     for (x=0; x<lev_fieldx; x++)
2661     {
2662       if (AmoebaNr[x][y] == group_nr &&
2663           (Feld[x][y] == EL_AMOEBE_TOT ||
2664            Feld[x][y] == EL_AMOEBE_BD ||
2665            Feld[x][y] == EL_AMOEBING))
2666       {
2667         AmoebaNr[x][y] = 0;
2668         Feld[x][y] = new_element;
2669         InitField(x, y, FALSE);
2670         DrawLevelField(x, y);
2671         done = TRUE;
2672       }
2673     }
2674   }
2675
2676   if (done)
2677     PlaySoundLevel(ax, ay,
2678                    (new_element == EL_FELSBROCKEN ? SND_KLOPF : SND_PLING));
2679 }
2680
2681 void AmoebeWaechst(int x, int y)
2682 {
2683   static unsigned long sound_delay = 0;
2684   static unsigned long sound_delay_value = 0;
2685
2686   if (!MovDelay[x][y])          /* start new growing cycle */
2687   {
2688     MovDelay[x][y] = 7;
2689
2690     if (DelayReached(&sound_delay, sound_delay_value))
2691     {
2692       PlaySoundLevel(x, y, SND_AMOEBE);
2693       sound_delay_value = 30;
2694     }
2695   }
2696
2697   if (MovDelay[x][y])           /* wait some time before growing bigger */
2698   {
2699     MovDelay[x][y]--;
2700     if (MovDelay[x][y]/2 && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
2701       DrawGraphic(SCREENX(x), SCREENY(y), GFX_AMOEBING + 3 - MovDelay[x][y]/2);
2702
2703     if (!MovDelay[x][y])
2704     {
2705       Feld[x][y] = Store[x][y];
2706       Store[x][y] = 0;
2707       DrawLevelField(x, y);
2708     }
2709   }
2710 }
2711
2712 void AmoebeAbleger(int ax, int ay)
2713 {
2714   int i;
2715   int element = Feld[ax][ay];
2716   int newax = ax, neway = ay;
2717   static int xy[4][2] =
2718   {
2719     { 0, -1 },
2720     { -1, 0 },
2721     { +1, 0 },
2722     { 0, +1 }
2723   };
2724
2725   if (!level.amoeba_speed)
2726   {
2727     Feld[ax][ay] = EL_AMOEBE_TOT;
2728     DrawLevelField(ax, ay);
2729     return;
2730   }
2731
2732   if (!MovDelay[ax][ay])        /* start making new amoeba field */
2733     MovDelay[ax][ay] = RND(FRAMES_PER_SECOND * 25 / (1 + level.amoeba_speed));
2734
2735   if (MovDelay[ax][ay])         /* wait some time before making new amoeba */
2736   {
2737     MovDelay[ax][ay]--;
2738     if (MovDelay[ax][ay])
2739       return;
2740   }
2741
2742   if (element == EL_AMOEBE_NASS)        /* object is an acid / amoeba drop */
2743   {
2744     int start = RND(4);
2745     int x = ax + xy[start][0];
2746     int y = ay + xy[start][1];
2747
2748     if (!IN_LEV_FIELD(x, y))
2749       return;
2750
2751     if (IS_FREE(x, y) ||
2752         Feld[x][y] == EL_ERDREICH || Feld[x][y] == EL_MORAST_LEER)
2753     {
2754       newax = x;
2755       neway = y;
2756     }
2757
2758     if (newax == ax && neway == ay)
2759       return;
2760   }
2761   else                          /* normal or "filled" (BD style) amoeba */
2762   {
2763     int start = RND(4);
2764     boolean waiting_for_player = FALSE;
2765
2766     for (i=0; i<4; i++)
2767     {
2768       int j = (start + i) % 4;
2769       int x = ax + xy[j][0];
2770       int y = ay + xy[j][1];
2771
2772       if (!IN_LEV_FIELD(x, y))
2773         continue;
2774
2775       if (IS_FREE(x, y) ||
2776           Feld[x][y] == EL_ERDREICH || Feld[x][y] == EL_MORAST_LEER)
2777       {
2778         newax = x;
2779         neway = y;
2780         break;
2781       }
2782       else if (IS_PLAYER(x, y))
2783         waiting_for_player = TRUE;
2784     }
2785
2786     if (newax == ax && neway == ay)             /* amoeba cannot grow */
2787     {
2788       if (i == 4 && (!waiting_for_player || game.emulation == EMU_BOULDERDASH))
2789       {
2790         Feld[ax][ay] = EL_AMOEBE_TOT;
2791         DrawLevelField(ax, ay);
2792         AmoebaCnt[AmoebaNr[ax][ay]]--;
2793
2794         if (AmoebaCnt[AmoebaNr[ax][ay]] <= 0)   /* amoeba is completely dead */
2795         {
2796           if (element == EL_AMOEBE_VOLL)
2797             AmoebeUmwandeln(ax, ay);
2798           else if (element == EL_AMOEBE_BD)
2799             AmoebeUmwandelnBD(ax, ay, level.amoeba_content);
2800         }
2801       }
2802       return;
2803     }
2804     else if (element == EL_AMOEBE_VOLL || element == EL_AMOEBE_BD)
2805     {
2806       /* amoeba gets larger by growing in some direction */
2807
2808       int new_group_nr = AmoebaNr[ax][ay];
2809
2810 #ifdef DEBUG
2811   if (new_group_nr == 0)
2812   {
2813     printf("AmoebeAbleger(): newax = %d, neway = %d\n", newax, neway);
2814     printf("AmoebeAbleger(): This should never happen!\n");
2815     return;
2816   }
2817 #endif
2818
2819       AmoebaNr[newax][neway] = new_group_nr;
2820       AmoebaCnt[new_group_nr]++;
2821       AmoebaCnt2[new_group_nr]++;
2822
2823       /* if amoeba touches other amoeba(s) after growing, unify them */
2824       AmoebenVereinigen(newax, neway);
2825
2826       if (element == EL_AMOEBE_BD && AmoebaCnt2[new_group_nr] >= 200)
2827       {
2828         AmoebeUmwandelnBD(newax, neway, EL_FELSBROCKEN);
2829         return;
2830       }
2831     }
2832   }
2833
2834   if (element != EL_AMOEBE_NASS || neway < ay || !IS_FREE(newax, neway) ||
2835       (neway == lev_fieldy - 1 && newax != ax))
2836   {
2837     Feld[newax][neway] = EL_AMOEBING;
2838     Store[newax][neway] = element;
2839   }
2840   else if (neway == ay)
2841     Feld[newax][neway] = EL_TROPFEN;
2842   else
2843   {
2844     InitMovingField(ax, ay, MV_DOWN);
2845     Feld[ax][ay] = EL_TROPFEN;
2846     Store[ax][ay] = EL_AMOEBE_NASS;
2847     ContinueMoving(ax, ay);
2848     return;
2849   }
2850
2851   DrawLevelField(newax, neway);
2852 }
2853
2854 void Life(int ax, int ay)
2855 {
2856   int x1, y1, x2, y2;
2857   static int life[4] = { 2, 3, 3, 3 };  /* parameters for "game of life" */
2858   int life_time = 40;
2859   int element = Feld[ax][ay];
2860
2861   if (Stop[ax][ay])
2862     return;
2863
2864   if (!MovDelay[ax][ay])        /* start new "game of life" cycle */
2865     MovDelay[ax][ay] = life_time;
2866
2867   if (MovDelay[ax][ay])         /* wait some time before next cycle */
2868   {
2869     MovDelay[ax][ay]--;
2870     if (MovDelay[ax][ay])
2871       return;
2872   }
2873
2874   for (y1=-1; y1<2; y1++) for(x1=-1; x1<2; x1++)
2875   {
2876     int xx = ax+x1, yy = ay+y1;
2877     int nachbarn = 0;
2878
2879     if (!IN_LEV_FIELD(xx, yy))
2880       continue;
2881
2882     for (y2=-1; y2<2; y2++) for (x2=-1; x2<2; x2++)
2883     {
2884       int x = xx+x2, y = yy+y2;
2885
2886       if (!IN_LEV_FIELD(x, y) || (x == xx && y == yy))
2887         continue;
2888
2889       if (((Feld[x][y] == element ||
2890             (element == EL_LIFE && IS_PLAYER(x, y))) &&
2891            !Stop[x][y]) ||
2892           (IS_FREE(x, y) && Stop[x][y]))
2893         nachbarn++;
2894     }
2895
2896     if (xx == ax && yy == ay)           /* field in the middle */
2897     {
2898       if (nachbarn<life[0] || nachbarn>life[1])
2899       {
2900         Feld[xx][yy] = EL_LEERRAUM;
2901         if (!Stop[xx][yy])
2902           DrawLevelField(xx, yy);
2903         Stop[xx][yy] = TRUE;
2904       }
2905     }
2906     else if (IS_FREE(xx, yy) || Feld[xx][yy] == EL_ERDREICH)
2907     {                                   /* free border field */
2908       if (nachbarn>=life[2] && nachbarn<=life[3])
2909       {
2910         Feld[xx][yy] = element;
2911         MovDelay[xx][yy] = (element == EL_LIFE ? 0 : life_time-1);
2912         if (!Stop[xx][yy])
2913           DrawLevelField(xx, yy);
2914         Stop[xx][yy] = TRUE;
2915       }
2916     }
2917   }
2918 }
2919
2920 void Ablenk(int x, int y)
2921 {
2922   if (!MovDelay[x][y])          /* next animation frame */
2923     MovDelay[x][y] = level.time_wheel * FRAMES_PER_SECOND;
2924
2925   if (MovDelay[x][y])           /* wait some time before next frame */
2926   {
2927     MovDelay[x][y]--;
2928     if (MovDelay[x][y])
2929     {
2930       if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
2931         DrawGraphic(SCREENX(x), SCREENY(y), GFX_ABLENK+MovDelay[x][y]%4);
2932       if (!(MovDelay[x][y]%4))
2933         PlaySoundLevel(x, y, SND_MIEP);
2934       return;
2935     }
2936   }
2937
2938   Feld[x][y] = EL_ABLENK_AUS;
2939   DrawLevelField(x, y);
2940   if (ZX == x && ZY == y)
2941     ZX = ZY = -1;
2942 }
2943
2944 void Birne(int x, int y)
2945 {
2946   if (!MovDelay[x][y])          /* next animation frame */
2947     MovDelay[x][y] = 800;
2948
2949   if (MovDelay[x][y])           /* wait some time before next frame */
2950   {
2951     MovDelay[x][y]--;
2952     if (MovDelay[x][y])
2953     {
2954       if (!(MovDelay[x][y]%5))
2955       {
2956         if (!(MovDelay[x][y]%10))
2957           Feld[x][y]=EL_ABLENK_EIN;
2958         else
2959           Feld[x][y]=EL_ABLENK_AUS;
2960         DrawLevelField(x, y);
2961         Feld[x][y]=EL_ABLENK_EIN;
2962       }
2963       return;
2964     }
2965   }
2966
2967   Feld[x][y]=EL_ABLENK_AUS;
2968   DrawLevelField(x, y);
2969   if (ZX == x && ZY == y)
2970     ZX=ZY=-1;
2971 }
2972
2973 void Blubber(int x, int y)
2974 {
2975   if (y > 0 && IS_MOVING(x, y-1) && MovDir[x][y-1] == MV_DOWN)
2976     DrawLevelField(x, y-1);
2977   else
2978     DrawGraphicAnimation(x, y, GFX_GEBLUBBER, 4, 10, ANIM_NORMAL);
2979 }
2980
2981 void NussKnacken(int x, int y)
2982 {
2983   if (!MovDelay[x][y])          /* next animation frame */
2984     MovDelay[x][y] = 7;
2985
2986   if (MovDelay[x][y])           /* wait some time before next frame */
2987   {
2988     MovDelay[x][y]--;
2989     if (MovDelay[x][y]/2 && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
2990       DrawGraphic(SCREENX(x), SCREENY(y), GFX_CRACKINGNUT+3-MovDelay[x][y]/2);
2991
2992     if (!MovDelay[x][y])
2993     {
2994       Feld[x][y] = EL_EDELSTEIN;
2995       DrawLevelField(x, y);
2996     }
2997   }
2998 }
2999
3000 void SiebAktivieren(int x, int y, int typ)
3001 {
3002   int graphic = (typ == 1 ? GFX_SIEB_VOLL : GFX_SIEB2_VOLL) + 3;
3003
3004   DrawGraphicAnimation(x, y, graphic, 4, 4, ANIM_REVERSE);
3005 }
3006
3007 void AusgangstuerPruefen(int x, int y)
3008 {
3009   if (!local_player->gems_still_needed &&
3010       !local_player->sokobanfields_still_needed &&
3011       !local_player->lights_still_needed)
3012   {
3013     Feld[x][y] = EL_AUSGANG_ACT;
3014
3015     PlaySoundLevel(x < LEVELX(BX1) ? LEVELX(BX1) :
3016                    (x > LEVELX(BX2) ? LEVELX(BX2) : x),
3017                    y < LEVELY(BY1) ? LEVELY(BY1) :
3018                    (y > LEVELY(BY2) ? LEVELY(BY2) : y),
3019                    SND_OEFFNEN);
3020   }
3021 }
3022
3023 void AusgangstuerOeffnen(int x, int y)
3024 {
3025   int delay = 6;
3026
3027   if (!MovDelay[x][y])          /* next animation frame */
3028     MovDelay[x][y] = 5*delay;
3029
3030   if (MovDelay[x][y])           /* wait some time before next frame */
3031   {
3032     int tuer;
3033
3034     MovDelay[x][y]--;
3035     tuer = MovDelay[x][y]/delay;
3036     if (!(MovDelay[x][y]%delay) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
3037       DrawGraphic(SCREENX(x), SCREENY(y), GFX_AUSGANG_AUF-tuer);
3038
3039     if (!MovDelay[x][y])
3040     {
3041       Feld[x][y] = EL_AUSGANG_AUF;
3042       DrawLevelField(x, y);
3043     }
3044   }
3045 }
3046
3047 void AusgangstuerBlinken(int x, int y)
3048 {
3049   DrawGraphicAnimation(x, y, GFX_AUSGANG_AUF, 4, 4, ANIM_OSCILLATE);
3050 }
3051
3052 void EdelsteinFunkeln(int x, int y)
3053 {
3054   if (!IN_SCR_FIELD(SCREENX(x), SCREENY(y)) || IS_MOVING(x, y))
3055     return;
3056
3057   if (Feld[x][y] == EL_EDELSTEIN_BD)
3058     DrawGraphicAnimation(x, y, GFX_EDELSTEIN_BD, 4, 4, ANIM_REVERSE);
3059   else
3060   {
3061     if (!MovDelay[x][y])        /* next animation frame */
3062       MovDelay[x][y] = 11 * !SimpleRND(500);
3063
3064     if (MovDelay[x][y])         /* wait some time before next frame */
3065     {
3066       MovDelay[x][y]--;
3067
3068       if (setup.direct_draw && MovDelay[x][y])
3069         SetDrawtoField(DRAW_BUFFERED);
3070
3071       DrawGraphic(SCREENX(x), SCREENY(y), el2gfx(Feld[x][y]));
3072
3073       if (MovDelay[x][y])
3074       {
3075         int phase = (MovDelay[x][y]-1)/2;
3076
3077         if (phase > 2)
3078           phase = 4-phase;
3079
3080         DrawGraphicThruMask(SCREENX(x), SCREENY(y), GFX_FUNKELN_WEISS + phase);
3081
3082         if (setup.direct_draw)
3083         {
3084           int dest_x, dest_y;
3085
3086           dest_x = FX + SCREENX(x)*TILEX;
3087           dest_y = FY + SCREENY(y)*TILEY;
3088
3089           XCopyArea(display, drawto_field, window, gc,
3090                     dest_x, dest_y, TILEX, TILEY, dest_x, dest_y);
3091           SetDrawtoField(DRAW_DIRECT);
3092         }
3093       }
3094     }
3095   }
3096 }
3097
3098 void MauerWaechst(int x, int y)
3099 {
3100   int delay = 6;
3101
3102   if (!MovDelay[x][y])          /* next animation frame */
3103     MovDelay[x][y] = 3*delay;
3104
3105   if (MovDelay[x][y])           /* wait some time before next frame */
3106   {
3107     int phase;
3108
3109     MovDelay[x][y]--;
3110     phase = 2-MovDelay[x][y]/delay;
3111     if (!(MovDelay[x][y]%delay) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
3112       DrawGraphic(SCREENX(x), SCREENY(y),
3113                   (MovDir[x][y] == MV_LEFT  ? GFX_MAUER_LEFT  :
3114                    MovDir[x][y] == MV_RIGHT ? GFX_MAUER_RIGHT :
3115                    MovDir[x][y] == MV_UP    ? GFX_MAUER_UP    :
3116                                               GFX_MAUER_DOWN  ) + phase);
3117
3118     if (!MovDelay[x][y])
3119     {
3120       if (MovDir[x][y] == MV_LEFT)
3121       {
3122         if (IN_LEV_FIELD(x-1, y) && IS_MAUER(Feld[x-1][y]))
3123           DrawLevelField(x-1, y);
3124       }
3125       else if (MovDir[x][y] == MV_RIGHT)
3126       {
3127         if (IN_LEV_FIELD(x+1, y) && IS_MAUER(Feld[x+1][y]))
3128           DrawLevelField(x+1, y);
3129       }
3130       else if (MovDir[x][y] == MV_UP)
3131       {
3132         if (IN_LEV_FIELD(x, y-1) && IS_MAUER(Feld[x][y-1]))
3133           DrawLevelField(x, y-1);
3134       }
3135       else
3136       {
3137         if (IN_LEV_FIELD(x, y+1) && IS_MAUER(Feld[x][y+1]))
3138           DrawLevelField(x, y+1);
3139       }
3140
3141       Feld[x][y] = Store[x][y];
3142       Store[x][y] = 0;
3143       MovDir[x][y] = MV_NO_MOVING;
3144       DrawLevelField(x, y);
3145     }
3146   }
3147 }
3148
3149 void MauerAbleger(int ax, int ay)
3150 {
3151   int element = Feld[ax][ay];
3152   boolean oben_frei = FALSE, unten_frei = FALSE;
3153   boolean links_frei = FALSE, rechts_frei = FALSE;
3154   boolean oben_massiv = FALSE, unten_massiv = FALSE;
3155   boolean links_massiv = FALSE, rechts_massiv = FALSE;
3156
3157   if (!MovDelay[ax][ay])        /* start building new wall */
3158     MovDelay[ax][ay] = 6;
3159
3160   if (MovDelay[ax][ay])         /* wait some time before building new wall */
3161   {
3162     MovDelay[ax][ay]--;
3163     if (MovDelay[ax][ay])
3164       return;
3165   }
3166
3167   if (IN_LEV_FIELD(ax, ay-1) && IS_FREE(ax, ay-1))
3168     oben_frei = TRUE;
3169   if (IN_LEV_FIELD(ax, ay+1) && IS_FREE(ax, ay+1))
3170     unten_frei = TRUE;
3171   if (IN_LEV_FIELD(ax-1, ay) && IS_FREE(ax-1, ay))
3172     links_frei = TRUE;
3173   if (IN_LEV_FIELD(ax+1, ay) && IS_FREE(ax+1, ay))
3174     rechts_frei = TRUE;
3175
3176   if (element == EL_MAUER_Y || element == EL_MAUER_XY)
3177   {
3178     if (oben_frei)
3179     {
3180       Feld[ax][ay-1] = EL_MAUERND;
3181       Store[ax][ay-1] = element;
3182       MovDir[ax][ay-1] = MV_UP;
3183       if (IN_SCR_FIELD(SCREENX(ax), SCREENY(ay-1)))
3184         DrawGraphic(SCREENX(ax), SCREENY(ay-1), GFX_MAUER_UP);
3185     }
3186     if (unten_frei)
3187     {
3188       Feld[ax][ay+1] = EL_MAUERND;
3189       Store[ax][ay+1] = element;
3190       MovDir[ax][ay+1] = MV_DOWN;
3191       if (IN_SCR_FIELD(SCREENX(ax), SCREENY(ay+1)))
3192         DrawGraphic(SCREENX(ax), SCREENY(ay+1), GFX_MAUER_DOWN);
3193     }
3194   }
3195
3196   if (element == EL_MAUER_X || element == EL_MAUER_XY ||
3197       element == EL_MAUER_LEBT)
3198   {
3199     if (links_frei)
3200     {
3201       Feld[ax-1][ay] = EL_MAUERND;
3202       Store[ax-1][ay] = element;
3203       MovDir[ax-1][ay] = MV_LEFT;
3204       if (IN_SCR_FIELD(SCREENX(ax-1), SCREENY(ay)))
3205         DrawGraphic(SCREENX(ax-1), SCREENY(ay), GFX_MAUER_LEFT);
3206     }
3207     if (rechts_frei)
3208     {
3209       Feld[ax+1][ay] = EL_MAUERND;
3210       Store[ax+1][ay] = element;
3211       MovDir[ax+1][ay] = MV_RIGHT;
3212       if (IN_SCR_FIELD(SCREENX(ax+1), SCREENY(ay)))
3213         DrawGraphic(SCREENX(ax+1), SCREENY(ay), GFX_MAUER_RIGHT);
3214     }
3215   }
3216
3217   if (element == EL_MAUER_LEBT && (links_frei || rechts_frei))
3218     DrawLevelField(ax, ay);
3219
3220   if (!IN_LEV_FIELD(ax, ay-1) || IS_MAUER(Feld[ax][ay-1]))
3221     oben_massiv = TRUE;
3222   if (!IN_LEV_FIELD(ax, ay+1) || IS_MAUER(Feld[ax][ay+1]))
3223     unten_massiv = TRUE;
3224   if (!IN_LEV_FIELD(ax-1, ay) || IS_MAUER(Feld[ax-1][ay]))
3225     links_massiv = TRUE;
3226   if (!IN_LEV_FIELD(ax+1, ay) || IS_MAUER(Feld[ax+1][ay]))
3227     rechts_massiv = TRUE;
3228
3229   if (((oben_massiv && unten_massiv) ||
3230        element == EL_MAUER_X || element == EL_MAUER_LEBT) &&
3231       ((links_massiv && rechts_massiv) ||
3232        element == EL_MAUER_Y))
3233     Feld[ax][ay] = EL_MAUERWERK;
3234 }
3235
3236 void CheckForDragon(int x, int y)
3237 {
3238   int i, j;
3239   boolean dragon_found = FALSE;
3240   static int xy[4][2] =
3241   {
3242     { 0, -1 },
3243     { -1, 0 },
3244     { +1, 0 },
3245     { 0, +1 }
3246   };
3247
3248   for (i=0; i<4; i++)
3249   {
3250     for (j=0; j<4; j++)
3251     {
3252       int xx = x + j*xy[i][0], yy = y + j*xy[i][1];
3253
3254       if (IN_LEV_FIELD(xx, yy) &&
3255           (Feld[xx][yy] == EL_BURNING || Feld[xx][yy] == EL_DRACHE))
3256       {
3257         if (Feld[xx][yy] == EL_DRACHE)
3258           dragon_found = TRUE;
3259       }
3260       else
3261         break;
3262     }
3263   }
3264
3265   if (!dragon_found)
3266   {
3267     for (i=0; i<4; i++)
3268     {
3269       for (j=0; j<3; j++)
3270       {
3271         int xx = x + j*xy[i][0], yy = y + j*xy[i][1];
3272   
3273         if (IN_LEV_FIELD(xx, yy) && Feld[xx][yy] == EL_BURNING)
3274         {
3275           Feld[xx][yy] = EL_LEERRAUM;
3276           DrawLevelField(xx, yy);
3277         }
3278         else
3279           break;
3280       }
3281     }
3282   }
3283 }
3284
3285 static void CheckBuggyBase(int x, int y)
3286 {
3287   int element = Feld[x][y];
3288
3289   if (element == EL_SP_BUG)
3290   {
3291     if (!MovDelay[x][y])        /* start activating buggy base */
3292       MovDelay[x][y] = 2 * FRAMES_PER_SECOND + RND(5 * FRAMES_PER_SECOND);
3293
3294     if (MovDelay[x][y])         /* wait some time before activating base */
3295     {
3296       MovDelay[x][y]--;
3297       if (MovDelay[x][y] < 5 && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
3298         DrawGraphic(SCREENX(x), SCREENY(y), GFX_SP_BUG_WARNING);
3299       if (MovDelay[x][y])
3300         return;
3301
3302       Feld[x][y] = EL_SP_BUG_ACTIVE;
3303     }
3304   }
3305   else if (element == EL_SP_BUG_ACTIVE)
3306   {
3307     if (!MovDelay[x][y])        /* start activating buggy base */
3308       MovDelay[x][y] = 1 * FRAMES_PER_SECOND + RND(1 * FRAMES_PER_SECOND);
3309
3310     if (MovDelay[x][y])         /* wait some time before activating base */
3311     {
3312       MovDelay[x][y]--;
3313       if (MovDelay[x][y])
3314       {
3315         int i;
3316         static int xy[4][2] =
3317         {
3318           { 0, -1 },
3319           { -1, 0 },
3320           { +1, 0 },
3321           { 0, +1 }
3322         };
3323
3324         if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
3325           DrawGraphic(SCREENX(x),SCREENY(y), GFX_SP_BUG_ACTIVE + SimpleRND(4));
3326
3327         for (i=0; i<4; i++)
3328         {
3329           int xx = x + xy[i][0], yy = y + xy[i][1];
3330
3331           if (IS_PLAYER(xx, yy))
3332           {
3333             PlaySoundLevel(x, y, SND_SP_BUG);
3334             break;
3335           }
3336         }
3337
3338         return;
3339       }
3340
3341       Feld[x][y] = EL_SP_BUG;
3342       DrawLevelField(x, y);
3343     }
3344   }
3345 }
3346
3347 static void PlayerActions(struct PlayerInfo *player, byte player_action)
3348 {
3349   static byte stored_player_action[MAX_PLAYERS];
3350   static int num_stored_actions = 0;
3351   static boolean save_tape_entry = FALSE;
3352   boolean moved = FALSE, snapped = FALSE, bombed = FALSE;
3353   int jx = player->jx, jy = player->jy;
3354   int left      = player_action & JOY_LEFT;
3355   int right     = player_action & JOY_RIGHT;
3356   int up        = player_action & JOY_UP;
3357   int down      = player_action & JOY_DOWN;
3358   int button1   = player_action & JOY_BUTTON_1;
3359   int button2   = player_action & JOY_BUTTON_2;
3360   int dx        = (left ? -1    : right ? 1     : 0);
3361   int dy        = (up   ? -1    : down  ? 1     : 0);
3362
3363   stored_player_action[player->index_nr] = 0;
3364   num_stored_actions++;
3365
3366   if (!player->active || tape.pausing)
3367     return;
3368
3369   if (player_action)
3370   {
3371     save_tape_entry = TRUE;
3372     player->frame_reset_delay = 0;
3373
3374     if (button1)
3375       snapped = SnapField(player, dx, dy);
3376     else
3377     {
3378       if (button2)
3379         bombed = PlaceBomb(player);
3380       moved = MoveFigure(player, dx, dy);
3381     }
3382
3383     if (tape.recording && (moved || snapped || bombed))
3384     {
3385       if (bombed && !moved)
3386         player_action &= JOY_BUTTON;
3387
3388       stored_player_action[player->index_nr] = player_action;
3389     }
3390     else if (tape.playing && snapped)
3391       SnapField(player, 0, 0);                  /* stop snapping */
3392   }
3393   else
3394   {
3395     /* no actions for this player (no input at player's configured device) */
3396
3397     DigField(player, 0, 0, 0, 0, DF_NO_PUSH);
3398     SnapField(player, 0, 0);
3399     CheckGravityMovement(player);
3400
3401     if (++player->frame_reset_delay > player->move_delay_value)
3402       player->Frame = 0;
3403   }
3404
3405   if (tape.recording && num_stored_actions >= MAX_PLAYERS && save_tape_entry)
3406   {
3407     TapeRecordAction(stored_player_action);
3408     num_stored_actions = 0;
3409     save_tape_entry = FALSE;
3410   }
3411
3412   if (tape.playing && !tape.pausing && !player_action &&
3413       tape.counter < tape.length)
3414   {
3415     int next_joy =
3416       tape.pos[tape.counter].action[player->index_nr] & (JOY_LEFT|JOY_RIGHT);
3417
3418     if ((next_joy == JOY_LEFT || next_joy == JOY_RIGHT) &&
3419         (player->MovDir != JOY_UP && player->MovDir != JOY_DOWN))
3420     {
3421       int dx = (next_joy == JOY_LEFT ? -1 : +1);
3422
3423       if (IN_LEV_FIELD(jx+dx, jy) && IS_PUSHABLE(Feld[jx+dx][jy]))
3424       {
3425         int el = Feld[jx+dx][jy];
3426         int push_delay = (IS_SB_ELEMENT(el) || el == EL_SONDE ? 2 : 10);
3427
3428         if (tape.delay_played + push_delay >= tape.pos[tape.counter].delay)
3429         {
3430           player->MovDir = next_joy;
3431           player->Frame = FrameCounter % 4;
3432           player->Pushing = TRUE;
3433         }
3434       }
3435     }
3436   }
3437 }
3438
3439 void GameActions()
3440 {
3441   static unsigned long action_delay = 0;
3442   unsigned long action_delay_value;
3443   int sieb_x = 0, sieb_y = 0;
3444   int i, x, y, element;
3445   byte *recorded_player_action;
3446   byte summarized_player_action = 0;
3447
3448   if (game_status != PLAYING)
3449     return;
3450
3451   action_delay_value =
3452     (tape.playing && tape.fast_forward ? FfwdFrameDelay : GameFrameDelay);
3453
3454   /* ---------- main game synchronization point ---------- */
3455
3456   WaitUntilDelayReached(&action_delay, action_delay_value);
3457
3458   if (network_playing && !network_player_action_received)
3459   {
3460     /*
3461 #ifdef DEBUG
3462     printf("DEBUG: try to get network player actions in time\n");
3463 #endif
3464     */
3465
3466 #ifndef MSDOS
3467     /* last chance to get network player actions without main loop delay */
3468     HandleNetworking();
3469 #endif
3470
3471     if (game_status != PLAYING)
3472       return;
3473
3474     if (!network_player_action_received)
3475     {
3476       /*
3477 #ifdef DEBUG
3478       printf("DEBUG: failed to get network player actions in time\n");
3479 #endif
3480       */
3481       return;
3482     }
3483   }
3484
3485   if (tape.pausing)
3486     return;
3487
3488   if (tape.playing)
3489     TapePlayDelay();
3490   else if (tape.recording)
3491     TapeRecordDelay();
3492
3493   recorded_player_action = (tape.playing ? TapePlayAction() : NULL);
3494
3495   for (i=0; i<MAX_PLAYERS; i++)
3496   {
3497     summarized_player_action |= stored_player[i].action;
3498
3499     if (!network_playing)
3500       stored_player[i].effective_action = stored_player[i].action;
3501   }
3502
3503 #ifndef MSDOS
3504   if (network_playing)
3505     SendToServer_MovePlayer(summarized_player_action);
3506 #endif
3507
3508   if (!options.network && !setup.team_mode)
3509     local_player->effective_action = summarized_player_action;
3510
3511   for (i=0; i<MAX_PLAYERS; i++)
3512   {
3513     int actual_player_action = stored_player[i].effective_action;
3514
3515     if (stored_player[i].programmed_action)
3516       actual_player_action = stored_player[i].programmed_action;
3517
3518     if (recorded_player_action)
3519       actual_player_action = recorded_player_action[i];
3520
3521     PlayerActions(&stored_player[i], actual_player_action);
3522     ScrollFigure(&stored_player[i], SCROLL_GO_ON);
3523   }
3524
3525   network_player_action_received = FALSE;
3526
3527   ScrollScreen(NULL, SCROLL_GO_ON);
3528
3529
3530
3531 #ifdef DEBUG
3532 #if 0
3533   if (TimeFrames == 0 && local_player->active)
3534   {
3535     extern unsigned int last_RND();
3536
3537     printf("DEBUG: %03d last RND was %d \t [state checksum is %d]\n",
3538            TimePlayed, last_RND(), getStateCheckSum(TimePlayed));
3539   }
3540 #endif
3541 #endif
3542
3543 #ifdef DEBUG
3544 #if 0
3545   if (GameFrameDelay >= 500)
3546     printf("FrameCounter == %d\n", FrameCounter);
3547 #endif
3548 #endif
3549
3550
3551
3552   FrameCounter++;
3553   TimeFrames++;
3554
3555   for (y=0; y<lev_fieldy; y++) for (x=0; x<lev_fieldx; x++)
3556   {
3557     Stop[x][y] = FALSE;
3558     if (JustHit[x][y]>0)
3559       JustHit[x][y]--;
3560
3561 #if DEBUG
3562     if (IS_BLOCKED(x, y))
3563     {
3564       int oldx, oldy;
3565
3566       Blocked2Moving(x, y, &oldx, &oldy);
3567       if (!IS_MOVING(oldx, oldy))
3568       {
3569         printf("GameActions(): (BLOCKED => MOVING) context corrupted!\n");
3570         printf("GameActions(): BLOCKED: x = %d, y = %d\n", x, y);
3571         printf("GameActions(): !MOVING: oldx = %d, oldy = %d\n", oldx, oldy);
3572         printf("GameActions(): This should never happen!\n");
3573       }
3574     }
3575 #endif
3576   }
3577
3578   for (y=0; y<lev_fieldy; y++) for (x=0; x<lev_fieldx; x++)
3579   {
3580     element = Feld[x][y];
3581
3582     if (IS_INACTIVE(element))
3583       continue;
3584
3585     if (!IS_MOVING(x, y) && (CAN_FALL(element) || CAN_MOVE(element)))
3586     {
3587       StartMoving(x, y);
3588
3589       if (IS_GEM(element))
3590         EdelsteinFunkeln(x, y);
3591     }
3592     else if (IS_MOVING(x, y))
3593       ContinueMoving(x, y);
3594     else if (IS_ACTIVE_BOMB(element))
3595       CheckDynamite(x, y);
3596     else if (element == EL_EXPLODING)
3597       Explode(x, y, Frame[x][y], EX_NORMAL);
3598     else if (element == EL_AMOEBING)
3599       AmoebeWaechst(x, y);
3600     else if (IS_AMOEBALIVE(element))
3601       AmoebeAbleger(x, y);
3602     else if (element == EL_LIFE || element == EL_LIFE_ASYNC)
3603       Life(x, y);
3604     else if (element == EL_ABLENK_EIN)
3605       Ablenk(x, y);
3606     else if (element == EL_SALZSAEURE)
3607       Blubber(x, y);
3608     else if (element == EL_BLURB_LEFT || element == EL_BLURB_RIGHT)
3609       Blurb(x, y);
3610     else if (element == EL_CRACKINGNUT)
3611       NussKnacken(x, y);
3612     else if (element == EL_AUSGANG_ZU)
3613       AusgangstuerPruefen(x, y);
3614     else if (element == EL_AUSGANG_ACT)
3615       AusgangstuerOeffnen(x, y);
3616     else if (element == EL_AUSGANG_AUF)
3617       AusgangstuerBlinken(x, y);
3618     else if (element == EL_MAUERND)
3619       MauerWaechst(x, y);
3620     else if (element == EL_MAUER_LEBT ||
3621              element == EL_MAUER_X ||
3622              element == EL_MAUER_Y ||
3623              element == EL_MAUER_XY)
3624       MauerAbleger(x, y);
3625     else if (element == EL_BURNING)
3626       CheckForDragon(x, y);
3627     else if (element == EL_SP_BUG || element == EL_SP_BUG_ACTIVE)
3628       CheckBuggyBase(x, y);
3629     else if (element == EL_SP_TERMINAL)
3630       DrawGraphicAnimation(x, y, GFX2_SP_TERMINAL, 7, 12, ANIM_NORMAL);
3631     else if (element == EL_SP_TERMINAL_ACTIVE)
3632       DrawGraphicAnimation(x, y, GFX2_SP_TERMINAL_ACTIVE, 7, 4, ANIM_NORMAL);
3633
3634     if (game.magic_wall_active)
3635     {
3636       boolean sieb = FALSE;
3637       int jx = local_player->jx, jy = local_player->jy;
3638
3639       if (element == EL_SIEB_LEER || element == EL_SIEB_VOLL ||
3640           Store[x][y] == EL_SIEB_LEER)
3641       {
3642         SiebAktivieren(x, y, 1);
3643         sieb = TRUE;
3644       }
3645       else if (element == EL_SIEB2_LEER || element == EL_SIEB2_VOLL ||
3646                Store[x][y] == EL_SIEB2_LEER)
3647       {
3648         SiebAktivieren(x, y, 2);
3649         sieb = TRUE;
3650       }
3651
3652       /* play the element sound at the position nearest to the player */
3653       if (sieb && ABS(x-jx)+ABS(y-jy) < ABS(sieb_x-jx)+ABS(sieb_y-jy))
3654       {
3655         sieb_x = x;
3656         sieb_y = y;
3657       }
3658     }
3659   }
3660
3661   if (game.magic_wall_active)
3662   {
3663     if (!(game.magic_wall_time_left % 4))
3664       PlaySoundLevel(sieb_x, sieb_y, SND_MIEP);
3665
3666     if (game.magic_wall_time_left > 0)
3667     {
3668       game.magic_wall_time_left--;
3669       if (!game.magic_wall_time_left)
3670       {
3671         for (y=0; y<lev_fieldy; y++) for (x=0; x<lev_fieldx; x++)
3672         {
3673           element = Feld[x][y];
3674           if (element == EL_SIEB_LEER || element == EL_SIEB_VOLL)
3675           {
3676             Feld[x][y] = EL_SIEB_TOT;
3677             DrawLevelField(x, y);
3678           }
3679           else if (element == EL_SIEB2_LEER || element == EL_SIEB2_VOLL)
3680           {
3681             Feld[x][y] = EL_SIEB2_TOT;
3682             DrawLevelField(x, y);
3683           }
3684         }
3685
3686         game.magic_wall_active = FALSE;
3687       }
3688     }
3689   }
3690
3691   if (TimeFrames >= (1000 / GameFrameDelay) && !tape.pausing)
3692   {
3693     TimeFrames = 0;
3694     TimePlayed++;
3695
3696     if (tape.recording || tape.playing)
3697       DrawVideoDisplay(VIDEO_STATE_TIME_ON, TimePlayed);
3698
3699     if (TimeLeft > 0)
3700     {
3701       TimeLeft--;
3702
3703       if (TimeLeft <= 10)
3704         PlaySoundStereo(SND_GONG, PSND_MAX_RIGHT);
3705
3706       DrawText(DX_TIME, DY_TIME, int2str(TimeLeft, 3), FS_SMALL, FC_YELLOW);
3707
3708       if (!TimeLeft)
3709         for (i=0; i<MAX_PLAYERS; i++)
3710           KillHero(&stored_player[i]);
3711     }
3712     else if (level.time == 0)           /* level without time limit */
3713       DrawText(DX_TIME, DY_TIME, int2str(TimePlayed, 3), FS_SMALL, FC_YELLOW);
3714   }
3715
3716   DrawAllPlayers();
3717 }
3718
3719 static boolean AllPlayersInSight(struct PlayerInfo *player, int x, int y)
3720 {
3721   int min_x = x, min_y = y, max_x = x, max_y = y;
3722   int i;
3723
3724   for (i=0; i<MAX_PLAYERS; i++)
3725   {
3726     int jx = stored_player[i].jx, jy = stored_player[i].jy;
3727
3728     if (!stored_player[i].active || &stored_player[i] == player)
3729       continue;
3730
3731     min_x = MIN(min_x, jx);
3732     min_y = MIN(min_y, jy);
3733     max_x = MAX(max_x, jx);
3734     max_y = MAX(max_y, jy);
3735   }
3736
3737   return (max_x - min_x < SCR_FIELDX && max_y - min_y < SCR_FIELDY);
3738 }
3739
3740 static boolean AllPlayersInVisibleScreen()
3741 {
3742   int i;
3743
3744   for (i=0; i<MAX_PLAYERS; i++)
3745   {
3746     int jx = stored_player[i].jx, jy = stored_player[i].jy;
3747
3748     if (!stored_player[i].active)
3749       continue;
3750
3751     if (!IN_VIS_FIELD(SCREENX(jx), SCREENY(jy)))
3752       return FALSE;
3753   }
3754
3755   return TRUE;
3756 }
3757
3758 void ScrollLevel(int dx, int dy)
3759 {
3760   int softscroll_offset = (setup.soft_scrolling ? TILEX : 0);
3761   int x, y;
3762
3763   XCopyArea(display, drawto_field, drawto_field, gc,
3764             FX + TILEX*(dx == -1) - softscroll_offset,
3765             FY + TILEY*(dy == -1) - softscroll_offset,
3766             SXSIZE - TILEX*(dx!=0) + 2*softscroll_offset,
3767             SYSIZE - TILEY*(dy!=0) + 2*softscroll_offset,
3768             FX + TILEX*(dx == 1) - softscroll_offset,
3769             FY + TILEY*(dy == 1) - softscroll_offset);
3770
3771   if (dx)
3772   {
3773     x = (dx == 1 ? BX1 : BX2);
3774     for (y=BY1; y<=BY2; y++)
3775       DrawScreenField(x, y);
3776   }
3777   if (dy)
3778   {
3779     y = (dy == 1 ? BY1 : BY2);
3780     for (x=BX1; x<=BX2; x++)
3781       DrawScreenField(x, y);
3782   }
3783
3784   redraw_mask |= REDRAW_FIELD;
3785 }
3786
3787 static void CheckGravityMovement(struct PlayerInfo *player)
3788 {
3789   if (level.gravity && !player->programmed_action)
3790   {
3791     int move_dir_vertical = player->action & (MV_UP | MV_DOWN);
3792     int move_dir_horizontal = player->action & (MV_LEFT | MV_RIGHT);
3793     int move_dir =
3794       (player->last_move_dir & (MV_LEFT | MV_RIGHT) ?
3795        (move_dir_vertical ? move_dir_vertical : move_dir_horizontal) :
3796        (move_dir_horizontal ? move_dir_horizontal : move_dir_vertical));
3797     int jx = player->jx, jy = player->jy;
3798     int dx = (move_dir & MV_LEFT ? -1 : move_dir & MV_RIGHT ? +1 : 0);
3799     int dy = (move_dir & MV_UP ? -1 : move_dir & MV_DOWN ? +1 : 0);
3800     int new_jx = jx + dx, new_jy = jy + dy;
3801     boolean field_under_player_is_free =
3802       (IN_LEV_FIELD(jx, jy + 1) && IS_FREE(jx, jy + 1));
3803     boolean player_is_moving_to_valid_field =
3804       (IN_LEV_FIELD(new_jx, new_jy) &&
3805        (Feld[new_jx][new_jy] == EL_SP_BASE ||
3806         Feld[new_jx][new_jy] == EL_ERDREICH));
3807
3808     if (field_under_player_is_free && !player_is_moving_to_valid_field)
3809       player->programmed_action = MV_DOWN;
3810   }
3811 }
3812
3813 boolean MoveFigureOneStep(struct PlayerInfo *player,
3814                           int dx, int dy, int real_dx, int real_dy)
3815 {
3816   int jx = player->jx, jy = player->jy;
3817   int new_jx = jx+dx, new_jy = jy+dy;
3818   int element;
3819   int can_move;
3820
3821   if (!player->active || (!dx && !dy))
3822     return MF_NO_ACTION;
3823
3824   player->MovDir = (dx < 0 ? MV_LEFT :
3825                     dx > 0 ? MV_RIGHT :
3826                     dy < 0 ? MV_UP :
3827                     dy > 0 ? MV_DOWN :  MV_NO_MOVING);
3828
3829   if (!IN_LEV_FIELD(new_jx, new_jy))
3830     return MF_NO_ACTION;
3831
3832   if (!options.network && !AllPlayersInSight(player, new_jx, new_jy))
3833     return MF_NO_ACTION;
3834
3835 #if 0
3836   element = MovingOrBlocked2Element(new_jx, new_jy);
3837 #else
3838   element = MovingOrBlocked2ElementIfNotLeaving(new_jx, new_jy);
3839 #endif
3840
3841   if (DONT_GO_TO(element))
3842   {
3843     if (element == EL_SALZSAEURE && dx == 0 && dy == 1)
3844     {
3845       Blurb(jx, jy);
3846       Feld[jx][jy] = EL_SPIELFIGUR;
3847       InitMovingField(jx, jy, MV_DOWN);
3848       Store[jx][jy] = EL_SALZSAEURE;
3849       ContinueMoving(jx, jy);
3850       BuryHero(player);
3851     }
3852     else
3853       KillHero(player);
3854
3855     return MF_MOVING;
3856   }
3857
3858   can_move = DigField(player, new_jx, new_jy, real_dx, real_dy, DF_DIG);
3859   if (can_move != MF_MOVING)
3860     return can_move;
3861
3862   StorePlayer[jx][jy] = 0;
3863   player->last_jx = jx;
3864   player->last_jy = jy;
3865   jx = player->jx = new_jx;
3866   jy = player->jy = new_jy;
3867   StorePlayer[jx][jy] = player->element_nr;
3868
3869   player->MovPos =
3870     (dx > 0 || dy > 0 ? -1 : 1) * (TILEX - TILEX / player->move_delay_value);
3871
3872   ScrollFigure(player, SCROLL_INIT);
3873
3874   return MF_MOVING;
3875 }
3876
3877 boolean MoveFigure(struct PlayerInfo *player, int dx, int dy)
3878 {
3879   int jx = player->jx, jy = player->jy;
3880   int old_jx = jx, old_jy = jy;
3881   int moved = MF_NO_ACTION;
3882
3883   if (!player->active || (!dx && !dy))
3884     return FALSE;
3885
3886   if (!FrameReached(&player->move_delay, player->move_delay_value) &&
3887       !tape.playing)
3888     return FALSE;
3889
3890   /* remove the last programmed player action */
3891   player->programmed_action = 0;
3892
3893   if (player->MovPos)
3894   {
3895     /* should only happen if pre-1.2 tape recordings are played */
3896     /* this is only for backward compatibility */
3897
3898     int original_move_delay_value = player->move_delay_value;
3899
3900 #if DEBUG
3901     printf("THIS SHOULD ONLY HAPPEN WITH PRE-1.2 LEVEL TAPES.\n");
3902 #endif
3903
3904     /* scroll remaining steps with finest movement resolution */
3905     player->move_delay_value = MOVE_DELAY_NORMAL_SPEED;
3906
3907     while (player->MovPos)
3908     {
3909       ScrollFigure(player, SCROLL_GO_ON);
3910       ScrollScreen(NULL, SCROLL_GO_ON);
3911       FrameCounter++;
3912       DrawAllPlayers();
3913       BackToFront();
3914     }
3915
3916     player->move_delay_value = original_move_delay_value;
3917   }
3918
3919   if (player->last_move_dir & (MV_LEFT | MV_RIGHT))
3920   {
3921     if (!(moved |= MoveFigureOneStep(player, 0, dy, dx, dy)))
3922       moved |= MoveFigureOneStep(player, dx, 0, dx, dy);
3923   }
3924   else
3925   {
3926     if (!(moved |= MoveFigureOneStep(player, dx, 0, dx, dy)))
3927       moved |= MoveFigureOneStep(player, 0, dy, dx, dy);
3928   }
3929
3930   jx = player->jx;
3931   jy = player->jy;
3932
3933   if (moved & MF_MOVING && !ScreenMovPos &&
3934       (player == local_player || !options.network))
3935   {
3936     int old_scroll_x = scroll_x, old_scroll_y = scroll_y;
3937     int offset = (setup.scroll_delay ? 3 : 0);
3938
3939     if (!IN_VIS_FIELD(SCREENX(jx), SCREENY(jy)))
3940     {
3941       /* actual player has left the screen -- scroll in that direction */
3942       if (jx != old_jx)         /* player has moved horizontally */
3943         scroll_x += (jx - old_jx);
3944       else                      /* player has moved vertically */
3945         scroll_y += (jy - old_jy);
3946     }
3947     else
3948     {
3949       if (jx != old_jx)         /* player has moved horizontally */
3950       {
3951         if ((player->MovDir == MV_LEFT && scroll_x > jx - MIDPOSX + offset) ||
3952             (player->MovDir == MV_RIGHT && scroll_x < jx - MIDPOSX - offset))
3953           scroll_x = jx-MIDPOSX + (scroll_x < jx-MIDPOSX ? -offset : +offset);
3954
3955         /* don't scroll over playfield boundaries */
3956         if (scroll_x < SBX_Left || scroll_x > SBX_Right)
3957           scroll_x = (scroll_x < SBX_Left ? SBX_Left : SBX_Right);
3958
3959         /* don't scroll more than one field at a time */
3960         scroll_x = old_scroll_x + SIGN(scroll_x - old_scroll_x);
3961
3962         /* don't scroll against the player's moving direction */
3963         if ((player->MovDir == MV_LEFT && scroll_x > old_scroll_x) ||
3964             (player->MovDir == MV_RIGHT && scroll_x < old_scroll_x))
3965           scroll_x = old_scroll_x;
3966       }
3967       else                      /* player has moved vertically */
3968       {
3969         if ((player->MovDir == MV_UP && scroll_y > jy - MIDPOSY + offset) ||
3970             (player->MovDir == MV_DOWN && scroll_y < jy - MIDPOSY - offset))
3971           scroll_y = jy-MIDPOSY + (scroll_y < jy-MIDPOSY ? -offset : +offset);
3972
3973         /* don't scroll over playfield boundaries */
3974         if (scroll_y < SBY_Upper || scroll_y > SBY_Lower)
3975           scroll_y = (scroll_y < SBY_Upper ? SBY_Upper : SBY_Lower);
3976
3977         /* don't scroll more than one field at a time */
3978         scroll_y = old_scroll_y + SIGN(scroll_y - old_scroll_y);
3979
3980         /* don't scroll against the player's moving direction */
3981         if ((player->MovDir == MV_UP && scroll_y > old_scroll_y) ||
3982             (player->MovDir == MV_DOWN && scroll_y < old_scroll_y))
3983           scroll_y = old_scroll_y;
3984       }
3985     }
3986
3987     if (scroll_x != old_scroll_x || scroll_y != old_scroll_y)
3988     {
3989       if (!options.network && !AllPlayersInVisibleScreen())
3990       {
3991         scroll_x = old_scroll_x;
3992         scroll_y = old_scroll_y;
3993       }
3994       else
3995       {
3996         ScrollScreen(player, SCROLL_INIT);
3997         ScrollLevel(old_scroll_x - scroll_x, old_scroll_y - scroll_y);
3998       }
3999     }
4000   }
4001
4002   if (!(moved & MF_MOVING) && !player->Pushing)
4003     player->Frame = 0;
4004   else
4005     player->Frame = (player->Frame + 1) % 4;
4006
4007   if (moved & MF_MOVING)
4008   {
4009     if (old_jx != jx && old_jy == jy)
4010       player->MovDir = (old_jx < jx ? MV_RIGHT : MV_LEFT);
4011     else if (old_jx == jx && old_jy != jy)
4012       player->MovDir = (old_jy < jy ? MV_DOWN : MV_UP);
4013
4014     DrawLevelField(jx, jy);     /* for "ErdreichAnbroeckeln()" */
4015
4016     player->last_move_dir = player->MovDir;
4017   }
4018   else
4019   {
4020     CheckGravityMovement(player);
4021
4022     player->last_move_dir = MV_NO_MOVING;
4023   }
4024
4025   TestIfHeroHitsBadThing(jx, jy);
4026
4027   if (!player->active)
4028     RemoveHero(player);
4029
4030   return moved;
4031 }
4032
4033 void ScrollFigure(struct PlayerInfo *player, int mode)
4034 {
4035   int jx = player->jx, jy = player->jy;
4036   int last_jx = player->last_jx, last_jy = player->last_jy;
4037   int move_stepsize = TILEX / player->move_delay_value;
4038
4039   if (!player->active || !player->MovPos)
4040     return;
4041
4042   if (mode == SCROLL_INIT)
4043   {
4044     player->actual_frame_counter = FrameCounter;
4045     player->GfxPos = move_stepsize * (player->MovPos / move_stepsize);
4046
4047     if (Feld[last_jx][last_jy] == EL_LEERRAUM)
4048       Feld[last_jx][last_jy] = EL_PLAYER_IS_LEAVING;
4049
4050     DrawPlayer(player);
4051     return;
4052   }
4053   else if (!FrameReached(&player->actual_frame_counter, 1))
4054     return;
4055
4056   player->MovPos += (player->MovPos > 0 ? -1 : 1) * move_stepsize;
4057   player->GfxPos = move_stepsize * (player->MovPos / move_stepsize);
4058
4059   if (Feld[last_jx][last_jy] == EL_PLAYER_IS_LEAVING)
4060     Feld[last_jx][last_jy] = EL_LEERRAUM;
4061
4062   /* before DrawPlayer() to draw correct player graphic for this case */
4063   if (player->MovPos == 0)
4064     CheckGravityMovement(player);
4065
4066   DrawPlayer(player);
4067
4068   if (player->MovPos == 0)
4069   {
4070     if (IS_QUICK_GATE(Feld[last_jx][last_jy]))
4071     {
4072       /* continue with normal speed after quickly moving through gate */
4073       HALVE_PLAYER_SPEED(player);
4074
4075       /* be able to make the next move without delay */
4076       player->move_delay = 0;
4077     }
4078
4079     player->last_jx = jx;
4080     player->last_jy = jy;
4081
4082     if (Feld[jx][jy] == EL_AUSGANG_AUF)
4083     {
4084       RemoveHero(player);
4085
4086       if (!local_player->friends_still_needed)
4087         player->LevelSolved = player->GameOver = TRUE;
4088     }
4089   }
4090 }
4091
4092 void ScrollScreen(struct PlayerInfo *player, int mode)
4093 {
4094   static unsigned long screen_frame_counter = 0;
4095
4096   if (mode == SCROLL_INIT)
4097   {
4098     /* set scrolling step size according to actual player's moving speed */
4099     ScrollStepSize = TILEX / player->move_delay_value;
4100
4101     screen_frame_counter = FrameCounter;
4102     ScreenMovDir = player->MovDir;
4103     ScreenMovPos = player->MovPos;
4104     ScreenGfxPos = ScrollStepSize * (ScreenMovPos / ScrollStepSize);
4105     return;
4106   }
4107   else if (!FrameReached(&screen_frame_counter, 1))
4108     return;
4109
4110   if (ScreenMovPos)
4111   {
4112     ScreenMovPos += (ScreenMovPos > 0 ? -1 : 1) * ScrollStepSize;
4113     ScreenGfxPos = ScrollStepSize * (ScreenMovPos / ScrollStepSize);
4114     redraw_mask |= REDRAW_FIELD;
4115   }
4116   else
4117     ScreenMovDir = MV_NO_MOVING;
4118 }
4119
4120 void TestIfGoodThingHitsBadThing(int goodx, int goody)
4121 {
4122   int i, killx = goodx, killy = goody;
4123   static int xy[4][2] =
4124   {
4125     { 0, -1 },
4126     { -1, 0 },
4127     { +1, 0 },
4128     { 0, +1 }
4129   };
4130   static int harmless[4] =
4131   {
4132     MV_UP,
4133     MV_LEFT,
4134     MV_RIGHT,
4135     MV_DOWN
4136   };
4137
4138   for (i=0; i<4; i++)
4139   {
4140     int x, y, element;
4141
4142     x = goodx + xy[i][0];
4143     y = goody + xy[i][1];
4144     if (!IN_LEV_FIELD(x, y))
4145       continue;
4146
4147 #if 0
4148     element = Feld[x][y];
4149 #else
4150     element = MovingOrBlocked2ElementIfNotLeaving(x, y);
4151 #endif
4152
4153     if (DONT_TOUCH(element))
4154     {
4155       if (MovDir[x][y] == harmless[i])
4156         continue;
4157
4158       killx = x;
4159       killy = y;
4160       break;
4161     }
4162   }
4163
4164   if (killx != goodx || killy != goody)
4165   {
4166     if (IS_PLAYER(goodx, goody))
4167       KillHero(PLAYERINFO(goodx, goody));
4168     else
4169       Bang(goodx, goody);
4170   }
4171 }
4172
4173 void TestIfBadThingHitsGoodThing(int badx, int bady)
4174 {
4175   int i, killx = badx, killy = bady;
4176   static int xy[4][2] =
4177   {
4178     { 0, -1 },
4179     { -1, 0 },
4180     { +1, 0 },
4181     { 0, +1 }
4182   };
4183   static int harmless[4] =
4184   {
4185     MV_UP,
4186     MV_LEFT,
4187     MV_RIGHT,
4188     MV_DOWN
4189   };
4190
4191   for (i=0; i<4; i++)
4192   {
4193     int x, y, element;
4194
4195     x = badx + xy[i][0];
4196     y = bady + xy[i][1];
4197     if (!IN_LEV_FIELD(x, y))
4198       continue;
4199
4200     element = Feld[x][y];
4201
4202     if (IS_PLAYER(x, y))
4203     {
4204       killx = x;
4205       killy = y;
4206       break;
4207     }
4208     else if (element == EL_PINGUIN)
4209     {
4210       if (MovDir[x][y] == harmless[i] && IS_MOVING(x, y))
4211         continue;
4212
4213       killx = x;
4214       killy = y;
4215       break;
4216     }
4217   }
4218
4219   if (killx != badx || killy != bady)
4220   {
4221     if (IS_PLAYER(killx, killy))
4222       KillHero(PLAYERINFO(killx, killy));
4223     else
4224       Bang(killx, killy);
4225   }
4226 }
4227
4228 void TestIfHeroHitsBadThing(int x, int y)
4229 {
4230   TestIfGoodThingHitsBadThing(x, y);
4231 }
4232
4233 void TestIfBadThingHitsHero(int x, int y)
4234 {
4235   TestIfBadThingHitsGoodThing(x, y);
4236 }
4237
4238 void TestIfFriendHitsBadThing(int x, int y)
4239 {
4240   TestIfGoodThingHitsBadThing(x, y);
4241 }
4242
4243 void TestIfBadThingHitsFriend(int x, int y)
4244 {
4245   TestIfBadThingHitsGoodThing(x, y);
4246 }
4247
4248 void TestIfBadThingHitsOtherBadThing(int badx, int bady)
4249 {
4250   int i, killx = badx, killy = bady;
4251   static int xy[4][2] =
4252   {
4253     { 0, -1 },
4254     { -1, 0 },
4255     { +1, 0 },
4256     { 0, +1 }
4257   };
4258
4259   for (i=0; i<4; i++)
4260   {
4261     int x, y, element;
4262
4263     x=badx + xy[i][0];
4264     y=bady + xy[i][1];
4265     if (!IN_LEV_FIELD(x, y))
4266       continue;
4267
4268     element = Feld[x][y];
4269     if (IS_AMOEBOID(element) || element == EL_LIFE ||
4270         element == EL_AMOEBING || element == EL_TROPFEN)
4271     {
4272       killx = x;
4273       killy = y;
4274       break;
4275     }
4276   }
4277
4278   if (killx != badx || killy != bady)
4279     Bang(badx, bady);
4280 }
4281
4282 void KillHero(struct PlayerInfo *player)
4283 {
4284   int jx = player->jx, jy = player->jy;
4285
4286   if (!player->active)
4287     return;
4288
4289   if (IS_PFORTE(Feld[jx][jy]))
4290     Feld[jx][jy] = EL_LEERRAUM;
4291
4292   Bang(jx, jy);
4293   BuryHero(player);
4294 }
4295
4296 void BuryHero(struct PlayerInfo *player)
4297 {
4298   int jx = player->jx, jy = player->jy;
4299
4300   if (!player->active)
4301     return;
4302
4303   PlaySoundLevel(jx, jy, SND_AUTSCH);
4304   PlaySoundLevel(jx, jy, SND_LACHEN);
4305
4306   player->GameOver = TRUE;
4307   RemoveHero(player);
4308 }
4309
4310 void RemoveHero(struct PlayerInfo *player)
4311 {
4312   int jx = player->jx, jy = player->jy;
4313   int i, found = FALSE;
4314
4315   player->present = FALSE;
4316   player->active = FALSE;
4317
4318   StorePlayer[jx][jy] = 0;
4319
4320   for (i=0; i<MAX_PLAYERS; i++)
4321     if (stored_player[i].active)
4322       found = TRUE;
4323
4324   if (!found)
4325     AllPlayersGone = TRUE;
4326
4327   ExitX = ZX = jx;
4328   ExitY = ZY = jy;
4329 }
4330
4331 int DigField(struct PlayerInfo *player,
4332              int x, int y, int real_dx, int real_dy, int mode)
4333 {
4334   int jx = player->jx, jy = player->jy;
4335   int dx = x - jx, dy = y - jy;
4336   int move_direction = (dx == -1 ? MV_LEFT :
4337                         dx == +1 ? MV_RIGHT :
4338                         dy == -1 ? MV_UP :
4339                         dy == +1 ? MV_DOWN : MV_NO_MOVING);
4340   int element;
4341
4342   if (!player->MovPos)
4343     player->Pushing = FALSE;
4344
4345   if (mode == DF_NO_PUSH)
4346   {
4347     player->push_delay = 0;
4348     return MF_NO_ACTION;
4349   }
4350
4351   if (IS_MOVING(x, y) || IS_PLAYER(x, y))
4352     return MF_NO_ACTION;
4353
4354   element = Feld[x][y];
4355
4356   switch(element)
4357   {
4358     case EL_LEERRAUM:
4359       PlaySoundLevel(x, y, SND_EMPTY);
4360       break;
4361
4362     case EL_ERDREICH:
4363       Feld[x][y] = EL_LEERRAUM;
4364       PlaySoundLevel(x, y, SND_SCHLURF);
4365       break;
4366
4367     case EL_SP_BASE:
4368     case EL_SP_BUG:
4369       Feld[x][y] = EL_LEERRAUM;
4370       PlaySoundLevel(x, y, SND_SP_BASE);
4371       break;
4372
4373     case EL_EDELSTEIN:
4374     case EL_EDELSTEIN_BD:
4375     case EL_EDELSTEIN_GELB:
4376     case EL_EDELSTEIN_ROT:
4377     case EL_EDELSTEIN_LILA:
4378     case EL_DIAMANT:
4379     case EL_SP_INFOTRON:
4380       RemoveField(x, y);
4381       local_player->gems_still_needed -= (element == EL_DIAMANT ? 3 : 1);
4382       if (local_player->gems_still_needed < 0)
4383         local_player->gems_still_needed = 0;
4384       RaiseScoreElement(element);
4385       DrawText(DX_EMERALDS, DY_EMERALDS,
4386                int2str(local_player->gems_still_needed, 3),
4387                FS_SMALL, FC_YELLOW);
4388       if (element == EL_SP_INFOTRON)
4389         PlaySoundLevel(x, y, SND_SP_INFOTRON);
4390       else
4391         PlaySoundLevel(x, y, SND_PONG);
4392       break;
4393
4394     case EL_SPEED_PILL:
4395       RemoveField(x, y);
4396       player->move_delay_value = MOVE_DELAY_HIGH_SPEED;
4397       PlaySoundLevel(x, y, SND_PONG);
4398       break;
4399
4400     case EL_DYNAMITE_INACTIVE:
4401     case EL_SP_DISK_RED:
4402       RemoveField(x, y);
4403       player->dynamite++;
4404       RaiseScoreElement(EL_DYNAMITE_INACTIVE);
4405       DrawText(DX_DYNAMITE, DY_DYNAMITE,
4406                int2str(local_player->dynamite, 3),
4407                FS_SMALL, FC_YELLOW);
4408       if (element == EL_SP_DISK_RED)
4409         PlaySoundLevel(x, y, SND_SP_INFOTRON);
4410       else
4411         PlaySoundLevel(x, y, SND_PONG);
4412       break;
4413
4414     case EL_DYNABOMB_NR:
4415       RemoveField(x, y);
4416       player->dynabomb_count++;
4417       player->dynabombs_left++;
4418       RaiseScoreElement(EL_DYNAMITE_INACTIVE);
4419       PlaySoundLevel(x, y, SND_PONG);
4420       break;
4421
4422     case EL_DYNABOMB_SZ:
4423       RemoveField(x, y);
4424       player->dynabomb_size++;
4425       RaiseScoreElement(EL_DYNAMITE_INACTIVE);
4426       PlaySoundLevel(x, y, SND_PONG);
4427       break;
4428
4429     case EL_DYNABOMB_XL:
4430       RemoveField(x, y);
4431       player->dynabomb_xl = TRUE;
4432       RaiseScoreElement(EL_DYNAMITE_INACTIVE);
4433       PlaySoundLevel(x, y, SND_PONG);
4434       break;
4435
4436     case EL_SCHLUESSEL1:
4437     case EL_SCHLUESSEL2:
4438     case EL_SCHLUESSEL3:
4439     case EL_SCHLUESSEL4:
4440     {
4441       int key_nr = element - EL_SCHLUESSEL1;
4442
4443       RemoveField(x, y);
4444       player->key[key_nr] = TRUE;
4445       RaiseScoreElement(EL_SCHLUESSEL);
4446       DrawMiniGraphicExt(drawto, gc,
4447                          DX_KEYS+key_nr*MINI_TILEX, DY_KEYS,
4448                          GFX_SCHLUESSEL1+key_nr);
4449       DrawMiniGraphicExt(window, gc,
4450                          DX_KEYS+key_nr*MINI_TILEX, DY_KEYS,
4451                          GFX_SCHLUESSEL1+key_nr);
4452       PlaySoundLevel(x, y, SND_PONG);
4453       break;
4454     }
4455
4456     case EL_EM_KEY_1:
4457     case EL_EM_KEY_2:
4458     case EL_EM_KEY_3:
4459     case EL_EM_KEY_4:
4460     {
4461       int key_nr = element - EL_EM_KEY_1;
4462
4463       RemoveField(x, y);
4464       player->key[key_nr] = TRUE;
4465       RaiseScoreElement(EL_SCHLUESSEL);
4466       DrawMiniGraphicExt(drawto, gc,
4467                          DX_KEYS+key_nr*MINI_TILEX, DY_KEYS,
4468                          GFX_SCHLUESSEL1+key_nr);
4469       DrawMiniGraphicExt(window, gc,
4470                          DX_KEYS+key_nr*MINI_TILEX, DY_KEYS,
4471                          GFX_SCHLUESSEL1+key_nr);
4472       PlaySoundLevel(x, y, SND_PONG);
4473       break;
4474     }
4475
4476     case EL_ABLENK_AUS:
4477       Feld[x][y] = EL_ABLENK_EIN;
4478       ZX = x;
4479       ZY = y;
4480       DrawLevelField(x, y);
4481       return MF_ACTION;
4482       break;
4483
4484     case EL_SP_TERMINAL:
4485       {
4486         int xx, yy;
4487
4488         for (yy=0; yy<lev_fieldy; yy++)
4489         {
4490           for (xx=0; xx<lev_fieldx; xx++)
4491           {
4492             if (Feld[xx][yy] == EL_SP_DISK_YELLOW)
4493               Bang(xx, yy);
4494             else if (Feld[xx][yy] == EL_SP_TERMINAL)
4495               Feld[xx][yy] = EL_SP_TERMINAL_ACTIVE;
4496           }
4497         }
4498
4499         return MF_ACTION;
4500       }
4501       break;
4502
4503     case EL_SP_EXIT:
4504       if (local_player->gems_still_needed > 0)
4505         return MF_NO_ACTION;
4506
4507       player->LevelSolved = player->GameOver = TRUE;
4508       PlaySoundStereo(SND_SP_EXIT, PSND_MAX_RIGHT);
4509       break;
4510
4511     case EL_FELSBROCKEN:
4512     case EL_BOMBE:
4513     case EL_KOKOSNUSS:
4514     case EL_ZEIT_LEER:
4515     case EL_SP_ZONK:
4516     case EL_SP_DISK_ORANGE:
4517       if (dy || mode == DF_SNAP)
4518         return MF_NO_ACTION;
4519
4520       player->Pushing = TRUE;
4521
4522       if (!IN_LEV_FIELD(x+dx, y+dy) || !IS_FREE(x+dx, y+dy))
4523         return MF_NO_ACTION;
4524
4525       if (real_dy)
4526       {
4527         if (IN_LEV_FIELD(jx, jy+real_dy) && !IS_SOLID(Feld[jx][jy+real_dy]))
4528           return MF_NO_ACTION;
4529       }
4530
4531       if (player->push_delay == 0)
4532         player->push_delay = FrameCounter;
4533       if (!FrameReached(&player->push_delay, player->push_delay_value) &&
4534           !tape.playing)
4535         return MF_NO_ACTION;
4536
4537       RemoveField(x, y);
4538       Feld[x+dx][y+dy] = element;
4539
4540       player->push_delay_value = 2+RND(8);
4541
4542       DrawLevelField(x+dx, y+dy);
4543       if (element == EL_FELSBROCKEN)
4544         PlaySoundLevel(x+dx, y+dy, SND_PUSCH);
4545       else if (element == EL_KOKOSNUSS)
4546         PlaySoundLevel(x+dx, y+dy, SND_KNURK);
4547       else if (IS_SP_ELEMENT(element))
4548         PlaySoundLevel(x+dx, y+dy, SND_SP_ZONKPUSH);
4549       else
4550         PlaySoundLevel(x+dx, y+dy, SND_KLOPF);
4551       break;
4552
4553     case EL_PFORTE1:
4554     case EL_PFORTE2:
4555     case EL_PFORTE3:
4556     case EL_PFORTE4:
4557       if (!player->key[element - EL_PFORTE1])
4558         return MF_NO_ACTION;
4559       break;
4560
4561     case EL_PFORTE1X:
4562     case EL_PFORTE2X:
4563     case EL_PFORTE3X:
4564     case EL_PFORTE4X:
4565       if (!player->key[element - EL_PFORTE1X])
4566         return MF_NO_ACTION;
4567       break;
4568
4569     case EL_EM_GATE_1:
4570     case EL_EM_GATE_2:
4571     case EL_EM_GATE_3:
4572     case EL_EM_GATE_4:
4573       if (!player->key[element - EL_EM_GATE_1])
4574         return MF_NO_ACTION;
4575       if (!IN_LEV_FIELD(x + dx, y + dy) || !IS_FREE(x + dx, y + dy))
4576         return MF_NO_ACTION;
4577
4578       /* automatically move to the next field with double speed */
4579       player->programmed_action = move_direction;
4580       DOUBLE_PLAYER_SPEED(player);
4581
4582       break;
4583
4584     case EL_EM_GATE_1X:
4585     case EL_EM_GATE_2X:
4586     case EL_EM_GATE_3X:
4587     case EL_EM_GATE_4X:
4588       if (!player->key[element - EL_EM_GATE_1X])
4589         return MF_NO_ACTION;
4590       if (!IN_LEV_FIELD(x + dx, y + dy) || !IS_FREE(x + dx, y + dy))
4591         return MF_NO_ACTION;
4592
4593       /* automatically move to the next field with double speed */
4594       player->programmed_action = move_direction;
4595       DOUBLE_PLAYER_SPEED(player);
4596
4597       break;
4598
4599     case EL_SP_PORT1_LEFT:
4600     case EL_SP_PORT2_LEFT:
4601     case EL_SP_PORT1_RIGHT:
4602     case EL_SP_PORT2_RIGHT:
4603     case EL_SP_PORT1_UP:
4604     case EL_SP_PORT2_UP:
4605     case EL_SP_PORT1_DOWN:
4606     case EL_SP_PORT2_DOWN:
4607     case EL_SP_PORT_X:
4608     case EL_SP_PORT_Y:
4609     case EL_SP_PORT_XY:
4610       if ((dx == -1 &&
4611            element != EL_SP_PORT1_LEFT &&
4612            element != EL_SP_PORT2_LEFT &&
4613            element != EL_SP_PORT_X &&
4614            element != EL_SP_PORT_XY) ||
4615           (dx == +1 &&
4616            element != EL_SP_PORT1_RIGHT &&
4617            element != EL_SP_PORT2_RIGHT &&
4618            element != EL_SP_PORT_X &&
4619            element != EL_SP_PORT_XY) ||
4620           (dy == -1 &&
4621            element != EL_SP_PORT1_UP &&
4622            element != EL_SP_PORT2_UP &&
4623            element != EL_SP_PORT_Y &&
4624            element != EL_SP_PORT_XY) ||
4625           (dy == +1 &&
4626            element != EL_SP_PORT1_DOWN &&
4627            element != EL_SP_PORT2_DOWN &&
4628            element != EL_SP_PORT_Y &&
4629            element != EL_SP_PORT_XY) ||
4630           !IN_LEV_FIELD(x + dx, y + dy) ||
4631           !IS_FREE(x + dx, y + dy))
4632         return MF_NO_ACTION;
4633
4634       /* automatically move to the next field with double speed */
4635       player->programmed_action = move_direction;
4636       DOUBLE_PLAYER_SPEED(player);
4637
4638       break;
4639
4640     case EL_AUSGANG_ZU:
4641     case EL_AUSGANG_ACT:
4642       /* door is not (yet) open */
4643       return MF_NO_ACTION;
4644       break;
4645
4646     case EL_AUSGANG_AUF:
4647       if (mode == DF_SNAP)
4648         return MF_NO_ACTION;
4649
4650       PlaySoundLevel(x, y, SND_BUING);
4651
4652       break;
4653
4654     case EL_BIRNE_AUS:
4655       Feld[x][y] = EL_BIRNE_EIN;
4656       local_player->lights_still_needed--;
4657       DrawLevelField(x, y);
4658       PlaySoundLevel(x, y, SND_DENG);
4659       return MF_ACTION;
4660       break;
4661
4662     case EL_ZEIT_VOLL:
4663       Feld[x][y] = EL_ZEIT_LEER;
4664       TimeLeft += 10;
4665       DrawText(DX_TIME, DY_TIME, int2str(TimeLeft, 3), FS_SMALL, FC_YELLOW);
4666       DrawLevelField(x, y);
4667       PlaySoundStereo(SND_GONG, PSND_MAX_RIGHT);
4668       return MF_ACTION;
4669       break;
4670
4671     case EL_SOKOBAN_FELD_LEER:
4672       break;
4673
4674     case EL_SOKOBAN_FELD_VOLL:
4675     case EL_SOKOBAN_OBJEKT:
4676     case EL_SONDE:
4677     case EL_SP_DISK_YELLOW:
4678       if (mode == DF_SNAP)
4679         return MF_NO_ACTION;
4680
4681       player->Pushing = TRUE;
4682
4683       if (!IN_LEV_FIELD(x+dx, y+dy)
4684           || (!IS_FREE(x+dx, y+dy)
4685               && (Feld[x+dx][y+dy] != EL_SOKOBAN_FELD_LEER
4686                   || !IS_SB_ELEMENT(element))))
4687         return MF_NO_ACTION;
4688
4689       if (dx && real_dy)
4690       {
4691         if (IN_LEV_FIELD(jx, jy+real_dy) && !IS_SOLID(Feld[jx][jy+real_dy]))
4692           return MF_NO_ACTION;
4693       }
4694       else if (dy && real_dx)
4695       {
4696         if (IN_LEV_FIELD(jx+real_dx, jy) && !IS_SOLID(Feld[jx+real_dx][jy]))
4697           return MF_NO_ACTION;
4698       }
4699
4700       if (player->push_delay == 0)
4701         player->push_delay = FrameCounter;
4702       if (!FrameReached(&player->push_delay, player->push_delay_value) &&
4703           !tape.playing)
4704         return MF_NO_ACTION;
4705
4706       if (IS_SB_ELEMENT(element))
4707       {
4708         if (element == EL_SOKOBAN_FELD_VOLL)
4709         {
4710           Feld[x][y] = EL_SOKOBAN_FELD_LEER;
4711           local_player->sokobanfields_still_needed++;
4712         }
4713         else
4714           RemoveField(x, y);
4715
4716         if (Feld[x+dx][y+dy] == EL_SOKOBAN_FELD_LEER)
4717         {
4718           Feld[x+dx][y+dy] = EL_SOKOBAN_FELD_VOLL;
4719           local_player->sokobanfields_still_needed--;
4720           if (element == EL_SOKOBAN_OBJEKT)
4721             PlaySoundLevel(x, y, SND_DENG);
4722         }
4723         else
4724           Feld[x+dx][y+dy] = EL_SOKOBAN_OBJEKT;
4725       }
4726       else
4727       {
4728         RemoveField(x, y);
4729         Feld[x+dx][y+dy] = element;
4730       }
4731
4732       player->push_delay_value = 2;
4733
4734       DrawLevelField(x, y);
4735       DrawLevelField(x+dx, y+dy);
4736       PlaySoundLevel(x+dx, y+dy, SND_PUSCH);
4737
4738       if (IS_SB_ELEMENT(element) &&
4739           local_player->sokobanfields_still_needed == 0 &&
4740           game.emulation == EMU_SOKOBAN)
4741       {
4742         player->LevelSolved = player->GameOver = TRUE;
4743         PlaySoundLevel(x, y, SND_BUING);
4744       }
4745
4746       break;
4747
4748     case EL_MAULWURF:
4749     case EL_PINGUIN:
4750     case EL_SCHWEIN:
4751     case EL_DRACHE:
4752       break;
4753
4754     default:
4755       return MF_NO_ACTION;
4756   }
4757
4758   player->push_delay = 0;
4759
4760   return MF_MOVING;
4761 }
4762
4763 boolean SnapField(struct PlayerInfo *player, int dx, int dy)
4764 {
4765   int jx = player->jx, jy = player->jy;
4766   int x = jx + dx, y = jy + dy;
4767
4768   if (!player->active || !IN_LEV_FIELD(x, y))
4769     return FALSE;
4770
4771   if (dx && dy)
4772     return FALSE;
4773
4774   if (!dx && !dy)
4775   {
4776     player->snapped = FALSE;
4777     return FALSE;
4778   }
4779
4780   if (player->snapped)
4781     return FALSE;
4782
4783   player->MovDir = (dx < 0 ? MV_LEFT :
4784                     dx > 0 ? MV_RIGHT :
4785                     dy < 0 ? MV_UP :
4786                     dy > 0 ? MV_DOWN :  MV_NO_MOVING);
4787
4788   if (!DigField(player, x, y, 0, 0, DF_SNAP))
4789     return FALSE;
4790
4791   player->snapped = TRUE;
4792   DrawLevelField(x, y);
4793   BackToFront();
4794
4795   return TRUE;
4796 }
4797
4798 boolean PlaceBomb(struct PlayerInfo *player)
4799 {
4800   int jx = player->jx, jy = player->jy;
4801   int element;
4802
4803   if (!player->active || player->MovPos)
4804     return FALSE;
4805
4806   element = Feld[jx][jy];
4807
4808   if ((player->dynamite == 0 && player->dynabombs_left == 0) ||
4809       IS_ACTIVE_BOMB(element) || element == EL_EXPLODING)
4810     return FALSE;
4811
4812   if (element != EL_LEERRAUM)
4813     Store[jx][jy] = element;
4814
4815   if (player->dynamite)
4816   {
4817     Feld[jx][jy] = EL_DYNAMITE_ACTIVE;
4818     MovDelay[jx][jy] = 96;
4819     player->dynamite--;
4820     DrawText(DX_DYNAMITE, DY_DYNAMITE, int2str(local_player->dynamite, 3),
4821              FS_SMALL, FC_YELLOW);
4822     if (IN_SCR_FIELD(SCREENX(jx), SCREENY(jy)))
4823     {
4824       if (game.emulation == EMU_SUPAPLEX)
4825         DrawGraphic(SCREENX(jx), SCREENY(jy), GFX_SP_DISK_RED);
4826       else
4827         DrawGraphicThruMask(SCREENX(jx), SCREENY(jy), GFX_DYNAMIT);
4828     }
4829   }
4830   else
4831   {
4832     Feld[jx][jy] = EL_DYNABOMB_ACTIVE_1 + (player->element_nr - EL_SPIELER1);
4833     MovDelay[jx][jy] = 96;
4834     player->dynabombs_left--;
4835     if (IN_SCR_FIELD(SCREENX(jx), SCREENY(jy)))
4836       DrawGraphicThruMask(SCREENX(jx), SCREENY(jy), GFX_DYNABOMB);
4837   }
4838
4839   return TRUE;
4840 }
4841
4842 void PlaySoundLevel(int x, int y, int sound_nr)
4843 {
4844   int sx = SCREENX(x), sy = SCREENY(y);
4845   int volume, stereo;
4846   int silence_distance = 8;
4847
4848   if ((!setup.sound_simple && !IS_LOOP_SOUND(sound_nr)) ||
4849       (!setup.sound_loops && IS_LOOP_SOUND(sound_nr)))
4850     return;
4851
4852   if (!IN_LEV_FIELD(x, y) ||
4853       sx < -silence_distance || sx >= SCR_FIELDX+silence_distance ||
4854       sy < -silence_distance || sy >= SCR_FIELDY+silence_distance)
4855     return;
4856
4857   volume = PSND_MAX_VOLUME;
4858
4859 #ifndef MSDOS
4860   stereo = (sx - SCR_FIELDX/2) * 12;
4861 #else
4862   stereo = PSND_MIDDLE + (2 * sx - (SCR_FIELDX - 1)) * 5;
4863   if (stereo > PSND_MAX_RIGHT)
4864     stereo = PSND_MAX_RIGHT;
4865   if (stereo < PSND_MAX_LEFT)
4866     stereo = PSND_MAX_LEFT;
4867 #endif
4868
4869   if (!IN_SCR_FIELD(sx, sy))
4870   {
4871     int dx = ABS(sx - SCR_FIELDX/2) - SCR_FIELDX/2;
4872     int dy = ABS(sy - SCR_FIELDY/2) - SCR_FIELDY/2;
4873
4874     volume -= volume * (dx > dy ? dx : dy) / silence_distance;
4875   }
4876
4877   PlaySoundExt(sound_nr, volume, stereo, PSND_NO_LOOP);
4878 }
4879
4880 void RaiseScore(int value)
4881 {
4882   local_player->score += value;
4883   DrawText(DX_SCORE, DY_SCORE, int2str(local_player->score, 5),
4884            FS_SMALL, FC_YELLOW);
4885 }
4886
4887 void RaiseScoreElement(int element)
4888 {
4889   switch(element)
4890   {
4891     case EL_EDELSTEIN:
4892     case EL_EDELSTEIN_BD:
4893     case EL_EDELSTEIN_GELB:
4894     case EL_EDELSTEIN_ROT:
4895     case EL_EDELSTEIN_LILA:
4896       RaiseScore(level.score[SC_EDELSTEIN]);
4897       break;
4898     case EL_DIAMANT:
4899       RaiseScore(level.score[SC_DIAMANT]);
4900       break;
4901     case EL_KAEFER:
4902     case EL_BUTTERFLY:
4903       RaiseScore(level.score[SC_KAEFER]);
4904       break;
4905     case EL_FLIEGER:
4906     case EL_FIREFLY:
4907       RaiseScore(level.score[SC_FLIEGER]);
4908       break;
4909     case EL_MAMPFER:
4910     case EL_MAMPFER2:
4911       RaiseScore(level.score[SC_MAMPFER]);
4912       break;
4913     case EL_ROBOT:
4914       RaiseScore(level.score[SC_ROBOT]);
4915       break;
4916     case EL_PACMAN:
4917       RaiseScore(level.score[SC_PACMAN]);
4918       break;
4919     case EL_KOKOSNUSS:
4920       RaiseScore(level.score[SC_KOKOSNUSS]);
4921       break;
4922     case EL_DYNAMITE_INACTIVE:
4923       RaiseScore(level.score[SC_DYNAMIT]);
4924       break;
4925     case EL_SCHLUESSEL:
4926       RaiseScore(level.score[SC_SCHLUESSEL]);
4927       break;
4928     default:
4929       break;
4930   }
4931 }
4932
4933 /* ---------- new game button stuff ---------------------------------------- */
4934
4935 /* graphic position values for game buttons */
4936 #define GAME_BUTTON_XSIZE       30
4937 #define GAME_BUTTON_YSIZE       30
4938 #define GAME_BUTTON_XPOS        5
4939 #define GAME_BUTTON_YPOS        215
4940 #define SOUND_BUTTON_XPOS       5
4941 #define SOUND_BUTTON_YPOS       (GAME_BUTTON_YPOS + GAME_BUTTON_YSIZE)
4942
4943 #define GAME_BUTTON_STOP_XPOS   (GAME_BUTTON_XPOS + 0 * GAME_BUTTON_XSIZE)
4944 #define GAME_BUTTON_PAUSE_XPOS  (GAME_BUTTON_XPOS + 1 * GAME_BUTTON_XSIZE)
4945 #define GAME_BUTTON_PLAY_XPOS   (GAME_BUTTON_XPOS + 2 * GAME_BUTTON_XSIZE)
4946 #define SOUND_BUTTON_MUSIC_XPOS (SOUND_BUTTON_XPOS + 0 * GAME_BUTTON_XSIZE)
4947 #define SOUND_BUTTON_LOOPS_XPOS (SOUND_BUTTON_XPOS + 1 * GAME_BUTTON_XSIZE)
4948 #define SOUND_BUTTON_SIMPLE_XPOS (SOUND_BUTTON_XPOS + 2 * GAME_BUTTON_XSIZE)
4949
4950 static struct
4951 {
4952   int x, y;
4953   int gadget_id;
4954   char *infotext;
4955 } gamebutton_info[NUM_GAME_BUTTONS] =
4956 {
4957   {
4958     GAME_BUTTON_STOP_XPOS,      GAME_BUTTON_YPOS,
4959     GAME_CTRL_ID_STOP,
4960     "stop game"
4961   },
4962   {
4963     GAME_BUTTON_PAUSE_XPOS,     GAME_BUTTON_YPOS,
4964     GAME_CTRL_ID_PAUSE,
4965     "pause game"
4966   },
4967   {
4968     GAME_BUTTON_PLAY_XPOS,      GAME_BUTTON_YPOS,
4969     GAME_CTRL_ID_PLAY,
4970     "play game"
4971   },
4972   {
4973     SOUND_BUTTON_MUSIC_XPOS,    SOUND_BUTTON_YPOS,
4974     SOUND_CTRL_ID_MUSIC,
4975     "background music on/off"
4976   },
4977   {
4978     SOUND_BUTTON_LOOPS_XPOS,    SOUND_BUTTON_YPOS,
4979     SOUND_CTRL_ID_LOOPS,
4980     "sound loops on/off"
4981   },
4982   {
4983     SOUND_BUTTON_SIMPLE_XPOS,   SOUND_BUTTON_YPOS,
4984     SOUND_CTRL_ID_SIMPLE,
4985     "normal sounds on/off"
4986   }
4987 };
4988
4989 void CreateGameButtons()
4990 {
4991   int i;
4992
4993   for (i=0; i<NUM_GAME_BUTTONS; i++)
4994   {
4995     Pixmap gd_pixmap = pix[PIX_DOOR];
4996     struct GadgetInfo *gi;
4997     int button_type;
4998     boolean checked;
4999     unsigned long event_mask;
5000     int gd_xoffset, gd_yoffset;
5001     int gd_x1, gd_x2, gd_y1, gd_y2;
5002     int id = i;
5003
5004     gd_xoffset = gamebutton_info[i].x;
5005     gd_yoffset = gamebutton_info[i].y;
5006     gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
5007     gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
5008
5009     if (id == GAME_CTRL_ID_STOP ||
5010         id == GAME_CTRL_ID_PAUSE ||
5011         id == GAME_CTRL_ID_PLAY)
5012     {
5013       button_type = GD_TYPE_NORMAL_BUTTON;
5014       checked = FALSE;
5015       event_mask = GD_EVENT_RELEASED;
5016       gd_y1  = DOOR_GFX_PAGEY1 + gd_yoffset - GAME_BUTTON_YSIZE;
5017       gd_y2  = DOOR_GFX_PAGEY1 + gd_yoffset - GAME_BUTTON_YSIZE;
5018     }
5019     else
5020     {
5021       button_type = GD_TYPE_CHECK_BUTTON;
5022       checked =
5023         ((id == SOUND_CTRL_ID_MUSIC && setup.sound_music) ||
5024          (id == SOUND_CTRL_ID_LOOPS && setup.sound_loops) ||
5025          (id == SOUND_CTRL_ID_SIMPLE && setup.sound_simple) ? TRUE : FALSE);
5026       event_mask = GD_EVENT_PRESSED;
5027       gd_y1  = DOOR_GFX_PAGEY1 + gd_yoffset;
5028       gd_y2  = DOOR_GFX_PAGEY1 + gd_yoffset - GAME_BUTTON_YSIZE;
5029     }
5030
5031     gi = CreateGadget(GDI_CUSTOM_ID, id,
5032                       GDI_INFO_TEXT, gamebutton_info[i].infotext,
5033                       GDI_X, DX + gd_xoffset,
5034                       GDI_Y, DY + gd_yoffset,
5035                       GDI_WIDTH, GAME_BUTTON_XSIZE,
5036                       GDI_HEIGHT, GAME_BUTTON_YSIZE,
5037                       GDI_TYPE, button_type,
5038                       GDI_STATE, GD_BUTTON_UNPRESSED,
5039                       GDI_CHECKED, checked,
5040                       GDI_DESIGN_UNPRESSED, gd_pixmap, gd_x1, gd_y1,
5041                       GDI_DESIGN_PRESSED, gd_pixmap, gd_x2, gd_y1,
5042                       GDI_ALT_DESIGN_UNPRESSED, gd_pixmap, gd_x1, gd_y2,
5043                       GDI_ALT_DESIGN_PRESSED, gd_pixmap, gd_x2, gd_y2,
5044                       GDI_EVENT_MASK, event_mask,
5045                       GDI_CALLBACK_ACTION, HandleGameButtons,
5046                       GDI_END);
5047
5048     if (gi == NULL)
5049       Error(ERR_EXIT, "cannot create gadget");
5050
5051     game_gadget[id] = gi;
5052   }
5053 }
5054
5055 static void MapGameButtons()
5056 {
5057   int i;
5058
5059   for (i=0; i<NUM_GAME_BUTTONS; i++)
5060     MapGadget(game_gadget[i]);
5061 }
5062
5063 void UnmapGameButtons()
5064 {
5065   int i;
5066
5067   for (i=0; i<NUM_GAME_BUTTONS; i++)
5068     UnmapGadget(game_gadget[i]);
5069 }
5070
5071 static void HandleGameButtons(struct GadgetInfo *gi)
5072 {
5073   int id = gi->custom_id;
5074
5075   if (game_status != PLAYING)
5076     return;
5077
5078   switch (id)
5079   {
5080     case GAME_CTRL_ID_STOP:
5081       if (AllPlayersGone)
5082       {
5083         CloseDoor(DOOR_CLOSE_1);
5084         game_status = MAINMENU;
5085         DrawMainMenu();
5086         break;
5087       }
5088
5089       if (level_editor_test_game ||
5090           Request("Do you really want to quit the game ?",
5091                   REQ_ASK | REQ_STAY_CLOSED))
5092       { 
5093 #ifndef MSDOS
5094         if (options.network)
5095           SendToServer_StopPlaying();
5096         else
5097 #endif
5098         {
5099           game_status = MAINMENU;
5100           DrawMainMenu();
5101         }
5102       }
5103       else
5104         OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
5105       break;
5106
5107     case GAME_CTRL_ID_PAUSE:
5108       if (options.network)
5109       {
5110 #ifndef MSDOS
5111         if (tape.pausing)
5112           SendToServer_ContinuePlaying();
5113         else
5114           SendToServer_PausePlaying();
5115 #endif
5116       }
5117       else
5118         TapeTogglePause();
5119       break;
5120
5121     case GAME_CTRL_ID_PLAY:
5122       if (tape.pausing)
5123       {
5124 #ifndef MSDOS
5125         if (options.network)
5126           SendToServer_ContinuePlaying();
5127         else
5128 #endif
5129         {
5130           tape.pausing = FALSE;
5131           DrawVideoDisplay(VIDEO_STATE_PAUSE_OFF,0);
5132         }
5133       }
5134       break;
5135
5136     case SOUND_CTRL_ID_MUSIC:
5137       if (setup.sound_music)
5138       { 
5139         setup.sound_music = FALSE;
5140         FadeSound(background_loop[level_nr % num_bg_loops]);
5141       }
5142       else if (sound_loops_allowed)
5143       { 
5144         setup.sound = setup.sound_music = TRUE;
5145         PlaySoundLoop(background_loop[level_nr % num_bg_loops]);
5146       }
5147       break;
5148
5149     case SOUND_CTRL_ID_LOOPS:
5150       if (setup.sound_loops)
5151         setup.sound_loops = FALSE;
5152       else if (sound_loops_allowed)
5153         setup.sound = setup.sound_loops = TRUE;
5154       break;
5155
5156     case SOUND_CTRL_ID_SIMPLE:
5157       if (setup.sound_simple)
5158         setup.sound_simple = FALSE;
5159       else if (sound_status==SOUND_AVAILABLE)
5160         setup.sound = setup.sound_simple = TRUE;
5161       break;
5162
5163     default:
5164       break;
5165   }
5166 }