78b950c28033f86c51620e6341ab11c62863561b
[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_DYNAMIT:
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 = 0;
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
592 #if 1
593
594   if (setup.soft_scrolling)
595     XCopyArea(display, fieldbuffer, backbuffer, gc,
596               FX, FY, SXSIZE, SYSIZE, SX, SY);
597
598   redraw_mask |= REDRAW_FROM_BACKBUFFER;
599
600 #endif
601
602
603   /* copy default game door content to main double buffer */
604   XCopyArea(display, pix[PIX_DOOR], drawto, gc,
605             DOOR_GFX_PAGEX5, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE, DX, DY);
606
607   if (level_nr < 100)
608     DrawText(DX + XX_LEVEL, DY + YY_LEVEL,
609              int2str(level_nr, 2), FS_SMALL, FC_YELLOW);
610   else
611     DrawText(DX + XX_LEVEL - 1, DY + YY_LEVEL + 1,
612              int2str(level_nr, 3), FS_SMALL, FC_SPECIAL3);
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_DYNAMIT)
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 (Feld[x][y] == EL_DYNAMIT && !(MovDelay[x][y] % 12))
1087         DrawDynamite(x, y);
1088       else if (Feld[x][y] == EL_DYNABOMB && !(MovDelay[x][y] % 6))
1089         DrawDynamite(x, y);
1090
1091       return;
1092     }
1093   }
1094
1095   StopSound(SND_ZISCH);
1096   Bang(x, y);
1097 }
1098
1099 void Explode(int ex, int ey, int phase, int mode)
1100 {
1101   int x, y;
1102   int num_phase = 9, delay = 2;
1103   int last_phase = num_phase * delay;
1104   int half_phase = (num_phase / 2) * delay;
1105   int first_phase_after_start = EX_PHASE_START + 1;
1106
1107   if (phase == EX_PHASE_START)          /* initialize 'Store[][]' field */
1108   {
1109     int center_element = Feld[ex][ey];
1110
1111     if (IS_MOVING(ex, ey) || IS_BLOCKED(ex, ey))
1112     {
1113       center_element = MovingOrBlocked2Element(ex, ey);
1114       RemoveMovingField(ex, ey);
1115     }
1116
1117     for (y=ey-1; y<ey+2; y++) for(x=ex-1; x<ex+2; x++)
1118     {
1119       int element = Feld[x][y];
1120
1121       if (IS_MOVING(x, y) || IS_BLOCKED(x, y))
1122       {
1123         element = MovingOrBlocked2Element(x, y);
1124         RemoveMovingField(x, y);
1125       }
1126
1127       if (!IN_LEV_FIELD(x, y) || IS_MASSIVE(element) || element == EL_BURNING)
1128         continue;
1129
1130       if ((mode!=EX_NORMAL || center_element == EL_AMOEBA2DIAM) &&
1131           (x!=ex || y!=ey))
1132         continue;
1133
1134       if (element == EL_EXPLODING)
1135         element = Store2[x][y];
1136
1137       if (IS_PLAYER(ex, ey))
1138       {
1139         switch(StorePlayer[ex][ey])
1140         {
1141           case EL_SPIELER2:
1142             Store[x][y] = EL_EDELSTEIN_ROT;
1143             break;
1144           case EL_SPIELER3:
1145             Store[x][y] = EL_EDELSTEIN;
1146             break;
1147           case EL_SPIELER4:
1148             Store[x][y] = EL_EDELSTEIN_LILA;
1149             break;
1150           case EL_SPIELER1:
1151           default:
1152             Store[x][y] = EL_EDELSTEIN_GELB;
1153             break;
1154         }
1155
1156         if (game.emulation == EMU_SUPAPLEX)
1157           Store[x][y] = EL_LEERRAUM;
1158       }
1159       else if (center_element == EL_MAULWURF)
1160         Store[x][y] = EL_EDELSTEIN_ROT;
1161       else if (center_element == EL_PINGUIN)
1162         Store[x][y] = EL_EDELSTEIN_LILA;
1163       else if (center_element == EL_KAEFER)
1164         Store[x][y] = ((x == ex && y == ey) ? EL_DIAMANT : EL_EDELSTEIN);
1165       else if (center_element == EL_BUTTERFLY)
1166         Store[x][y] = EL_EDELSTEIN_BD;
1167       else if (center_element == EL_SP_ELECTRON)
1168         Store[x][y] = EL_SP_INFOTRON;
1169       else if (center_element == EL_MAMPFER)
1170         Store[x][y] = level.yam_content[game.yam_content_nr][x-ex+1][y-ey+1];
1171       else if (center_element == EL_AMOEBA2DIAM)
1172         Store[x][y] = level.amoeba_content;
1173       else if (element == EL_ERZ_EDEL)
1174         Store[x][y] = EL_EDELSTEIN;
1175       else if (element == EL_ERZ_DIAM)
1176         Store[x][y] = EL_DIAMANT;
1177       else if (element == EL_ERZ_EDEL_BD)
1178         Store[x][y] = EL_EDELSTEIN_BD;
1179       else if (element == EL_ERZ_EDEL_GELB)
1180         Store[x][y] = EL_EDELSTEIN_GELB;
1181       else if (element == EL_ERZ_EDEL_ROT)
1182         Store[x][y] = EL_EDELSTEIN_ROT;
1183       else if (element == EL_ERZ_EDEL_LILA)
1184         Store[x][y] = EL_EDELSTEIN_LILA;
1185       else if (!IS_PFORTE(Store[x][y]))
1186         Store[x][y] = EL_LEERRAUM;
1187
1188       if (x != ex || y != ey ||
1189           center_element == EL_AMOEBA2DIAM || mode == EX_BORDER)
1190         Store2[x][y] = element;
1191
1192       if (AmoebaNr[x][y] &&
1193           (element == EL_AMOEBE_VOLL ||
1194            element == EL_AMOEBE_BD ||
1195            element == EL_AMOEBING))
1196       {
1197         AmoebaCnt[AmoebaNr[x][y]]--;
1198         AmoebaCnt2[AmoebaNr[x][y]]--;
1199       }
1200
1201       Feld[x][y] = EL_EXPLODING;
1202       MovDir[x][y] = MovPos[x][y] = 0;
1203       AmoebaNr[x][y] = 0;
1204       Frame[x][y] = 1;
1205       Stop[x][y] = TRUE;
1206     }
1207
1208     if (center_element == EL_MAMPFER)
1209       game.yam_content_nr = (game.yam_content_nr + 1) % level.num_yam_contents;
1210
1211     return;
1212   }
1213
1214   if (Stop[ex][ey])
1215     return;
1216
1217   x = ex;
1218   y = ey;
1219
1220   Frame[x][y] = (phase < last_phase ? phase + 1 : 0);
1221
1222   if (phase == first_phase_after_start)
1223   {
1224     int element = Store2[x][y];
1225
1226     if (element == EL_BLACK_ORB)
1227     {
1228       Feld[x][y] = Store2[x][y];
1229       Store2[x][y] = 0;
1230       Bang(x, y);
1231     }
1232   }
1233   else if (phase == half_phase)
1234   {
1235     int element = Store2[x][y];
1236
1237     if (IS_PLAYER(x, y))
1238       KillHero(PLAYERINFO(x, y));
1239     else if (IS_EXPLOSIVE(element))
1240     {
1241       Feld[x][y] = Store2[x][y];
1242       Store2[x][y] = 0;
1243       Bang(x, y);
1244     }
1245     else if (element == EL_AMOEBA2DIAM)
1246       AmoebeUmwandeln(x, y);
1247   }
1248
1249   if (phase == last_phase)
1250   {
1251     int element;
1252
1253     element = Feld[x][y] = Store[x][y];
1254     Store[x][y] = Store2[x][y] = 0;
1255     MovDir[x][y] = MovPos[x][y] = MovDelay[x][y] = 0;
1256     InitField(x, y, FALSE);
1257     if (CAN_MOVE(element) || COULD_MOVE(element))
1258       InitMovDir(x, y);
1259     DrawLevelField(x, y);
1260   }
1261   else if (!(phase % delay) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1262   {
1263     int graphic = GFX_EXPLOSION;
1264
1265     if (game.emulation == EMU_SUPAPLEX)
1266       graphic = (Store[x][y] == EL_SP_INFOTRON ?
1267                  GFX_SP_EXPLODE_INFOTRON :
1268                  GFX_SP_EXPLODE_EMPTY);
1269
1270     if (phase == delay)
1271       ErdreichAnbroeckeln(SCREENX(x), SCREENY(y));
1272
1273     DrawGraphic(SCREENX(x), SCREENY(y), graphic + (phase / delay - 1));
1274   }
1275 }
1276
1277 void DynaExplode(int ex, int ey)
1278 {
1279   int i, j;
1280   struct PlayerInfo *player = &stored_player[Store2[ex][ey] - EL_SPIELER1];
1281   static int xy[4][2] =
1282   {
1283     { 0, -1 },
1284     { -1, 0 },
1285     { +1, 0 },
1286     { 0, +1 }
1287   };
1288
1289   Store2[ex][ey] = 0;   /* delete player information */
1290
1291   Explode(ex, ey, EX_PHASE_START, EX_CENTER);
1292
1293   for (i=0; i<4; i++)
1294   {
1295     for (j=1; j<=player->dynabomb_size; j++)
1296     {
1297       int x = ex+j*xy[i%4][0];
1298       int y = ey+j*xy[i%4][1];
1299       int element;
1300
1301       if (!IN_LEV_FIELD(x, y) || IS_MASSIVE(Feld[x][y]))
1302         break;
1303
1304       element = Feld[x][y];
1305       Explode(x, y, EX_PHASE_START, EX_BORDER);
1306
1307       if (element != EL_LEERRAUM &&
1308           element != EL_ERDREICH &&
1309           element != EL_EXPLODING &&
1310           !player->dynabomb_xl)
1311         break;
1312     }
1313   }
1314
1315   player->dynabombs_left++;
1316 }
1317
1318 void Bang(int x, int y)
1319 {
1320   int element = Feld[x][y];
1321
1322   if (game.emulation == EMU_SUPAPLEX)
1323     PlaySoundLevel(x, y, SND_SP_BOOOM);
1324   else
1325     PlaySoundLevel(x, y, SND_ROAAAR);
1326
1327   if (IS_PLAYER(x, y))  /* remove objects that might cause smaller explosion */
1328     element = EL_LEERRAUM;
1329
1330   switch(element)
1331   {
1332     case EL_KAEFER:
1333     case EL_FLIEGER:
1334     case EL_BUTTERFLY:
1335     case EL_FIREFLY:
1336     case EL_MAMPFER:
1337     case EL_MAMPFER2:
1338     case EL_ROBOT:
1339     case EL_PACMAN:
1340       RaiseScoreElement(element);
1341       Explode(x, y, EX_PHASE_START, EX_NORMAL);
1342       break;
1343     case EL_DYNABOMB:
1344     case EL_DYNABOMB_NR:
1345     case EL_DYNABOMB_SZ:
1346     case EL_DYNABOMB_XL:
1347       DynaExplode(x, y);
1348       break;
1349     case EL_MAULWURF:
1350     case EL_PINGUIN:
1351     case EL_BIRNE_AUS:
1352     case EL_BIRNE_EIN:
1353       Explode(x, y, EX_PHASE_START, EX_CENTER);
1354       break;
1355     default:
1356       Explode(x, y, EX_PHASE_START, EX_NORMAL);
1357       break;
1358   }
1359 }
1360
1361 void Blurb(int x, int y)
1362 {
1363   int element = Feld[x][y];
1364
1365   if (element != EL_BLURB_LEFT && element != EL_BLURB_RIGHT)    /* start */
1366   {
1367     PlaySoundLevel(x, y, SND_BLURB);
1368     if (IN_LEV_FIELD(x-1, y) && IS_FREE(x-1, y) &&
1369         (!IN_LEV_FIELD(x-1, y-1) ||
1370          !CAN_FALL(MovingOrBlocked2Element(x-1, y-1))))
1371     {
1372       Feld[x-1][y] = EL_BLURB_LEFT;
1373     }
1374     if (IN_LEV_FIELD(x+1, y) && IS_FREE(x+1, y) &&
1375         (!IN_LEV_FIELD(x+1, y-1) ||
1376          !CAN_FALL(MovingOrBlocked2Element(x+1, y-1))))
1377     {
1378       Feld[x+1][y] = EL_BLURB_RIGHT;
1379     }
1380   }
1381   else                                                          /* go on */
1382   {
1383     int graphic = (element==EL_BLURB_LEFT ? GFX_BLURB_LEFT : GFX_BLURB_RIGHT);
1384
1385     if (!MovDelay[x][y])        /* initialize animation counter */
1386       MovDelay[x][y] = 9;
1387
1388     if (MovDelay[x][y])         /* continue animation */
1389     {
1390       MovDelay[x][y]--;
1391       if (MovDelay[x][y]/2 && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1392         DrawGraphic(SCREENX(x), SCREENY(y), graphic+4-MovDelay[x][y]/2);
1393
1394       if (!MovDelay[x][y])
1395       {
1396         Feld[x][y] = EL_LEERRAUM;
1397         DrawLevelField(x, y);
1398       }
1399     }
1400   }
1401 }
1402
1403 void Impact(int x, int y)
1404 {
1405   boolean lastline = (y == lev_fieldy-1);
1406   boolean object_hit = FALSE;
1407   int element = Feld[x][y];
1408   int smashed = 0;
1409
1410   if (!lastline)        /* check if element below was hit */
1411   {
1412     if (Feld[x][y+1] == EL_PLAYER_IS_LEAVING)
1413       return;
1414
1415     object_hit = (!IS_FREE(x, y+1) && (!IS_MOVING(x, y+1) ||
1416                                       MovDir[x][y+1]!=MV_DOWN ||
1417                                       MovPos[x][y+1]<=TILEY/2));
1418     if (object_hit)
1419       smashed = MovingOrBlocked2Element(x, y+1);
1420   }
1421
1422   if (!lastline && smashed == EL_SALZSAEURE)    /* element falls into acid */
1423   {
1424     Blurb(x, y);
1425     return;
1426   }
1427
1428   if ((element == EL_BOMBE || element == EL_SP_DISK_ORANGE) &&
1429       (lastline || object_hit)) /* element is bomb */
1430   {
1431     Bang(x, y);
1432     return;
1433   }
1434
1435   if (element == EL_TROPFEN && (lastline || object_hit))        /* acid drop */
1436   {
1437     if (object_hit && IS_PLAYER(x, y+1))
1438       KillHero(PLAYERINFO(x, y+1));
1439     else if (object_hit && (smashed == EL_MAULWURF || smashed == EL_PINGUIN))
1440       Bang(x, y+1);
1441     else
1442     {
1443       Feld[x][y] = EL_AMOEBING;
1444       Store[x][y] = EL_AMOEBE_NASS;
1445     }
1446     return;
1447   }
1448
1449   if (!lastline && object_hit)          /* check which object was hit */
1450   {
1451     if (CAN_CHANGE(element) && 
1452         (smashed == EL_SIEB_INAKTIV || smashed == EL_SIEB2_INAKTIV))
1453     {
1454       int x, y;
1455       int activated_magic_wall =
1456         (smashed == EL_SIEB_INAKTIV ? EL_SIEB_LEER : EL_SIEB2_LEER);
1457
1458       /* activate magic wall / mill */
1459
1460       for (y=0; y<lev_fieldy; y++)
1461         for (x=0; x<lev_fieldx; x++)
1462           if (Feld[x][y] == smashed)
1463             Feld[x][y] = activated_magic_wall;
1464
1465       game.magic_wall_time_left = level.time_magic_wall * FRAMES_PER_SECOND;
1466       game.magic_wall_active = TRUE;
1467     }
1468
1469     if (IS_PLAYER(x, y+1))
1470     {
1471       KillHero(PLAYERINFO(x, y+1));
1472       return;
1473     }
1474     else if (smashed == EL_MAULWURF || smashed == EL_PINGUIN)
1475     {
1476       Bang(x, y+1);
1477       return;
1478     }
1479     else if (element == EL_EDELSTEIN_BD)
1480     {
1481       if (IS_ENEMY(smashed) && IS_BD_ELEMENT(smashed))
1482       {
1483         Bang(x, y+1);
1484         return;
1485       }
1486     }
1487     else if (element == EL_FELSBROCKEN || element == EL_SP_ZONK)
1488     {
1489       if (IS_ENEMY(smashed) ||
1490           smashed == EL_BOMBE || smashed == EL_SP_DISK_ORANGE ||
1491           smashed == EL_SONDE || smashed == EL_SCHWEIN || smashed == EL_DRACHE)
1492       {
1493         Bang(x, y+1);
1494         return;
1495       }
1496       else if (!IS_MOVING(x, y+1))
1497       {
1498         if (smashed == EL_BIRNE_AUS || smashed == EL_BIRNE_EIN)
1499         {
1500           Bang(x, y+1);
1501           return;
1502         }
1503         else if (smashed == EL_KOKOSNUSS)
1504         {
1505           Feld[x][y+1] = EL_CRACKINGNUT;
1506           PlaySoundLevel(x, y, SND_KNACK);
1507           RaiseScoreElement(EL_KOKOSNUSS);
1508           return;
1509         }
1510         else if (smashed == EL_DIAMANT)
1511         {
1512           Feld[x][y+1] = EL_LEERRAUM;
1513           PlaySoundLevel(x, y, SND_QUIRK);
1514           return;
1515         }
1516       }
1517     }
1518   }
1519
1520   /* play sound of magic wall / mill */
1521   if (!lastline &&
1522       (Feld[x][y+1] == EL_SIEB_LEER || Feld[x][y+1] == EL_SIEB2_LEER))
1523   {
1524     PlaySoundLevel(x, y, SND_QUIRK);
1525     return;
1526   }
1527
1528   /* play sound of object that hits the ground */
1529   if (lastline || object_hit)
1530   {
1531     int sound;
1532
1533     switch(element)
1534     {
1535       case EL_EDELSTEIN:
1536       case EL_EDELSTEIN_BD:
1537       case EL_EDELSTEIN_GELB:
1538       case EL_EDELSTEIN_ROT:
1539       case EL_EDELSTEIN_LILA:
1540       case EL_DIAMANT:
1541       case EL_SP_INFOTRON:
1542         sound = SND_PLING;
1543         break;
1544       case EL_KOKOSNUSS:
1545         sound = SND_KLUMPF;
1546         break;
1547       case EL_FELSBROCKEN:
1548         sound = SND_KLOPF;
1549         break;
1550       case EL_SP_ZONK:
1551         sound = SND_SP_ZONKDOWN;
1552         break;
1553       case EL_SCHLUESSEL:
1554       case EL_SCHLUESSEL1:
1555       case EL_SCHLUESSEL2:
1556       case EL_SCHLUESSEL3:
1557       case EL_SCHLUESSEL4:
1558       case EL_EM_KEY_1:
1559       case EL_EM_KEY_2:
1560       case EL_EM_KEY_3:
1561       case EL_EM_KEY_4:
1562         sound = SND_KINK;
1563         break;
1564       case EL_ZEIT_VOLL:
1565       case EL_ZEIT_LEER:
1566         sound = SND_DENG;
1567         break;
1568       default:
1569         sound = -1;
1570         break;
1571     }
1572
1573     if (sound>=0)
1574       PlaySoundLevel(x, y, sound);
1575   }
1576 }
1577
1578 void TurnRound(int x, int y)
1579 {
1580   static struct
1581   {
1582     int x, y;
1583   } move_xy[] =
1584   {
1585     { 0, 0 },
1586     {-1, 0 },
1587     {+1, 0 },
1588     { 0, 0 },
1589     { 0, -1 },
1590     { 0, 0 }, { 0, 0 }, { 0, 0 },
1591     { 0, +1 }
1592   };
1593   static struct
1594   {
1595     int left, right, back;
1596   } turn[] =
1597   {
1598     { 0,        0,              0 },
1599     { MV_DOWN,  MV_UP,          MV_RIGHT },
1600     { MV_UP,    MV_DOWN,        MV_LEFT },
1601     { 0,        0,              0 },
1602     { MV_LEFT,  MV_RIGHT,       MV_DOWN },
1603     { 0,0,0 },  { 0,0,0 },      { 0,0,0 },
1604     { MV_RIGHT, MV_LEFT,        MV_UP }
1605   };
1606
1607   int element = Feld[x][y];
1608   int old_move_dir = MovDir[x][y];
1609   int left_dir = turn[old_move_dir].left;
1610   int right_dir = turn[old_move_dir].right;
1611   int back_dir = turn[old_move_dir].back;
1612
1613   int left_dx = move_xy[left_dir].x, left_dy = move_xy[left_dir].y;
1614   int right_dx = move_xy[right_dir].x, right_dy = move_xy[right_dir].y;
1615   int move_dx = move_xy[old_move_dir].x, move_dy = move_xy[old_move_dir].y;
1616   int back_dx = move_xy[back_dir].x, back_dy = move_xy[back_dir].y;
1617
1618   int left_x = x+left_dx, left_y = y+left_dy;
1619   int right_x = x+right_dx, right_y = y+right_dy;
1620   int move_x = x+move_dx, move_y = y+move_dy;
1621
1622   if (element == EL_KAEFER || element == EL_BUTTERFLY)
1623   {
1624     TestIfBadThingHitsOtherBadThing(x, y);
1625
1626     if (IN_LEV_FIELD(right_x, right_y) &&
1627         IS_FREE_OR_PLAYER(right_x, right_y))
1628       MovDir[x][y] = right_dir;
1629     else if (!IN_LEV_FIELD(move_x, move_y) ||
1630              !IS_FREE_OR_PLAYER(move_x, move_y))
1631       MovDir[x][y] = left_dir;
1632
1633     if (element == EL_KAEFER && MovDir[x][y] != old_move_dir)
1634       MovDelay[x][y] = 9;
1635     else if (element == EL_BUTTERFLY)   /* && MovDir[x][y] == left_dir) */
1636       MovDelay[x][y] = 1;
1637   }
1638   else if (element == EL_FLIEGER || element == EL_FIREFLY ||
1639            element == EL_SP_SNIKSNAK || element == EL_SP_ELECTRON)
1640   {
1641     TestIfBadThingHitsOtherBadThing(x, y);
1642
1643     if (IN_LEV_FIELD(left_x, left_y) &&
1644         IS_FREE_OR_PLAYER(left_x, left_y))
1645       MovDir[x][y] = left_dir;
1646     else if (!IN_LEV_FIELD(move_x, move_y) ||
1647              !IS_FREE_OR_PLAYER(move_x, move_y))
1648       MovDir[x][y] = right_dir;
1649
1650     if ((element == EL_FLIEGER ||
1651          element == EL_SP_SNIKSNAK || element == EL_SP_ELECTRON)
1652         && MovDir[x][y] != old_move_dir)
1653       MovDelay[x][y] = 9;
1654     else if (element == EL_FIREFLY)     /* && MovDir[x][y] == right_dir) */
1655       MovDelay[x][y] = 1;
1656   }
1657   else if (element == EL_MAMPFER)
1658   {
1659     boolean can_turn_left = FALSE, can_turn_right = FALSE;
1660
1661     if (IN_LEV_FIELD(left_x, left_y) &&
1662         (IS_FREE_OR_PLAYER(left_x, left_y) ||
1663          Feld[left_x][left_y] == EL_DIAMANT))
1664       can_turn_left = TRUE;
1665     if (IN_LEV_FIELD(right_x, right_y) &&
1666         (IS_FREE_OR_PLAYER(right_x, right_y) ||
1667          Feld[right_x][right_y] == EL_DIAMANT))
1668       can_turn_right = TRUE;
1669
1670     if (can_turn_left && can_turn_right)
1671       MovDir[x][y] = (RND(3) ? (RND(2) ? left_dir : right_dir) : back_dir);
1672     else if (can_turn_left)
1673       MovDir[x][y] = (RND(2) ? left_dir : back_dir);
1674     else if (can_turn_right)
1675       MovDir[x][y] = (RND(2) ? right_dir : back_dir);
1676     else
1677       MovDir[x][y] = back_dir;
1678
1679     MovDelay[x][y] = 16+16*RND(3);
1680   }
1681   else if (element == EL_MAMPFER2)
1682   {
1683     boolean can_turn_left = FALSE, can_turn_right = FALSE;
1684
1685     if (IN_LEV_FIELD(left_x, left_y) &&
1686         (IS_FREE_OR_PLAYER(left_x, left_y) ||
1687          IS_MAMPF2(Feld[left_x][left_y])))
1688       can_turn_left = TRUE;
1689     if (IN_LEV_FIELD(right_x, right_y) &&
1690         (IS_FREE_OR_PLAYER(right_x, right_y) ||
1691          IS_MAMPF2(Feld[right_x][right_y])))
1692       can_turn_right = TRUE;
1693
1694     if (can_turn_left && can_turn_right)
1695       MovDir[x][y] = (RND(3) ? (RND(2) ? left_dir : right_dir) : back_dir);
1696     else if (can_turn_left)
1697       MovDir[x][y] = (RND(2) ? left_dir : back_dir);
1698     else if (can_turn_right)
1699       MovDir[x][y] = (RND(2) ? right_dir : back_dir);
1700     else
1701       MovDir[x][y] = back_dir;
1702
1703     MovDelay[x][y] = 16+16*RND(3);
1704   }
1705   else if (element == EL_PACMAN)
1706   {
1707     boolean can_turn_left = FALSE, can_turn_right = FALSE;
1708
1709     if (IN_LEV_FIELD(left_x, left_y) &&
1710         (IS_FREE_OR_PLAYER(left_x, left_y) ||
1711          IS_AMOEBOID(Feld[left_x][left_y])))
1712       can_turn_left = TRUE;
1713     if (IN_LEV_FIELD(right_x, right_y) &&
1714         (IS_FREE_OR_PLAYER(right_x, right_y) ||
1715          IS_AMOEBOID(Feld[right_x][right_y])))
1716       can_turn_right = TRUE;
1717
1718     if (can_turn_left && can_turn_right)
1719       MovDir[x][y] = (RND(3) ? (RND(2) ? left_dir : right_dir) : back_dir);
1720     else if (can_turn_left)
1721       MovDir[x][y] = (RND(2) ? left_dir : back_dir);
1722     else if (can_turn_right)
1723       MovDir[x][y] = (RND(2) ? right_dir : back_dir);
1724     else
1725       MovDir[x][y] = back_dir;
1726
1727     MovDelay[x][y] = 6+RND(40);
1728   }
1729   else if (element == EL_SCHWEIN)
1730   {
1731     boolean can_turn_left = FALSE, can_turn_right = FALSE, can_move_on = FALSE;
1732     boolean should_turn_left = FALSE, should_turn_right = FALSE;
1733     boolean should_move_on = FALSE;
1734     int rnd_value = 24;
1735     int rnd = RND(rnd_value);
1736
1737     if (IN_LEV_FIELD(left_x, left_y) &&
1738         (IS_FREE(left_x, left_y) || IS_GEM(Feld[left_x][left_y])))
1739       can_turn_left = TRUE;
1740     if (IN_LEV_FIELD(right_x, right_y) &&
1741         (IS_FREE(right_x, right_y) || IS_GEM(Feld[right_x][right_y])))
1742       can_turn_right = TRUE;
1743     if (IN_LEV_FIELD(move_x, move_y) &&
1744         (IS_FREE(move_x, move_y) || IS_GEM(Feld[move_x][move_y])))
1745       can_move_on = TRUE;
1746
1747     if (can_turn_left &&
1748         (!can_move_on ||
1749          (IN_LEV_FIELD(x+back_dx+left_dx, y+back_dy+left_dy) &&
1750           !IS_FREE(x+back_dx+left_dx, y+back_dy+left_dy))))
1751       should_turn_left = TRUE;
1752     if (can_turn_right &&
1753         (!can_move_on ||
1754          (IN_LEV_FIELD(x+back_dx+right_dx, y+back_dy+right_dy) &&
1755           !IS_FREE(x+back_dx+right_dx, y+back_dy+right_dy))))
1756       should_turn_right = TRUE;
1757     if (can_move_on &&
1758         (!can_turn_left || !can_turn_right ||
1759          (IN_LEV_FIELD(x+move_dx+left_dx, y+move_dy+left_dy) &&
1760           !IS_FREE(x+move_dx+left_dx, y+move_dy+left_dy)) ||
1761          (IN_LEV_FIELD(x+move_dx+right_dx, y+move_dy+right_dy) &&
1762           !IS_FREE(x+move_dx+right_dx, y+move_dy+right_dy))))
1763       should_move_on = TRUE;
1764
1765     if (should_turn_left || should_turn_right || should_move_on)
1766     {
1767       if (should_turn_left && should_turn_right && should_move_on)
1768         MovDir[x][y] = (rnd < rnd_value/3 ? left_dir :
1769                         rnd < 2*rnd_value/3 ? right_dir :
1770                         old_move_dir);
1771       else if (should_turn_left && should_turn_right)
1772         MovDir[x][y] = (rnd < rnd_value/2 ? left_dir : right_dir);
1773       else if (should_turn_left && should_move_on)
1774         MovDir[x][y] = (rnd < rnd_value/2 ? left_dir : old_move_dir);
1775       else if (should_turn_right && should_move_on)
1776         MovDir[x][y] = (rnd < rnd_value/2 ? right_dir : old_move_dir);
1777       else if (should_turn_left)
1778         MovDir[x][y] = left_dir;
1779       else if (should_turn_right)
1780         MovDir[x][y] = right_dir;
1781       else if (should_move_on)
1782         MovDir[x][y] = old_move_dir;
1783     }
1784     else if (can_move_on && rnd > rnd_value/8)
1785       MovDir[x][y] = old_move_dir;
1786     else if (can_turn_left && can_turn_right)
1787       MovDir[x][y] = (rnd < rnd_value/2 ? left_dir : right_dir);
1788     else if (can_turn_left && rnd > rnd_value/8)
1789       MovDir[x][y] = left_dir;
1790     else if (can_turn_right && rnd > rnd_value/8)
1791       MovDir[x][y] = right_dir;
1792     else
1793       MovDir[x][y] = back_dir;
1794
1795     if (!IS_FREE(x+move_xy[MovDir[x][y]].x, y+move_xy[MovDir[x][y]].y) &&
1796         !IS_GEM(Feld[x+move_xy[MovDir[x][y]].x][y+move_xy[MovDir[x][y]].y]))
1797       MovDir[x][y] = old_move_dir;
1798
1799     MovDelay[x][y] = 0;
1800   }
1801   else if (element == EL_DRACHE)
1802   {
1803     boolean can_turn_left = FALSE, can_turn_right = FALSE, can_move_on = FALSE;
1804     int rnd_value = 24;
1805     int rnd = RND(rnd_value);
1806
1807     if (IN_LEV_FIELD(left_x, left_y) && IS_FREE(left_x, left_y))
1808       can_turn_left = TRUE;
1809     if (IN_LEV_FIELD(right_x, right_y) && IS_FREE(right_x, right_y))
1810       can_turn_right = TRUE;
1811     if (IN_LEV_FIELD(move_x, move_y) && IS_FREE(move_x, move_y))
1812       can_move_on = TRUE;
1813
1814     if (can_move_on && rnd > rnd_value/8)
1815       MovDir[x][y] = old_move_dir;
1816     else if (can_turn_left && can_turn_right)
1817       MovDir[x][y] = (rnd < rnd_value/2 ? left_dir : right_dir);
1818     else if (can_turn_left && rnd > rnd_value/8)
1819       MovDir[x][y] = left_dir;
1820     else if (can_turn_right && rnd > rnd_value/8)
1821       MovDir[x][y] = right_dir;
1822     else
1823       MovDir[x][y] = back_dir;
1824
1825     if (!IS_FREE(x+move_xy[MovDir[x][y]].x, y+move_xy[MovDir[x][y]].y))
1826       MovDir[x][y] = old_move_dir;
1827
1828     MovDelay[x][y] = 0;
1829   }
1830   else if (element == EL_ROBOT || element == EL_SONDE ||
1831            element == EL_MAULWURF || element == EL_PINGUIN)
1832   {
1833     int attr_x = -1, attr_y = -1;
1834
1835     if (AllPlayersGone)
1836     {
1837       attr_x = ExitX;
1838       attr_y = ExitY;
1839     }
1840     else
1841     {
1842       int i;
1843
1844       for (i=0; i<MAX_PLAYERS; i++)
1845       {
1846         struct PlayerInfo *player = &stored_player[i];
1847         int jx = player->jx, jy = player->jy;
1848
1849         if (!player->active)
1850           continue;
1851
1852         if (attr_x == -1 || ABS(jx-x)+ABS(jy-y) < ABS(attr_x-x)+ABS(attr_y-y))
1853         {
1854           attr_x = jx;
1855           attr_y = jy;
1856         }
1857       }
1858     }
1859
1860     if (element == EL_ROBOT && ZX>=0 && ZY>=0)
1861     {
1862       attr_x = ZX;
1863       attr_y = ZY;
1864     }
1865
1866     if (element == EL_MAULWURF || element == EL_PINGUIN)
1867     {
1868       int i;
1869       static int xy[4][2] =
1870       {
1871         { 0, -1 },
1872         { -1, 0 },
1873         { +1, 0 },
1874         { 0, +1 }
1875       };
1876
1877       for (i=0; i<4; i++)
1878       {
1879         int ex = x + xy[i%4][0];
1880         int ey = y + xy[i%4][1];
1881
1882         if (IN_LEV_FIELD(ex, ey) && Feld[ex][ey] == EL_AUSGANG_AUF)
1883         {
1884           attr_x = ex;
1885           attr_y = ey;
1886           break;
1887         }
1888       }
1889     }
1890
1891     MovDir[x][y] = MV_NO_MOVING;
1892     if (attr_x<x)
1893       MovDir[x][y] |= (AllPlayersGone ? MV_RIGHT : MV_LEFT);
1894     else if (attr_x>x)
1895       MovDir[x][y] |= (AllPlayersGone ? MV_LEFT : MV_RIGHT);
1896     if (attr_y<y)
1897       MovDir[x][y] |= (AllPlayersGone ? MV_DOWN : MV_UP);
1898     else if (attr_y>y)
1899       MovDir[x][y] |= (AllPlayersGone ? MV_UP : MV_DOWN);
1900
1901     if (element == EL_ROBOT)
1902     {
1903       int newx, newy;
1904
1905       if ((MovDir[x][y]&(MV_LEFT|MV_RIGHT)) && (MovDir[x][y]&(MV_UP|MV_DOWN)))
1906         MovDir[x][y] &= (RND(2) ? (MV_LEFT|MV_RIGHT) : (MV_UP|MV_DOWN));
1907       Moving2Blocked(x, y, &newx, &newy);
1908
1909       if (IN_LEV_FIELD(newx, newy) && IS_FREE_OR_PLAYER(newx, newy))
1910         MovDelay[x][y] = 8+8*!RND(3);
1911       else
1912         MovDelay[x][y] = 16;
1913     }
1914     else
1915     {
1916       int newx, newy;
1917
1918       MovDelay[x][y] = 1;
1919
1920       if ((MovDir[x][y]&(MV_LEFT|MV_RIGHT)) && (MovDir[x][y]&(MV_UP|MV_DOWN)))
1921       {
1922         boolean first_horiz = RND(2);
1923         int new_move_dir = MovDir[x][y];
1924
1925         MovDir[x][y] =
1926           new_move_dir & (first_horiz ? (MV_LEFT|MV_RIGHT) : (MV_UP|MV_DOWN));
1927         Moving2Blocked(x, y, &newx, &newy);
1928
1929         if (IN_LEV_FIELD(newx, newy) &&
1930             (IS_FREE(newx, newy) ||
1931              Feld[newx][newy] == EL_SALZSAEURE ||
1932              ((element == EL_MAULWURF || element == EL_PINGUIN) &&
1933               (Feld[newx][newy] == EL_AUSGANG_AUF ||
1934                IS_MAMPF3(Feld[newx][newy])))))
1935           return;
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] = old_move_dir;
1950         return;
1951       }
1952     }
1953   }
1954 }
1955
1956 static boolean JustBeingPushed(int x, int y)
1957 {
1958   int i;
1959
1960   for (i=0; i<MAX_PLAYERS; i++)
1961   {
1962     struct PlayerInfo *player = &stored_player[i];
1963
1964     if (player->active && player->Pushing && player->MovPos)
1965     {
1966       int next_jx = player->jx + (player->jx - player->last_jx);
1967       int next_jy = player->jy + (player->jy - player->last_jy);
1968
1969       if (x == next_jx && y == next_jy)
1970         return TRUE;
1971     }
1972   }
1973
1974   return FALSE;
1975 }
1976
1977 void StartMoving(int x, int y)
1978 {
1979   int element = Feld[x][y];
1980
1981   if (Stop[x][y])
1982     return;
1983
1984   if (CAN_FALL(element) && y<lev_fieldy-1)
1985   {
1986     if ((x>0 && IS_PLAYER(x-1, y)) || (x<lev_fieldx-1 && IS_PLAYER(x+1, y)))
1987       if (JustBeingPushed(x, y))
1988         return;
1989
1990     if (element == EL_MORAST_VOLL)
1991     {
1992       if (IS_FREE(x, y+1))
1993       {
1994         InitMovingField(x, y, MV_DOWN);
1995         Feld[x][y] = EL_FELSBROCKEN;
1996         Store[x][y] = EL_MORAST_LEER;
1997       }
1998       else if (Feld[x][y+1] == EL_MORAST_LEER)
1999       {
2000         if (!MovDelay[x][y])
2001           MovDelay[x][y] = TILEY + 1;
2002
2003         if (MovDelay[x][y])
2004         {
2005           MovDelay[x][y]--;
2006           if (MovDelay[x][y])
2007             return;
2008         }
2009
2010         Feld[x][y] = EL_MORAST_LEER;
2011         Feld[x][y+1] = EL_MORAST_VOLL;
2012       }
2013     }
2014     else if (element == EL_FELSBROCKEN && Feld[x][y+1] == EL_MORAST_LEER)
2015     {
2016       InitMovingField(x, y, MV_DOWN);
2017       Store[x][y] = EL_MORAST_VOLL;
2018     }
2019     else if (element == EL_SIEB_VOLL)
2020     {
2021       if (IS_FREE(x, y+1))
2022       {
2023         InitMovingField(x, y, MV_DOWN);
2024         Feld[x][y] = EL_CHANGED(Store2[x][y]);
2025         Store[x][y] = EL_SIEB_LEER;
2026       }
2027       else if (Feld[x][y+1] == EL_SIEB_LEER)
2028       {
2029         if (!MovDelay[x][y])
2030           MovDelay[x][y] = TILEY/4 + 1;
2031
2032         if (MovDelay[x][y])
2033         {
2034           MovDelay[x][y]--;
2035           if (MovDelay[x][y])
2036             return;
2037         }
2038
2039         Feld[x][y] = EL_SIEB_LEER;
2040         Feld[x][y+1] = EL_SIEB_VOLL;
2041         Store2[x][y+1] = EL_CHANGED(Store2[x][y]);
2042         Store2[x][y] = 0;
2043       }
2044     }
2045     else if (element == EL_SIEB2_VOLL)
2046     {
2047       if (IS_FREE(x, y+1))
2048       {
2049         InitMovingField(x, y, MV_DOWN);
2050         Feld[x][y] = EL_CHANGED2(Store2[x][y]);
2051         Store[x][y] = EL_SIEB2_LEER;
2052       }
2053       else if (Feld[x][y+1] == EL_SIEB2_LEER)
2054       {
2055         if (!MovDelay[x][y])
2056           MovDelay[x][y] = TILEY/4 + 1;
2057
2058         if (MovDelay[x][y])
2059         {
2060           MovDelay[x][y]--;
2061           if (MovDelay[x][y])
2062             return;
2063         }
2064
2065         Feld[x][y] = EL_SIEB2_LEER;
2066         Feld[x][y+1] = EL_SIEB2_VOLL;
2067         Store2[x][y+1] = EL_CHANGED2(Store2[x][y]);
2068         Store2[x][y] = 0;
2069       }
2070     }
2071     else if (CAN_CHANGE(element) &&
2072              (Feld[x][y+1] == EL_SIEB_LEER || Feld[x][y+1] == EL_SIEB2_LEER))
2073     {
2074       InitMovingField(x, y, MV_DOWN);
2075       Store[x][y] =
2076         (Feld[x][y+1] == EL_SIEB_LEER ? EL_SIEB_VOLL : EL_SIEB2_VOLL);
2077       Store2[x][y+1] = element;
2078     }
2079     else if (CAN_SMASH(element) && Feld[x][y+1] == EL_SALZSAEURE)
2080     {
2081       Blurb(x, y);
2082       InitMovingField(x, y, MV_DOWN);
2083       Store[x][y] = EL_SALZSAEURE;
2084     }
2085     else if (CAN_SMASH(element) && Feld[x][y+1] == EL_BLOCKED && JustHit[x][y])
2086     {
2087       Impact(x, y);
2088     }
2089     else if (IS_FREE(x, y+1))
2090     {
2091       InitMovingField(x, y, MV_DOWN);
2092     }
2093     else if (element == EL_TROPFEN)
2094     {
2095       Feld[x][y] = EL_AMOEBING;
2096       Store[x][y] = EL_AMOEBE_NASS;
2097     }
2098     else if (IS_SLIPPERY(Feld[x][y+1]) && !Store[x][y+1])
2099     {
2100       boolean left  = (x>0 && IS_FREE(x-1, y) &&
2101                        (IS_FREE(x-1, y+1) || Feld[x-1][y+1] == EL_SALZSAEURE));
2102       boolean right = (x<lev_fieldx-1 && IS_FREE(x+1, y) &&
2103                        (IS_FREE(x+1, y+1) || Feld[x+1][y+1] == EL_SALZSAEURE));
2104
2105       if (left || right)
2106       {
2107         if (left && right && game.emulation != EMU_BOULDERDASH)
2108           left = !(right = RND(2));
2109
2110         InitMovingField(x, y, left ? MV_LEFT : MV_RIGHT);
2111       }
2112     }
2113   }
2114   else if (CAN_MOVE(element))
2115   {
2116     int newx, newy;
2117
2118     if (element == EL_SONDE && JustBeingPushed(x, y))
2119       return;
2120
2121     if (!MovDelay[x][y])        /* start new movement phase */
2122     {
2123       /* all objects that can change their move direction after each step */
2124       /* (MAMPFER, MAMPFER2 and PACMAN go straight until they hit a wall  */
2125
2126       if (element!=EL_MAMPFER && element!=EL_MAMPFER2 && element!=EL_PACMAN)
2127       {
2128         TurnRound(x, y);
2129         if (MovDelay[x][y] && (element == EL_KAEFER || element == EL_FLIEGER ||
2130                                element == EL_SP_SNIKSNAK ||
2131                                element == EL_SP_ELECTRON))
2132           DrawLevelField(x, y);
2133       }
2134     }
2135
2136     if (MovDelay[x][y])         /* wait some time before next movement */
2137     {
2138       MovDelay[x][y]--;
2139
2140       if (element == EL_ROBOT ||
2141           element == EL_MAMPFER || element == EL_MAMPFER2)
2142       {
2143         int phase = MovDelay[x][y] % 8;
2144
2145         if (phase>3)
2146           phase = 7-phase;
2147
2148         if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
2149           DrawGraphic(SCREENX(x), SCREENY(y), el2gfx(element)+phase);
2150
2151         if ((element == EL_MAMPFER || element == EL_MAMPFER2)
2152             && MovDelay[x][y]%4 == 3)
2153           PlaySoundLevel(x, y, SND_NJAM);
2154       }
2155       else if (element == EL_SP_ELECTRON)
2156         DrawGraphicAnimation(x, y, GFX2_SP_ELECTRON, 8, 2, ANIM_NORMAL);
2157       else if (element == EL_DRACHE)
2158       {
2159         int i;
2160         int dir = MovDir[x][y];
2161         int dx = (dir == MV_LEFT ? -1 : dir == MV_RIGHT ? +1 : 0);
2162         int dy = (dir == MV_UP   ? -1 : dir == MV_DOWN  ? +1 : 0);
2163         int graphic = (dir == MV_LEFT   ? GFX_FLAMMEN_LEFT :
2164                        dir == MV_RIGHT  ? GFX_FLAMMEN_RIGHT :
2165                        dir == MV_UP     ? GFX_FLAMMEN_UP :
2166                        dir == MV_DOWN   ? GFX_FLAMMEN_DOWN : GFX_LEERRAUM);
2167         int phase = FrameCounter % 2;
2168
2169         for (i=1; i<=3; i++)
2170         {
2171           int xx = x + i*dx, yy = y + i*dy;
2172           int sx = SCREENX(xx), sy = SCREENY(yy);
2173
2174           if (!IN_LEV_FIELD(xx, yy) ||
2175               IS_SOLID(Feld[xx][yy]) || Feld[xx][yy] == EL_EXPLODING)
2176             break;
2177
2178           if (MovDelay[x][y])
2179           {
2180             int flamed = MovingOrBlocked2Element(xx, yy);
2181
2182             if (IS_ENEMY(flamed) || IS_EXPLOSIVE(flamed))
2183               Bang(xx, yy);
2184             else
2185               RemoveMovingField(xx, yy);
2186
2187             Feld[xx][yy] = EL_BURNING;
2188             if (IN_SCR_FIELD(sx, sy))
2189               DrawGraphic(sx, sy, graphic + phase*3 + i-1);
2190           }
2191           else
2192           {
2193             if (Feld[xx][yy] == EL_BURNING)
2194               Feld[xx][yy] = EL_LEERRAUM;
2195             DrawLevelField(xx, yy);
2196           }
2197         }
2198       }
2199
2200       if (MovDelay[x][y])
2201         return;
2202     }
2203
2204     if (element == EL_KAEFER || element == EL_BUTTERFLY)
2205     {
2206       PlaySoundLevel(x, y, SND_KLAPPER);
2207     }
2208     else if (element == EL_FLIEGER || element == EL_FIREFLY)
2209     {
2210       PlaySoundLevel(x, y, SND_ROEHR);
2211     }
2212
2213     /* now make next step */
2214
2215     Moving2Blocked(x, y, &newx, &newy); /* get next screen position */
2216
2217     if (IS_ENEMY(element) && IS_PLAYER(newx, newy))
2218     {
2219       /* enemy got the player */
2220       MovDir[x][y] = 0;
2221       KillHero(PLAYERINFO(newx, newy));
2222       return;
2223     }
2224     else if ((element == EL_MAULWURF || element == EL_PINGUIN ||
2225               element == EL_ROBOT || element == EL_SONDE) &&
2226              IN_LEV_FIELD(newx, newy) &&
2227              MovDir[x][y] == MV_DOWN && Feld[newx][newy] == EL_SALZSAEURE)
2228     {
2229       Blurb(x, y);
2230       Store[x][y] = EL_SALZSAEURE;
2231     }
2232     else if ((element == EL_MAULWURF || element == EL_PINGUIN) &&
2233              IN_LEV_FIELD(newx, newy))
2234     {
2235       if (Feld[newx][newy] == EL_AUSGANG_AUF)
2236       {
2237         Feld[x][y] = EL_LEERRAUM;
2238         DrawLevelField(x, y);
2239
2240         PlaySoundLevel(newx, newy, SND_BUING);
2241         if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
2242           DrawGraphicThruMask(SCREENX(newx), SCREENY(newy), el2gfx(element));
2243
2244         local_player->friends_still_needed--;
2245         if (!local_player->friends_still_needed &&
2246             !local_player->GameOver && AllPlayersGone)
2247           local_player->LevelSolved = local_player->GameOver = TRUE;
2248
2249         return;
2250       }
2251       else if (IS_MAMPF3(Feld[newx][newy]))
2252       {
2253         if (DigField(local_player, newx, newy, 0, 0, DF_DIG) == MF_MOVING)
2254           DrawLevelField(newx, newy);
2255         else
2256           MovDir[x][y] = MV_NO_MOVING;
2257       }
2258       else if (!IS_FREE(newx, newy))
2259       {
2260         if (IS_PLAYER(x, y))
2261           DrawPlayerField(x, y);
2262         else
2263           DrawLevelField(x, y);
2264         return;
2265       }
2266     }
2267     else if (element == EL_SCHWEIN && IN_LEV_FIELD(newx, newy))
2268     {
2269       if (IS_GEM(Feld[newx][newy]))
2270       {
2271         if (IS_MOVING(newx, newy))
2272           RemoveMovingField(newx, newy);
2273         else
2274         {
2275           Feld[newx][newy] = EL_LEERRAUM;
2276           DrawLevelField(newx, newy);
2277         }
2278       }
2279       else if (!IS_FREE(newx, newy))
2280       {
2281         if (IS_PLAYER(x, y))
2282           DrawPlayerField(x, y);
2283         else
2284           DrawLevelField(x, y);
2285         return;
2286       }
2287     }
2288     else if (element == EL_DRACHE && IN_LEV_FIELD(newx, newy))
2289     {
2290       if (!IS_FREE(newx, newy))
2291       {
2292         if (IS_PLAYER(x, y))
2293           DrawPlayerField(x, y);
2294         else
2295           DrawLevelField(x, y);
2296         return;
2297       }
2298       else
2299       {
2300         boolean wanna_flame = !RND(10);
2301         int dx = newx - x, dy = newy - y;
2302         int newx1 = newx+1*dx, newy1 = newy+1*dy;
2303         int newx2 = newx+2*dx, newy2 = newy+2*dy;
2304         int element1 = (IN_LEV_FIELD(newx1, newy1) ?
2305                         MovingOrBlocked2Element(newx1, newy1) : EL_BETON);
2306         int element2 = (IN_LEV_FIELD(newx2, newy2) ?
2307                         MovingOrBlocked2Element(newx2, newy2) : EL_BETON);
2308
2309         if ((wanna_flame || IS_ENEMY(element1) || IS_ENEMY(element2)) &&
2310             element1 != EL_DRACHE && element2 != EL_DRACHE &&
2311             element1 != EL_BURNING && element2 != EL_BURNING)
2312         {
2313           if (IS_PLAYER(x, y))
2314             DrawPlayerField(x, y);
2315           else
2316             DrawLevelField(x, y);
2317
2318           MovDelay[x][y] = 50;
2319           Feld[newx][newy] = EL_BURNING;
2320           if (IN_LEV_FIELD(newx1, newy1) && Feld[newx1][newy1] == EL_LEERRAUM)
2321             Feld[newx1][newy1] = EL_BURNING;
2322           if (IN_LEV_FIELD(newx2, newy2) && Feld[newx2][newy2] == EL_LEERRAUM)
2323             Feld[newx2][newy2] = EL_BURNING;
2324           return;
2325         }
2326       }
2327     }
2328     else if (element == EL_MAMPFER && IN_LEV_FIELD(newx, newy) &&
2329              Feld[newx][newy] == EL_DIAMANT)
2330     {
2331       if (IS_MOVING(newx, newy))
2332         RemoveMovingField(newx, newy);
2333       else
2334       {
2335         Feld[newx][newy] = EL_LEERRAUM;
2336         DrawLevelField(newx, newy);
2337       }
2338     }
2339     else if (element == EL_MAMPFER2 && IN_LEV_FIELD(newx, newy) &&
2340              IS_MAMPF2(Feld[newx][newy]))
2341     {
2342       if (AmoebaNr[newx][newy])
2343       {
2344         AmoebaCnt2[AmoebaNr[newx][newy]]--;
2345         if (Feld[newx][newy] == EL_AMOEBE_VOLL ||
2346             Feld[newx][newy] == EL_AMOEBE_BD)
2347           AmoebaCnt[AmoebaNr[newx][newy]]--;
2348       }
2349
2350       if (IS_MOVING(newx, newy))
2351         RemoveMovingField(newx, newy);
2352       else
2353       {
2354         Feld[newx][newy] = EL_LEERRAUM;
2355         DrawLevelField(newx, newy);
2356       }
2357     }
2358     else if (element == EL_PACMAN && IN_LEV_FIELD(newx, newy) &&
2359              IS_AMOEBOID(Feld[newx][newy]))
2360     {
2361       if (AmoebaNr[newx][newy])
2362       {
2363         AmoebaCnt2[AmoebaNr[newx][newy]]--;
2364         if (Feld[newx][newy] == EL_AMOEBE_VOLL ||
2365             Feld[newx][newy] == EL_AMOEBE_BD)
2366           AmoebaCnt[AmoebaNr[newx][newy]]--;
2367       }
2368
2369       Feld[newx][newy] = EL_LEERRAUM;
2370       DrawLevelField(newx, newy);
2371     }
2372     else if (!IN_LEV_FIELD(newx, newy) || !IS_FREE(newx, newy))
2373     {
2374       /* object was running against a wall */
2375
2376       TurnRound(x, y);
2377
2378       if (element == EL_KAEFER || element == EL_FLIEGER ||
2379           element == EL_SP_SNIKSNAK)
2380         DrawLevelField(x, y);
2381       else if (element == EL_BUTTERFLY || element == EL_FIREFLY)
2382         DrawGraphicAnimation(x, y, el2gfx(element), 2, 4, ANIM_NORMAL);
2383       else if (element == EL_SONDE)
2384         DrawGraphicAnimation(x, y, GFX_SONDE_START, 8, 2, ANIM_NORMAL);
2385       else if (element == EL_SP_ELECTRON)
2386         DrawGraphicAnimation(x, y, GFX2_SP_ELECTRON, 8, 2, ANIM_NORMAL);
2387
2388       return;
2389     }
2390
2391     if (element == EL_ROBOT && IN_SCR_FIELD(x, y))
2392       PlaySoundLevel(x, y, SND_SCHLURF);
2393
2394     InitMovingField(x, y, MovDir[x][y]);
2395   }
2396
2397   if (MovDir[x][y])
2398     ContinueMoving(x, y);
2399 }
2400
2401 void ContinueMoving(int x, int y)
2402 {
2403   int element = Feld[x][y];
2404   int direction = MovDir[x][y];
2405   int dx = (direction == MV_LEFT ? -1 : direction == MV_RIGHT ? +1 : 0);
2406   int dy = (direction == MV_UP   ? -1 : direction == MV_DOWN  ? +1 : 0);
2407   int horiz_move = (dx!=0);
2408   int newx = x + dx, newy = y + dy;
2409   int step = (horiz_move ? dx : dy) * TILEX/8;
2410
2411   if (CAN_FALL(element) && horiz_move && !IS_SP_ELEMENT(element))
2412     step*=2;
2413   else if (element == EL_TROPFEN)
2414     step/=2;
2415   else if (Store[x][y] == EL_MORAST_VOLL || Store[x][y] == EL_MORAST_LEER)
2416     step/=4;
2417
2418   MovPos[x][y] += step;
2419
2420   if (ABS(MovPos[x][y])>=TILEX)         /* object reached its destination */
2421   {
2422     Feld[x][y] = EL_LEERRAUM;
2423     Feld[newx][newy] = element;
2424
2425     if (Store[x][y] == EL_MORAST_VOLL)
2426     {
2427       Store[x][y] = 0;
2428       Feld[newx][newy] = EL_MORAST_VOLL;
2429       element = EL_MORAST_VOLL;
2430     }
2431     else if (Store[x][y] == EL_MORAST_LEER)
2432     {
2433       Store[x][y] = 0;
2434       Feld[x][y] = EL_MORAST_LEER;
2435     }
2436     else if (Store[x][y] == EL_SIEB_VOLL)
2437     {
2438       Store[x][y] = 0;
2439       element = Feld[newx][newy] =
2440         (game.magic_wall_active ? EL_SIEB_VOLL : EL_SIEB_TOT);
2441     }
2442     else if (Store[x][y] == EL_SIEB_LEER)
2443     {
2444       Store[x][y] = Store2[x][y] = 0;
2445       Feld[x][y] = (game.magic_wall_active ? EL_SIEB_LEER : EL_SIEB_TOT);
2446     }
2447     else if (Store[x][y] == EL_SIEB2_VOLL)
2448     {
2449       Store[x][y] = 0;
2450       element = Feld[newx][newy] =
2451         (game.magic_wall_active ? EL_SIEB2_VOLL : EL_SIEB2_TOT);
2452     }
2453     else if (Store[x][y] == EL_SIEB2_LEER)
2454     {
2455       Store[x][y] = Store2[x][y] = 0;
2456       Feld[x][y] = (game.magic_wall_active ? EL_SIEB2_LEER : EL_SIEB2_TOT);
2457     }
2458     else if (Store[x][y] == EL_SALZSAEURE)
2459     {
2460       Store[x][y] = 0;
2461       Feld[newx][newy] = EL_SALZSAEURE;
2462       element = EL_SALZSAEURE;
2463     }
2464     else if (Store[x][y] == EL_AMOEBE_NASS)
2465     {
2466       Store[x][y] = 0;
2467       Feld[x][y] = EL_AMOEBE_NASS;
2468     }
2469
2470     MovPos[x][y] = MovDir[x][y] = MovDelay[x][y] = 0;
2471     MovDelay[newx][newy] = 0;
2472
2473     if (!CAN_MOVE(element))
2474       MovDir[newx][newy] = 0;
2475
2476     DrawLevelField(x, y);
2477     DrawLevelField(newx, newy);
2478
2479     Stop[newx][newy] = TRUE;
2480     JustHit[x][newy] = 3;
2481
2482     if (DONT_TOUCH(element))    /* object may be nasty to player or others */
2483     {
2484       TestIfBadThingHitsHero(newx, newy);
2485       TestIfBadThingHitsFriend(newx, newy);
2486       TestIfBadThingHitsOtherBadThing(newx, newy);
2487     }
2488     else if (element == EL_PINGUIN)
2489       TestIfFriendHitsBadThing(newx, newy);
2490
2491     if (CAN_SMASH(element) && direction == MV_DOWN &&
2492         (newy == lev_fieldy-1 || !IS_FREE(x, newy+1)))
2493       Impact(x, newy);
2494   }
2495   else                          /* still moving on */
2496     DrawLevelField(x, y);
2497 }
2498
2499 int AmoebeNachbarNr(int ax, int ay)
2500 {
2501   int i;
2502   int element = Feld[ax][ay];
2503   int group_nr = 0;
2504   static int xy[4][2] =
2505   {
2506     { 0, -1 },
2507     { -1, 0 },
2508     { +1, 0 },
2509     { 0, +1 }
2510   };
2511
2512   for (i=0; i<4; i++)
2513   {
2514     int x = ax + xy[i][0];
2515     int y = ay + xy[i][1];
2516
2517     if (!IN_LEV_FIELD(x, y))
2518       continue;
2519
2520     if (Feld[x][y] == element && AmoebaNr[x][y] > 0)
2521       group_nr = AmoebaNr[x][y];
2522   }
2523
2524   return group_nr;
2525 }
2526
2527 void AmoebenVereinigen(int ax, int ay)
2528 {
2529   int i, x, y, xx, yy;
2530   int new_group_nr = AmoebaNr[ax][ay];
2531   static int xy[4][2] =
2532   {
2533     { 0, -1 },
2534     { -1, 0 },
2535     { +1, 0 },
2536     { 0, +1 }
2537   };
2538
2539   if (new_group_nr == 0)
2540     return;
2541
2542   for (i=0; i<4; i++)
2543   {
2544     x = ax + xy[i][0];
2545     y = ay + xy[i][1];
2546
2547     if (!IN_LEV_FIELD(x, y))
2548       continue;
2549
2550     if ((Feld[x][y] == EL_AMOEBE_VOLL ||
2551          Feld[x][y] == EL_AMOEBE_BD ||
2552          Feld[x][y] == EL_AMOEBE_TOT) &&
2553         AmoebaNr[x][y] != new_group_nr)
2554     {
2555       int old_group_nr = AmoebaNr[x][y];
2556
2557       if (old_group_nr == 0)
2558         return;
2559
2560       AmoebaCnt[new_group_nr] += AmoebaCnt[old_group_nr];
2561       AmoebaCnt[old_group_nr] = 0;
2562       AmoebaCnt2[new_group_nr] += AmoebaCnt2[old_group_nr];
2563       AmoebaCnt2[old_group_nr] = 0;
2564
2565       for (yy=0; yy<lev_fieldy; yy++)
2566       {
2567         for (xx=0; xx<lev_fieldx; xx++)
2568         {
2569           if (AmoebaNr[xx][yy] == old_group_nr)
2570             AmoebaNr[xx][yy] = new_group_nr;
2571         }
2572       }
2573     }
2574   }
2575 }
2576
2577 void AmoebeUmwandeln(int ax, int ay)
2578 {
2579   int i, x, y;
2580
2581   if (Feld[ax][ay] == EL_AMOEBE_TOT)
2582   {
2583     int group_nr = AmoebaNr[ax][ay];
2584
2585 #ifdef DEBUG
2586     if (group_nr == 0)
2587     {
2588       printf("AmoebeUmwandeln(): ax = %d, ay = %d\n", ax, ay);
2589       printf("AmoebeUmwandeln(): This should never happen!\n");
2590       return;
2591     }
2592 #endif
2593
2594     for (y=0; y<lev_fieldy; y++)
2595     {
2596       for (x=0; x<lev_fieldx; x++)
2597       {
2598         if (Feld[x][y] == EL_AMOEBE_TOT && AmoebaNr[x][y] == group_nr)
2599         {
2600           AmoebaNr[x][y] = 0;
2601           Feld[x][y] = EL_AMOEBA2DIAM;
2602         }
2603       }
2604     }
2605     Bang(ax, ay);
2606   }
2607   else
2608   {
2609     static int xy[4][2] =
2610     {
2611       { 0, -1 },
2612       { -1, 0 },
2613       { +1, 0 },
2614       { 0, +1 }
2615     };
2616
2617     for (i=0; i<4; i++)
2618     {
2619       x = ax + xy[i][0];
2620       y = ay + xy[i][1];
2621
2622       if (!IN_LEV_FIELD(x, y))
2623         continue;
2624
2625       if (Feld[x][y] == EL_AMOEBA2DIAM)
2626         Bang(x, y);
2627     }
2628   }
2629 }
2630
2631 void AmoebeUmwandelnBD(int ax, int ay, int new_element)
2632 {
2633   int x, y;
2634   int group_nr = AmoebaNr[ax][ay];
2635   boolean done = FALSE;
2636
2637 #ifdef DEBUG
2638   if (group_nr == 0)
2639   {
2640     printf("AmoebeUmwandelnBD(): ax = %d, ay = %d\n", ax, ay);
2641     printf("AmoebeUmwandelnBD(): This should never happen!\n");
2642     return;
2643   }
2644 #endif
2645
2646   for (y=0; y<lev_fieldy; y++)
2647   {
2648     for (x=0; x<lev_fieldx; x++)
2649     {
2650       if (AmoebaNr[x][y] == group_nr &&
2651           (Feld[x][y] == EL_AMOEBE_TOT ||
2652            Feld[x][y] == EL_AMOEBE_BD ||
2653            Feld[x][y] == EL_AMOEBING))
2654       {
2655         AmoebaNr[x][y] = 0;
2656         Feld[x][y] = new_element;
2657         InitField(x, y, FALSE);
2658         DrawLevelField(x, y);
2659         done = TRUE;
2660       }
2661     }
2662   }
2663
2664   if (done)
2665     PlaySoundLevel(ax, ay,
2666                    (new_element == EL_FELSBROCKEN ? SND_KLOPF : SND_PLING));
2667 }
2668
2669 void AmoebeWaechst(int x, int y)
2670 {
2671   static unsigned long sound_delay = 0;
2672   static unsigned long sound_delay_value = 0;
2673
2674   if (!MovDelay[x][y])          /* start new growing cycle */
2675   {
2676     MovDelay[x][y] = 7;
2677
2678     if (DelayReached(&sound_delay, sound_delay_value))
2679     {
2680       PlaySoundLevel(x, y, SND_AMOEBE);
2681       sound_delay_value = 30;
2682     }
2683   }
2684
2685   if (MovDelay[x][y])           /* wait some time before growing bigger */
2686   {
2687     MovDelay[x][y]--;
2688     if (MovDelay[x][y]/2 && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
2689       DrawGraphic(SCREENX(x), SCREENY(y), GFX_AMOEBING + 3 - MovDelay[x][y]/2);
2690
2691     if (!MovDelay[x][y])
2692     {
2693       Feld[x][y] = Store[x][y];
2694       Store[x][y] = 0;
2695       DrawLevelField(x, y);
2696     }
2697   }
2698 }
2699
2700 void AmoebeAbleger(int ax, int ay)
2701 {
2702   int i;
2703   int element = Feld[ax][ay];
2704   int newax = ax, neway = ay;
2705   static int xy[4][2] =
2706   {
2707     { 0, -1 },
2708     { -1, 0 },
2709     { +1, 0 },
2710     { 0, +1 }
2711   };
2712
2713   if (!level.amoeba_speed)
2714   {
2715     Feld[ax][ay] = EL_AMOEBE_TOT;
2716     DrawLevelField(ax, ay);
2717     return;
2718   }
2719
2720   if (!MovDelay[ax][ay])        /* start making new amoeba field */
2721     MovDelay[ax][ay] = RND(FRAMES_PER_SECOND * 25 / (1 + level.amoeba_speed));
2722
2723   if (MovDelay[ax][ay])         /* wait some time before making new amoeba */
2724   {
2725     MovDelay[ax][ay]--;
2726     if (MovDelay[ax][ay])
2727       return;
2728   }
2729
2730   if (element == EL_AMOEBE_NASS)        /* object is an acid / amoeba drop */
2731   {
2732     int start = RND(4);
2733     int x = ax + xy[start][0];
2734     int y = ay + xy[start][1];
2735
2736     if (!IN_LEV_FIELD(x, y))
2737       return;
2738
2739     if (IS_FREE(x, y) ||
2740         Feld[x][y] == EL_ERDREICH || Feld[x][y] == EL_MORAST_LEER)
2741     {
2742       newax = x;
2743       neway = y;
2744     }
2745
2746     if (newax == ax && neway == ay)
2747       return;
2748   }
2749   else                          /* normal or "filled" (BD style) amoeba */
2750   {
2751     int start = RND(4);
2752     boolean waiting_for_player = FALSE;
2753
2754     for (i=0; i<4; i++)
2755     {
2756       int j = (start + i) % 4;
2757       int x = ax + xy[j][0];
2758       int y = ay + xy[j][1];
2759
2760       if (!IN_LEV_FIELD(x, y))
2761         continue;
2762
2763       if (IS_FREE(x, y) ||
2764           Feld[x][y] == EL_ERDREICH || Feld[x][y] == EL_MORAST_LEER)
2765       {
2766         newax = x;
2767         neway = y;
2768         break;
2769       }
2770       else if (IS_PLAYER(x, y))
2771         waiting_for_player = TRUE;
2772     }
2773
2774     if (newax == ax && neway == ay)             /* amoeba cannot grow */
2775     {
2776       if (i == 4 && (!waiting_for_player || game.emulation == EMU_BOULDERDASH))
2777       {
2778         Feld[ax][ay] = EL_AMOEBE_TOT;
2779         DrawLevelField(ax, ay);
2780         AmoebaCnt[AmoebaNr[ax][ay]]--;
2781
2782         if (AmoebaCnt[AmoebaNr[ax][ay]] <= 0)   /* amoeba is completely dead */
2783         {
2784           if (element == EL_AMOEBE_VOLL)
2785             AmoebeUmwandeln(ax, ay);
2786           else if (element == EL_AMOEBE_BD)
2787             AmoebeUmwandelnBD(ax, ay, level.amoeba_content);
2788         }
2789       }
2790       return;
2791     }
2792     else if (element == EL_AMOEBE_VOLL || element == EL_AMOEBE_BD)
2793     {
2794       /* amoeba gets larger by growing in some direction */
2795
2796       int new_group_nr = AmoebaNr[ax][ay];
2797
2798 #ifdef DEBUG
2799   if (new_group_nr == 0)
2800   {
2801     printf("AmoebeAbleger(): newax = %d, neway = %d\n", newax, neway);
2802     printf("AmoebeAbleger(): This should never happen!\n");
2803     return;
2804   }
2805 #endif
2806
2807       AmoebaNr[newax][neway] = new_group_nr;
2808       AmoebaCnt[new_group_nr]++;
2809       AmoebaCnt2[new_group_nr]++;
2810
2811       /* if amoeba touches other amoeba(s) after growing, unify them */
2812       AmoebenVereinigen(newax, neway);
2813
2814       if (element == EL_AMOEBE_BD && AmoebaCnt2[new_group_nr] >= 200)
2815       {
2816         AmoebeUmwandelnBD(newax, neway, EL_FELSBROCKEN);
2817         return;
2818       }
2819     }
2820   }
2821
2822   if (element != EL_AMOEBE_NASS || neway < ay || !IS_FREE(newax, neway) ||
2823       (neway == lev_fieldy - 1 && newax != ax))
2824   {
2825     Feld[newax][neway] = EL_AMOEBING;
2826     Store[newax][neway] = element;
2827   }
2828   else if (neway == ay)
2829     Feld[newax][neway] = EL_TROPFEN;
2830   else
2831   {
2832     InitMovingField(ax, ay, MV_DOWN);
2833     Feld[ax][ay] = EL_TROPFEN;
2834     Store[ax][ay] = EL_AMOEBE_NASS;
2835     ContinueMoving(ax, ay);
2836     return;
2837   }
2838
2839   DrawLevelField(newax, neway);
2840 }
2841
2842 void Life(int ax, int ay)
2843 {
2844   int x1, y1, x2, y2;
2845   static int life[4] = { 2, 3, 3, 3 };  /* parameters for "game of life" */
2846   int life_time = 40;
2847   int element = Feld[ax][ay];
2848
2849   if (Stop[ax][ay])
2850     return;
2851
2852   if (!MovDelay[ax][ay])        /* start new "game of life" cycle */
2853     MovDelay[ax][ay] = life_time;
2854
2855   if (MovDelay[ax][ay])         /* wait some time before next cycle */
2856   {
2857     MovDelay[ax][ay]--;
2858     if (MovDelay[ax][ay])
2859       return;
2860   }
2861
2862   for (y1=-1; y1<2; y1++) for(x1=-1; x1<2; x1++)
2863   {
2864     int xx = ax+x1, yy = ay+y1;
2865     int nachbarn = 0;
2866
2867     if (!IN_LEV_FIELD(xx, yy))
2868       continue;
2869
2870     for (y2=-1; y2<2; y2++) for (x2=-1; x2<2; x2++)
2871     {
2872       int x = xx+x2, y = yy+y2;
2873
2874       if (!IN_LEV_FIELD(x, y) || (x == xx && y == yy))
2875         continue;
2876
2877       if (((Feld[x][y] == element ||
2878             (element == EL_LIFE && IS_PLAYER(x, y))) &&
2879            !Stop[x][y]) ||
2880           (IS_FREE(x, y) && Stop[x][y]))
2881         nachbarn++;
2882     }
2883
2884     if (xx == ax && yy == ay)           /* field in the middle */
2885     {
2886       if (nachbarn<life[0] || nachbarn>life[1])
2887       {
2888         Feld[xx][yy] = EL_LEERRAUM;
2889         if (!Stop[xx][yy])
2890           DrawLevelField(xx, yy);
2891         Stop[xx][yy] = TRUE;
2892       }
2893     }
2894     else if (IS_FREE(xx, yy) || Feld[xx][yy] == EL_ERDREICH)
2895     {                                   /* free border field */
2896       if (nachbarn>=life[2] && nachbarn<=life[3])
2897       {
2898         Feld[xx][yy] = element;
2899         MovDelay[xx][yy] = (element == EL_LIFE ? 0 : life_time-1);
2900         if (!Stop[xx][yy])
2901           DrawLevelField(xx, yy);
2902         Stop[xx][yy] = TRUE;
2903       }
2904     }
2905   }
2906 }
2907
2908 void Ablenk(int x, int y)
2909 {
2910   if (!MovDelay[x][y])          /* next animation frame */
2911     MovDelay[x][y] = level.time_wheel * FRAMES_PER_SECOND;
2912
2913   if (MovDelay[x][y])           /* wait some time before next frame */
2914   {
2915     MovDelay[x][y]--;
2916     if (MovDelay[x][y])
2917     {
2918       if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
2919         DrawGraphic(SCREENX(x), SCREENY(y), GFX_ABLENK+MovDelay[x][y]%4);
2920       if (!(MovDelay[x][y]%4))
2921         PlaySoundLevel(x, y, SND_MIEP);
2922       return;
2923     }
2924   }
2925
2926   Feld[x][y] = EL_ABLENK_AUS;
2927   DrawLevelField(x, y);
2928   if (ZX == x && ZY == y)
2929     ZX = ZY = -1;
2930 }
2931
2932 void Birne(int x, int y)
2933 {
2934   if (!MovDelay[x][y])          /* next animation frame */
2935     MovDelay[x][y] = 800;
2936
2937   if (MovDelay[x][y])           /* wait some time before next frame */
2938   {
2939     MovDelay[x][y]--;
2940     if (MovDelay[x][y])
2941     {
2942       if (!(MovDelay[x][y]%5))
2943       {
2944         if (!(MovDelay[x][y]%10))
2945           Feld[x][y]=EL_ABLENK_EIN;
2946         else
2947           Feld[x][y]=EL_ABLENK_AUS;
2948         DrawLevelField(x, y);
2949         Feld[x][y]=EL_ABLENK_EIN;
2950       }
2951       return;
2952     }
2953   }
2954
2955   Feld[x][y]=EL_ABLENK_AUS;
2956   DrawLevelField(x, y);
2957   if (ZX == x && ZY == y)
2958     ZX=ZY=-1;
2959 }
2960
2961 void Blubber(int x, int y)
2962 {
2963   if (y > 0 && IS_MOVING(x, y-1) && MovDir[x][y-1] == MV_DOWN)
2964     DrawLevelField(x, y-1);
2965   else
2966     DrawGraphicAnimation(x, y, GFX_GEBLUBBER, 4, 10, ANIM_NORMAL);
2967 }
2968
2969 void NussKnacken(int x, int y)
2970 {
2971   if (!MovDelay[x][y])          /* next animation frame */
2972     MovDelay[x][y] = 7;
2973
2974   if (MovDelay[x][y])           /* wait some time before next frame */
2975   {
2976     MovDelay[x][y]--;
2977     if (MovDelay[x][y]/2 && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
2978       DrawGraphic(SCREENX(x), SCREENY(y), GFX_CRACKINGNUT+3-MovDelay[x][y]/2);
2979
2980     if (!MovDelay[x][y])
2981     {
2982       Feld[x][y] = EL_EDELSTEIN;
2983       DrawLevelField(x, y);
2984     }
2985   }
2986 }
2987
2988 void SiebAktivieren(int x, int y, int typ)
2989 {
2990   int graphic = (typ == 1 ? GFX_SIEB_VOLL : GFX_SIEB2_VOLL) + 3;
2991
2992   DrawGraphicAnimation(x, y, graphic, 4, 4, ANIM_REVERSE);
2993 }
2994
2995 void AusgangstuerPruefen(int x, int y)
2996 {
2997   if (!local_player->gems_still_needed &&
2998       !local_player->sokobanfields_still_needed &&
2999       !local_player->lights_still_needed)
3000   {
3001     Feld[x][y] = EL_AUSGANG_ACT;
3002
3003     PlaySoundLevel(x < LEVELX(BX1) ? LEVELX(BX1) :
3004                    (x > LEVELX(BX2) ? LEVELX(BX2) : x),
3005                    y < LEVELY(BY1) ? LEVELY(BY1) :
3006                    (y > LEVELY(BY2) ? LEVELY(BY2) : y),
3007                    SND_OEFFNEN);
3008   }
3009 }
3010
3011 void AusgangstuerOeffnen(int x, int y)
3012 {
3013   int delay = 6;
3014
3015   if (!MovDelay[x][y])          /* next animation frame */
3016     MovDelay[x][y] = 5*delay;
3017
3018   if (MovDelay[x][y])           /* wait some time before next frame */
3019   {
3020     int tuer;
3021
3022     MovDelay[x][y]--;
3023     tuer = MovDelay[x][y]/delay;
3024     if (!(MovDelay[x][y]%delay) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
3025       DrawGraphic(SCREENX(x), SCREENY(y), GFX_AUSGANG_AUF-tuer);
3026
3027     if (!MovDelay[x][y])
3028     {
3029       Feld[x][y] = EL_AUSGANG_AUF;
3030       DrawLevelField(x, y);
3031     }
3032   }
3033 }
3034
3035 void AusgangstuerBlinken(int x, int y)
3036 {
3037   DrawGraphicAnimation(x, y, GFX_AUSGANG_AUF, 4, 4, ANIM_OSCILLATE);
3038 }
3039
3040 void EdelsteinFunkeln(int x, int y)
3041 {
3042   if (!IN_SCR_FIELD(SCREENX(x), SCREENY(y)) || IS_MOVING(x, y))
3043     return;
3044
3045   if (Feld[x][y] == EL_EDELSTEIN_BD)
3046     DrawGraphicAnimation(x, y, GFX_EDELSTEIN_BD, 4, 4, ANIM_REVERSE);
3047   else
3048   {
3049     if (!MovDelay[x][y])        /* next animation frame */
3050       MovDelay[x][y] = 11 * !SimpleRND(500);
3051
3052     if (MovDelay[x][y])         /* wait some time before next frame */
3053     {
3054       MovDelay[x][y]--;
3055
3056       if (setup.direct_draw && MovDelay[x][y])
3057         SetDrawtoField(DRAW_BUFFERED);
3058
3059       DrawGraphic(SCREENX(x), SCREENY(y), el2gfx(Feld[x][y]));
3060
3061       if (MovDelay[x][y])
3062       {
3063         int phase = (MovDelay[x][y]-1)/2;
3064
3065         if (phase > 2)
3066           phase = 4-phase;
3067
3068         DrawGraphicThruMask(SCREENX(x), SCREENY(y), GFX_FUNKELN_WEISS + phase);
3069
3070         if (setup.direct_draw)
3071         {
3072           int dest_x, dest_y;
3073
3074           dest_x = FX + SCREENX(x)*TILEX;
3075           dest_y = FY + SCREENY(y)*TILEY;
3076
3077           XCopyArea(display, drawto_field, window, gc,
3078                     dest_x, dest_y, TILEX, TILEY, dest_x, dest_y);
3079           SetDrawtoField(DRAW_DIRECT);
3080         }
3081       }
3082     }
3083   }
3084 }
3085
3086 void MauerWaechst(int x, int y)
3087 {
3088   int delay = 6;
3089
3090   if (!MovDelay[x][y])          /* next animation frame */
3091     MovDelay[x][y] = 3*delay;
3092
3093   if (MovDelay[x][y])           /* wait some time before next frame */
3094   {
3095     int phase;
3096
3097     MovDelay[x][y]--;
3098     phase = 2-MovDelay[x][y]/delay;
3099     if (!(MovDelay[x][y]%delay) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
3100       DrawGraphic(SCREENX(x), SCREENY(y),
3101                   (MovDir[x][y] == MV_LEFT  ? GFX_MAUER_LEFT  :
3102                    MovDir[x][y] == MV_RIGHT ? GFX_MAUER_RIGHT :
3103                    MovDir[x][y] == MV_UP    ? GFX_MAUER_UP    :
3104                                               GFX_MAUER_DOWN  ) + phase);
3105
3106     if (!MovDelay[x][y])
3107     {
3108       if (MovDir[x][y] == MV_LEFT)
3109       {
3110         if (IN_LEV_FIELD(x-1, y) && IS_MAUER(Feld[x-1][y]))
3111           DrawLevelField(x-1, y);
3112       }
3113       else if (MovDir[x][y] == MV_RIGHT)
3114       {
3115         if (IN_LEV_FIELD(x+1, y) && IS_MAUER(Feld[x+1][y]))
3116           DrawLevelField(x+1, y);
3117       }
3118       else if (MovDir[x][y] == MV_UP)
3119       {
3120         if (IN_LEV_FIELD(x, y-1) && IS_MAUER(Feld[x][y-1]))
3121           DrawLevelField(x, y-1);
3122       }
3123       else
3124       {
3125         if (IN_LEV_FIELD(x, y+1) && IS_MAUER(Feld[x][y+1]))
3126           DrawLevelField(x, y+1);
3127       }
3128
3129       Feld[x][y] = Store[x][y];
3130       Store[x][y] = 0;
3131       MovDir[x][y] = MV_NO_MOVING;
3132       DrawLevelField(x, y);
3133     }
3134   }
3135 }
3136
3137 void MauerAbleger(int ax, int ay)
3138 {
3139   int element = Feld[ax][ay];
3140   boolean oben_frei = FALSE, unten_frei = FALSE;
3141   boolean links_frei = FALSE, rechts_frei = FALSE;
3142   boolean oben_massiv = FALSE, unten_massiv = FALSE;
3143   boolean links_massiv = FALSE, rechts_massiv = FALSE;
3144
3145   if (!MovDelay[ax][ay])        /* start building new wall */
3146     MovDelay[ax][ay] = 6;
3147
3148   if (MovDelay[ax][ay])         /* wait some time before building new wall */
3149   {
3150     MovDelay[ax][ay]--;
3151     if (MovDelay[ax][ay])
3152       return;
3153   }
3154
3155   if (IN_LEV_FIELD(ax, ay-1) && IS_FREE(ax, ay-1))
3156     oben_frei = TRUE;
3157   if (IN_LEV_FIELD(ax, ay+1) && IS_FREE(ax, ay+1))
3158     unten_frei = TRUE;
3159   if (IN_LEV_FIELD(ax-1, ay) && IS_FREE(ax-1, ay))
3160     links_frei = TRUE;
3161   if (IN_LEV_FIELD(ax+1, ay) && IS_FREE(ax+1, ay))
3162     rechts_frei = TRUE;
3163
3164   if (element == EL_MAUER_Y || element == EL_MAUER_XY)
3165   {
3166     if (oben_frei)
3167     {
3168       Feld[ax][ay-1] = EL_MAUERND;
3169       Store[ax][ay-1] = element;
3170       MovDir[ax][ay-1] = MV_UP;
3171       if (IN_SCR_FIELD(SCREENX(ax), SCREENY(ay-1)))
3172         DrawGraphic(SCREENX(ax), SCREENY(ay-1), GFX_MAUER_UP);
3173     }
3174     if (unten_frei)
3175     {
3176       Feld[ax][ay+1] = EL_MAUERND;
3177       Store[ax][ay+1] = element;
3178       MovDir[ax][ay+1] = MV_DOWN;
3179       if (IN_SCR_FIELD(SCREENX(ax), SCREENY(ay+1)))
3180         DrawGraphic(SCREENX(ax), SCREENY(ay+1), GFX_MAUER_DOWN);
3181     }
3182   }
3183
3184   if (element == EL_MAUER_X || element == EL_MAUER_XY ||
3185       element == EL_MAUER_LEBT)
3186   {
3187     if (links_frei)
3188     {
3189       Feld[ax-1][ay] = EL_MAUERND;
3190       Store[ax-1][ay] = element;
3191       MovDir[ax-1][ay] = MV_LEFT;
3192       if (IN_SCR_FIELD(SCREENX(ax-1), SCREENY(ay)))
3193         DrawGraphic(SCREENX(ax-1), SCREENY(ay), GFX_MAUER_LEFT);
3194     }
3195     if (rechts_frei)
3196     {
3197       Feld[ax+1][ay] = EL_MAUERND;
3198       Store[ax+1][ay] = element;
3199       MovDir[ax+1][ay] = MV_RIGHT;
3200       if (IN_SCR_FIELD(SCREENX(ax+1), SCREENY(ay)))
3201         DrawGraphic(SCREENX(ax+1), SCREENY(ay), GFX_MAUER_RIGHT);
3202     }
3203   }
3204
3205   if (element == EL_MAUER_LEBT && (links_frei || rechts_frei))
3206     DrawLevelField(ax, ay);
3207
3208   if (!IN_LEV_FIELD(ax, ay-1) || IS_MAUER(Feld[ax][ay-1]))
3209     oben_massiv = TRUE;
3210   if (!IN_LEV_FIELD(ax, ay+1) || IS_MAUER(Feld[ax][ay+1]))
3211     unten_massiv = TRUE;
3212   if (!IN_LEV_FIELD(ax-1, ay) || IS_MAUER(Feld[ax-1][ay]))
3213     links_massiv = TRUE;
3214   if (!IN_LEV_FIELD(ax+1, ay) || IS_MAUER(Feld[ax+1][ay]))
3215     rechts_massiv = TRUE;
3216
3217   if (((oben_massiv && unten_massiv) ||
3218        element == EL_MAUER_X || element == EL_MAUER_LEBT) &&
3219       ((links_massiv && rechts_massiv) ||
3220        element == EL_MAUER_Y))
3221     Feld[ax][ay] = EL_MAUERWERK;
3222 }
3223
3224 void CheckForDragon(int x, int y)
3225 {
3226   int i, j;
3227   boolean dragon_found = FALSE;
3228   static int xy[4][2] =
3229   {
3230     { 0, -1 },
3231     { -1, 0 },
3232     { +1, 0 },
3233     { 0, +1 }
3234   };
3235
3236   for (i=0; i<4; i++)
3237   {
3238     for (j=0; j<4; j++)
3239     {
3240       int xx = x + j*xy[i][0], yy = y + j*xy[i][1];
3241
3242       if (IN_LEV_FIELD(xx, yy) &&
3243           (Feld[xx][yy] == EL_BURNING || Feld[xx][yy] == EL_DRACHE))
3244       {
3245         if (Feld[xx][yy] == EL_DRACHE)
3246           dragon_found = TRUE;
3247       }
3248       else
3249         break;
3250     }
3251   }
3252
3253   if (!dragon_found)
3254   {
3255     for (i=0; i<4; i++)
3256     {
3257       for (j=0; j<3; j++)
3258       {
3259         int xx = x + j*xy[i][0], yy = y + j*xy[i][1];
3260   
3261         if (IN_LEV_FIELD(xx, yy) && Feld[xx][yy] == EL_BURNING)
3262         {
3263           Feld[xx][yy] = EL_LEERRAUM;
3264           DrawLevelField(xx, yy);
3265         }
3266         else
3267           break;
3268       }
3269     }
3270   }
3271 }
3272
3273 static void CheckBuggyBase(int x, int y)
3274 {
3275   int element = Feld[x][y];
3276
3277   if (element == EL_SP_BUG)
3278   {
3279     if (!MovDelay[x][y])        /* start activating buggy base */
3280       MovDelay[x][y] = 2 * FRAMES_PER_SECOND + RND(5 * FRAMES_PER_SECOND);
3281
3282     if (MovDelay[x][y])         /* wait some time before activating base */
3283     {
3284       MovDelay[x][y]--;
3285       if (MovDelay[x][y] < 5 && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
3286         DrawGraphic(SCREENX(x), SCREENY(y), GFX_SP_BUG_WARNING);
3287       if (MovDelay[x][y])
3288         return;
3289
3290       Feld[x][y] = EL_SP_BUG_ACTIVE;
3291     }
3292   }
3293   else if (element == EL_SP_BUG_ACTIVE)
3294   {
3295     if (!MovDelay[x][y])        /* start activating buggy base */
3296       MovDelay[x][y] = 1 * FRAMES_PER_SECOND + RND(1 * FRAMES_PER_SECOND);
3297
3298     if (MovDelay[x][y])         /* wait some time before activating base */
3299     {
3300       MovDelay[x][y]--;
3301       if (MovDelay[x][y])
3302       {
3303         int i;
3304         static int xy[4][2] =
3305         {
3306           { 0, -1 },
3307           { -1, 0 },
3308           { +1, 0 },
3309           { 0, +1 }
3310         };
3311
3312         if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
3313           DrawGraphic(SCREENX(x),SCREENY(y), GFX_SP_BUG_ACTIVE + SimpleRND(4));
3314
3315         for (i=0; i<4; i++)
3316         {
3317           int xx = x + xy[i][0], yy = y + xy[i][1];
3318
3319           if (IS_PLAYER(xx, yy))
3320           {
3321             PlaySoundLevel(x, y, SND_SP_BUG);
3322             break;
3323           }
3324         }
3325
3326         return;
3327       }
3328
3329       Feld[x][y] = EL_SP_BUG;
3330       DrawLevelField(x, y);
3331     }
3332   }
3333 }
3334
3335 static void PlayerActions(struct PlayerInfo *player, byte player_action)
3336 {
3337   static byte stored_player_action[MAX_PLAYERS];
3338   static int num_stored_actions = 0;
3339   static boolean save_tape_entry = FALSE;
3340   boolean moved = FALSE, snapped = FALSE, bombed = FALSE;
3341   int jx = player->jx, jy = player->jy;
3342   int left      = player_action & JOY_LEFT;
3343   int right     = player_action & JOY_RIGHT;
3344   int up        = player_action & JOY_UP;
3345   int down      = player_action & JOY_DOWN;
3346   int button1   = player_action & JOY_BUTTON_1;
3347   int button2   = player_action & JOY_BUTTON_2;
3348   int dx        = (left ? -1    : right ? 1     : 0);
3349   int dy        = (up   ? -1    : down  ? 1     : 0);
3350
3351   stored_player_action[player->index_nr] = 0;
3352   num_stored_actions++;
3353
3354   if (!player->active || tape.pausing)
3355     return;
3356
3357   if (player_action)
3358   {
3359     save_tape_entry = TRUE;
3360     player->frame_reset_delay = 0;
3361
3362     if (button1)
3363       snapped = SnapField(player, dx, dy);
3364     else
3365     {
3366       if (button2)
3367         bombed = PlaceBomb(player);
3368       moved = MoveFigure(player, dx, dy);
3369     }
3370
3371     if (tape.recording && (moved || snapped || bombed))
3372     {
3373       if (bombed && !moved)
3374         player_action &= JOY_BUTTON;
3375
3376       stored_player_action[player->index_nr] = player_action;
3377     }
3378     else if (tape.playing && snapped)
3379       SnapField(player, 0, 0);                  /* stop snapping */
3380   }
3381   else
3382   {
3383     /* no actions for this player (no input at player's configured device) */
3384
3385     DigField(player, 0, 0, 0, 0, DF_NO_PUSH);
3386     SnapField(player, 0, 0);
3387     CheckGravityMovement(player);
3388
3389     if (++player->frame_reset_delay > player->move_delay_value)
3390       player->Frame = 0;
3391   }
3392
3393   if (tape.recording && num_stored_actions >= MAX_PLAYERS && save_tape_entry)
3394   {
3395     TapeRecordAction(stored_player_action);
3396     num_stored_actions = 0;
3397     save_tape_entry = FALSE;
3398   }
3399
3400   if (tape.playing && !tape.pausing && !player_action &&
3401       tape.counter < tape.length)
3402   {
3403     int next_joy =
3404       tape.pos[tape.counter].action[player->index_nr] & (JOY_LEFT|JOY_RIGHT);
3405
3406     if ((next_joy == JOY_LEFT || next_joy == JOY_RIGHT) &&
3407         (player->MovDir != JOY_UP && player->MovDir != JOY_DOWN))
3408     {
3409       int dx = (next_joy == JOY_LEFT ? -1 : +1);
3410
3411       if (IN_LEV_FIELD(jx+dx, jy) && IS_PUSHABLE(Feld[jx+dx][jy]))
3412       {
3413         int el = Feld[jx+dx][jy];
3414         int push_delay = (IS_SB_ELEMENT(el) || el == EL_SONDE ? 2 : 10);
3415
3416         if (tape.delay_played + push_delay >= tape.pos[tape.counter].delay)
3417         {
3418           player->MovDir = next_joy;
3419           player->Frame = FrameCounter % 4;
3420           player->Pushing = TRUE;
3421         }
3422       }
3423     }
3424   }
3425 }
3426
3427 void GameActions()
3428 {
3429   static unsigned long action_delay = 0;
3430   unsigned long action_delay_value;
3431   int sieb_x = 0, sieb_y = 0;
3432   int i, x, y, element;
3433   byte *recorded_player_action;
3434   byte summarized_player_action = 0;
3435
3436   if (game_status != PLAYING)
3437     return;
3438
3439   action_delay_value =
3440     (tape.playing && tape.fast_forward ? FfwdFrameDelay : GameFrameDelay);
3441
3442   /* ---------- main game synchronization point ---------- */
3443
3444   WaitUntilDelayReached(&action_delay, action_delay_value);
3445
3446   if (network_playing && !network_player_action_received)
3447   {
3448     /*
3449 #ifdef DEBUG
3450     printf("DEBUG: try to get network player actions in time\n");
3451 #endif
3452     */
3453
3454 #ifndef MSDOS
3455     /* last chance to get network player actions without main loop delay */
3456     HandleNetworking();
3457 #endif
3458
3459     if (game_status != PLAYING)
3460       return;
3461
3462     if (!network_player_action_received)
3463     {
3464       /*
3465 #ifdef DEBUG
3466       printf("DEBUG: failed to get network player actions in time\n");
3467 #endif
3468       */
3469       return;
3470     }
3471   }
3472
3473   if (tape.pausing)
3474     return;
3475
3476   if (tape.playing)
3477     TapePlayDelay();
3478   else if (tape.recording)
3479     TapeRecordDelay();
3480
3481   recorded_player_action = (tape.playing ? TapePlayAction() : NULL);
3482
3483   for (i=0; i<MAX_PLAYERS; i++)
3484   {
3485     summarized_player_action |= stored_player[i].action;
3486
3487     if (!network_playing)
3488       stored_player[i].effective_action = stored_player[i].action;
3489   }
3490
3491 #ifndef MSDOS
3492   if (network_playing)
3493     SendToServer_MovePlayer(summarized_player_action);
3494 #endif
3495
3496   if (!options.network && !setup.team_mode)
3497     local_player->effective_action = summarized_player_action;
3498
3499   for (i=0; i<MAX_PLAYERS; i++)
3500   {
3501     int actual_player_action = stored_player[i].effective_action;
3502
3503     if (stored_player[i].programmed_action)
3504       actual_player_action = stored_player[i].programmed_action;
3505
3506     if (recorded_player_action)
3507       actual_player_action = recorded_player_action[i];
3508
3509     PlayerActions(&stored_player[i], actual_player_action);
3510     ScrollFigure(&stored_player[i], SCROLL_GO_ON);
3511   }
3512
3513   network_player_action_received = FALSE;
3514
3515   ScrollScreen(NULL, SCROLL_GO_ON);
3516
3517
3518
3519 #ifdef DEBUG
3520 #if 0
3521   if (TimeFrames == 0 && local_player->active)
3522   {
3523     extern unsigned int last_RND();
3524
3525     printf("DEBUG: %03d last RND was %d \t [state checksum is %d]\n",
3526            TimePlayed, last_RND(), getStateCheckSum(TimePlayed));
3527   }
3528 #endif
3529 #endif
3530
3531 #ifdef DEBUG
3532 #if 0
3533   if (GameFrameDelay >= 500)
3534     printf("FrameCounter == %d\n", FrameCounter);
3535 #endif
3536 #endif
3537
3538
3539
3540   FrameCounter++;
3541   TimeFrames++;
3542
3543   for (y=0; y<lev_fieldy; y++) for (x=0; x<lev_fieldx; x++)
3544   {
3545     Stop[x][y] = FALSE;
3546     if (JustHit[x][y]>0)
3547       JustHit[x][y]--;
3548
3549 #if DEBUG
3550     if (IS_BLOCKED(x, y))
3551     {
3552       int oldx, oldy;
3553
3554       Blocked2Moving(x, y, &oldx, &oldy);
3555       if (!IS_MOVING(oldx, oldy))
3556       {
3557         printf("GameActions(): (BLOCKED => MOVING) context corrupted!\n");
3558         printf("GameActions(): BLOCKED: x = %d, y = %d\n", x, y);
3559         printf("GameActions(): !MOVING: oldx = %d, oldy = %d\n", oldx, oldy);
3560         printf("GameActions(): This should never happen!\n");
3561       }
3562     }
3563 #endif
3564   }
3565
3566   for (y=0; y<lev_fieldy; y++) for (x=0; x<lev_fieldx; x++)
3567   {
3568     element = Feld[x][y];
3569
3570     if (IS_INACTIVE(element))
3571       continue;
3572
3573     if (!IS_MOVING(x, y) && (CAN_FALL(element) || CAN_MOVE(element)))
3574     {
3575       StartMoving(x, y);
3576
3577       if (IS_GEM(element))
3578         EdelsteinFunkeln(x, y);
3579     }
3580     else if (IS_MOVING(x, y))
3581       ContinueMoving(x, y);
3582     else if (element == EL_DYNAMIT || element == EL_DYNABOMB)
3583       CheckDynamite(x, y);
3584     else if (element == EL_EXPLODING)
3585       Explode(x, y, Frame[x][y], EX_NORMAL);
3586     else if (element == EL_AMOEBING)
3587       AmoebeWaechst(x, y);
3588     else if (IS_AMOEBALIVE(element))
3589       AmoebeAbleger(x, y);
3590     else if (element == EL_LIFE || element == EL_LIFE_ASYNC)
3591       Life(x, y);
3592     else if (element == EL_ABLENK_EIN)
3593       Ablenk(x, y);
3594     else if (element == EL_SALZSAEURE)
3595       Blubber(x, y);
3596     else if (element == EL_BLURB_LEFT || element == EL_BLURB_RIGHT)
3597       Blurb(x, y);
3598     else if (element == EL_CRACKINGNUT)
3599       NussKnacken(x, y);
3600     else if (element == EL_AUSGANG_ZU)
3601       AusgangstuerPruefen(x, y);
3602     else if (element == EL_AUSGANG_ACT)
3603       AusgangstuerOeffnen(x, y);
3604     else if (element == EL_AUSGANG_AUF)
3605       AusgangstuerBlinken(x, y);
3606     else if (element == EL_MAUERND)
3607       MauerWaechst(x, y);
3608     else if (element == EL_MAUER_LEBT ||
3609              element == EL_MAUER_X ||
3610              element == EL_MAUER_Y ||
3611              element == EL_MAUER_XY)
3612       MauerAbleger(x, y);
3613     else if (element == EL_BURNING)
3614       CheckForDragon(x, y);
3615     else if (element == EL_SP_BUG || element == EL_SP_BUG_ACTIVE)
3616       CheckBuggyBase(x, y);
3617     else if (element == EL_SP_TERMINAL)
3618       DrawGraphicAnimation(x, y, GFX2_SP_TERMINAL, 7, 12, ANIM_NORMAL);
3619     else if (element == EL_SP_TERMINAL_ACTIVE)
3620       DrawGraphicAnimation(x, y, GFX2_SP_TERMINAL_ACTIVE, 7, 4, ANIM_NORMAL);
3621
3622     if (game.magic_wall_active)
3623     {
3624       boolean sieb = FALSE;
3625       int jx = local_player->jx, jy = local_player->jy;
3626
3627       if (element == EL_SIEB_LEER || element == EL_SIEB_VOLL ||
3628           Store[x][y] == EL_SIEB_LEER)
3629       {
3630         SiebAktivieren(x, y, 1);
3631         sieb = TRUE;
3632       }
3633       else if (element == EL_SIEB2_LEER || element == EL_SIEB2_VOLL ||
3634                Store[x][y] == EL_SIEB2_LEER)
3635       {
3636         SiebAktivieren(x, y, 2);
3637         sieb = TRUE;
3638       }
3639
3640       /* play the element sound at the position nearest to the player */
3641       if (sieb && ABS(x-jx)+ABS(y-jy) < ABS(sieb_x-jx)+ABS(sieb_y-jy))
3642       {
3643         sieb_x = x;
3644         sieb_y = y;
3645       }
3646     }
3647   }
3648
3649   if (game.magic_wall_active)
3650   {
3651     if (!(game.magic_wall_time_left % 4))
3652       PlaySoundLevel(sieb_x, sieb_y, SND_MIEP);
3653
3654     if (game.magic_wall_time_left > 0)
3655     {
3656       game.magic_wall_time_left--;
3657       if (!game.magic_wall_time_left)
3658       {
3659         for (y=0; y<lev_fieldy; y++) for (x=0; x<lev_fieldx; x++)
3660         {
3661           element = Feld[x][y];
3662           if (element == EL_SIEB_LEER || element == EL_SIEB_VOLL)
3663           {
3664             Feld[x][y] = EL_SIEB_TOT;
3665             DrawLevelField(x, y);
3666           }
3667           else if (element == EL_SIEB2_LEER || element == EL_SIEB2_VOLL)
3668           {
3669             Feld[x][y] = EL_SIEB2_TOT;
3670             DrawLevelField(x, y);
3671           }
3672         }
3673
3674         game.magic_wall_active = FALSE;
3675       }
3676     }
3677   }
3678
3679   if (TimeFrames >= (1000 / GameFrameDelay) && !tape.pausing)
3680   {
3681     TimeFrames = 0;
3682     TimePlayed++;
3683
3684     if (tape.recording || tape.playing)
3685       DrawVideoDisplay(VIDEO_STATE_TIME_ON, TimePlayed);
3686
3687     if (TimeLeft > 0)
3688     {
3689       TimeLeft--;
3690
3691       if (TimeLeft <= 10)
3692         PlaySoundStereo(SND_GONG, PSND_MAX_RIGHT);
3693
3694       DrawText(DX_TIME, DY_TIME, int2str(TimeLeft, 3), FS_SMALL, FC_YELLOW);
3695
3696       if (!TimeLeft)
3697         for (i=0; i<MAX_PLAYERS; i++)
3698           KillHero(&stored_player[i]);
3699     }
3700     else if (level.time == 0)           /* level without time limit */
3701       DrawText(DX_TIME, DY_TIME, int2str(TimePlayed, 3), FS_SMALL, FC_YELLOW);
3702   }
3703
3704   DrawAllPlayers();
3705 }
3706
3707 static boolean AllPlayersInSight(struct PlayerInfo *player, int x, int y)
3708 {
3709   int min_x = x, min_y = y, max_x = x, max_y = y;
3710   int i;
3711
3712   for (i=0; i<MAX_PLAYERS; i++)
3713   {
3714     int jx = stored_player[i].jx, jy = stored_player[i].jy;
3715
3716     if (!stored_player[i].active || &stored_player[i] == player)
3717       continue;
3718
3719     min_x = MIN(min_x, jx);
3720     min_y = MIN(min_y, jy);
3721     max_x = MAX(max_x, jx);
3722     max_y = MAX(max_y, jy);
3723   }
3724
3725   return (max_x - min_x < SCR_FIELDX && max_y - min_y < SCR_FIELDY);
3726 }
3727
3728 static boolean AllPlayersInVisibleScreen()
3729 {
3730   int i;
3731
3732   for (i=0; i<MAX_PLAYERS; i++)
3733   {
3734     int jx = stored_player[i].jx, jy = stored_player[i].jy;
3735
3736     if (!stored_player[i].active)
3737       continue;
3738
3739     if (!IN_VIS_FIELD(SCREENX(jx), SCREENY(jy)))
3740       return FALSE;
3741   }
3742
3743   return TRUE;
3744 }
3745
3746 void ScrollLevel(int dx, int dy)
3747 {
3748   int softscroll_offset = (setup.soft_scrolling ? TILEX : 0);
3749   int x, y;
3750
3751   XCopyArea(display, drawto_field, drawto_field, gc,
3752             FX + TILEX*(dx == -1) - softscroll_offset,
3753             FY + TILEY*(dy == -1) - softscroll_offset,
3754             SXSIZE - TILEX*(dx!=0) + 2*softscroll_offset,
3755             SYSIZE - TILEY*(dy!=0) + 2*softscroll_offset,
3756             FX + TILEX*(dx == 1) - softscroll_offset,
3757             FY + TILEY*(dy == 1) - softscroll_offset);
3758
3759   if (dx)
3760   {
3761     x = (dx == 1 ? BX1 : BX2);
3762     for (y=BY1; y<=BY2; y++)
3763       DrawScreenField(x, y);
3764   }
3765   if (dy)
3766   {
3767     y = (dy == 1 ? BY1 : BY2);
3768     for (x=BX1; x<=BX2; x++)
3769       DrawScreenField(x, y);
3770   }
3771
3772   redraw_mask |= REDRAW_FIELD;
3773 }
3774
3775 static void CheckGravityMovement(struct PlayerInfo *player)
3776 {
3777   if (level.gravity && !player->programmed_action)
3778   {
3779     int move_dir_vertical = player->action & (MV_UP | MV_DOWN);
3780     int move_dir_horizontal = player->action & (MV_LEFT | MV_RIGHT);
3781     int move_dir =
3782       (player->last_move_dir & (MV_LEFT | MV_RIGHT) ?
3783        (move_dir_vertical ? move_dir_vertical : move_dir_horizontal) :
3784        (move_dir_horizontal ? move_dir_horizontal : move_dir_vertical));
3785     int jx = player->jx, jy = player->jy;
3786     int dx = (move_dir & MV_LEFT ? -1 : move_dir & MV_RIGHT ? +1 : 0);
3787     int dy = (move_dir & MV_UP ? -1 : move_dir & MV_DOWN ? +1 : 0);
3788     int new_jx = jx + dx, new_jy = jy + dy;
3789     boolean field_under_player_is_free =
3790       (IN_LEV_FIELD(jx, jy + 1) && IS_FREE(jx, jy + 1));
3791     boolean player_is_moving_to_valid_field =
3792       (IN_LEV_FIELD(new_jx, new_jy) &&
3793        (Feld[new_jx][new_jy] == EL_SP_BASE ||
3794         Feld[new_jx][new_jy] == EL_ERDREICH));
3795
3796     if (field_under_player_is_free && !player_is_moving_to_valid_field)
3797       player->programmed_action = MV_DOWN;
3798   }
3799 }
3800
3801 boolean MoveFigureOneStep(struct PlayerInfo *player,
3802                           int dx, int dy, int real_dx, int real_dy)
3803 {
3804   int jx = player->jx, jy = player->jy;
3805   int new_jx = jx+dx, new_jy = jy+dy;
3806   int element;
3807   int can_move;
3808
3809   if (!player->active || (!dx && !dy))
3810     return MF_NO_ACTION;
3811
3812   player->MovDir = (dx < 0 ? MV_LEFT :
3813                     dx > 0 ? MV_RIGHT :
3814                     dy < 0 ? MV_UP :
3815                     dy > 0 ? MV_DOWN :  MV_NO_MOVING);
3816
3817   if (!IN_LEV_FIELD(new_jx, new_jy))
3818     return MF_NO_ACTION;
3819
3820   if (!options.network && !AllPlayersInSight(player, new_jx, new_jy))
3821     return MF_NO_ACTION;
3822
3823 #if 0
3824   element = MovingOrBlocked2Element(new_jx, new_jy);
3825 #else
3826   element = MovingOrBlocked2ElementIfNotLeaving(new_jx, new_jy);
3827 #endif
3828
3829   if (DONT_GO_TO(element))
3830   {
3831     if (element == EL_SALZSAEURE && dx == 0 && dy == 1)
3832     {
3833       Blurb(jx, jy);
3834       Feld[jx][jy] = EL_SPIELFIGUR;
3835       InitMovingField(jx, jy, MV_DOWN);
3836       Store[jx][jy] = EL_SALZSAEURE;
3837       ContinueMoving(jx, jy);
3838       BuryHero(player);
3839     }
3840     else
3841       KillHero(player);
3842
3843     return MF_MOVING;
3844   }
3845
3846   can_move = DigField(player, new_jx, new_jy, real_dx, real_dy, DF_DIG);
3847   if (can_move != MF_MOVING)
3848     return can_move;
3849
3850   StorePlayer[jx][jy] = 0;
3851   player->last_jx = jx;
3852   player->last_jy = jy;
3853   jx = player->jx = new_jx;
3854   jy = player->jy = new_jy;
3855   StorePlayer[jx][jy] = player->element_nr;
3856
3857   player->MovPos =
3858     (dx > 0 || dy > 0 ? -1 : 1) * (TILEX - TILEX / player->move_delay_value);
3859
3860   ScrollFigure(player, SCROLL_INIT);
3861
3862   return MF_MOVING;
3863 }
3864
3865 boolean MoveFigure(struct PlayerInfo *player, int dx, int dy)
3866 {
3867   int jx = player->jx, jy = player->jy;
3868   int old_jx = jx, old_jy = jy;
3869   int moved = MF_NO_ACTION;
3870
3871   if (!player->active || (!dx && !dy))
3872     return FALSE;
3873
3874   if (!FrameReached(&player->move_delay, player->move_delay_value) &&
3875       !tape.playing)
3876     return FALSE;
3877
3878   /* remove the last programmed player action */
3879   player->programmed_action = 0;
3880
3881   if (player->MovPos)
3882   {
3883     /* should only happen if pre-1.2 tape recordings are played */
3884     /* this is only for backward compatibility */
3885
3886     int original_move_delay_value = player->move_delay_value;
3887
3888 #if DEBUG
3889     printf("THIS SHOULD ONLY HAPPEN WITH PRE-1.2 LEVEL TAPES.\n");
3890 #endif
3891
3892     /* scroll remaining steps with finest movement resolution */
3893     player->move_delay_value = MOVE_DELAY_NORMAL_SPEED;
3894
3895     while (player->MovPos)
3896     {
3897       ScrollFigure(player, SCROLL_GO_ON);
3898       ScrollScreen(NULL, SCROLL_GO_ON);
3899       FrameCounter++;
3900       DrawAllPlayers();
3901       BackToFront();
3902     }
3903
3904     player->move_delay_value = original_move_delay_value;
3905   }
3906
3907   if (player->last_move_dir & (MV_LEFT | MV_RIGHT))
3908   {
3909     if (!(moved |= MoveFigureOneStep(player, 0, dy, dx, dy)))
3910       moved |= MoveFigureOneStep(player, dx, 0, dx, dy);
3911   }
3912   else
3913   {
3914     if (!(moved |= MoveFigureOneStep(player, dx, 0, dx, dy)))
3915       moved |= MoveFigureOneStep(player, 0, dy, dx, dy);
3916   }
3917
3918   jx = player->jx;
3919   jy = player->jy;
3920
3921   if (moved & MF_MOVING && !ScreenMovPos &&
3922       (player == local_player || !options.network))
3923   {
3924     int old_scroll_x = scroll_x, old_scroll_y = scroll_y;
3925     int offset = (setup.scroll_delay ? 3 : 0);
3926
3927     if (!IN_VIS_FIELD(SCREENX(jx), SCREENY(jy)))
3928     {
3929       /* actual player has left the screen -- scroll in that direction */
3930       if (jx != old_jx)         /* player has moved horizontally */
3931         scroll_x += (jx - old_jx);
3932       else                      /* player has moved vertically */
3933         scroll_y += (jy - old_jy);
3934     }
3935     else
3936     {
3937       if (jx != old_jx)         /* player has moved horizontally */
3938       {
3939         if ((player->MovDir == MV_LEFT && scroll_x > jx - MIDPOSX + offset) ||
3940             (player->MovDir == MV_RIGHT && scroll_x < jx - MIDPOSX - offset))
3941           scroll_x = jx-MIDPOSX + (scroll_x < jx-MIDPOSX ? -offset : +offset);
3942
3943         /* don't scroll over playfield boundaries */
3944         if (scroll_x < SBX_Left || scroll_x > SBX_Right)
3945           scroll_x = (scroll_x < SBX_Left ? SBX_Left : SBX_Right);
3946
3947         /* don't scroll more than one field at a time */
3948         scroll_x = old_scroll_x + SIGN(scroll_x - old_scroll_x);
3949
3950         /* don't scroll against the player's moving direction */
3951         if ((player->MovDir == MV_LEFT && scroll_x > old_scroll_x) ||
3952             (player->MovDir == MV_RIGHT && scroll_x < old_scroll_x))
3953           scroll_x = old_scroll_x;
3954       }
3955       else                      /* player has moved vertically */
3956       {
3957         if ((player->MovDir == MV_UP && scroll_y > jy - MIDPOSY + offset) ||
3958             (player->MovDir == MV_DOWN && scroll_y < jy - MIDPOSY - offset))
3959           scroll_y = jy-MIDPOSY + (scroll_y < jy-MIDPOSY ? -offset : +offset);
3960
3961         /* don't scroll over playfield boundaries */
3962         if (scroll_y < SBY_Upper || scroll_y > SBY_Lower)
3963           scroll_y = (scroll_y < SBY_Upper ? SBY_Upper : SBY_Lower);
3964
3965         /* don't scroll more than one field at a time */
3966         scroll_y = old_scroll_y + SIGN(scroll_y - old_scroll_y);
3967
3968         /* don't scroll against the player's moving direction */
3969         if ((player->MovDir == MV_UP && scroll_y > old_scroll_y) ||
3970             (player->MovDir == MV_DOWN && scroll_y < old_scroll_y))
3971           scroll_y = old_scroll_y;
3972       }
3973     }
3974
3975     if (scroll_x != old_scroll_x || scroll_y != old_scroll_y)
3976     {
3977       if (!options.network && !AllPlayersInVisibleScreen())
3978       {
3979         scroll_x = old_scroll_x;
3980         scroll_y = old_scroll_y;
3981       }
3982       else
3983       {
3984         ScrollScreen(player, SCROLL_INIT);
3985         ScrollLevel(old_scroll_x - scroll_x, old_scroll_y - scroll_y);
3986       }
3987     }
3988   }
3989
3990   if (!(moved & MF_MOVING) && !player->Pushing)
3991     player->Frame = 0;
3992   else
3993     player->Frame = (player->Frame + 1) % 4;
3994
3995   if (moved & MF_MOVING)
3996   {
3997     if (old_jx != jx && old_jy == jy)
3998       player->MovDir = (old_jx < jx ? MV_RIGHT : MV_LEFT);
3999     else if (old_jx == jx && old_jy != jy)
4000       player->MovDir = (old_jy < jy ? MV_DOWN : MV_UP);
4001
4002     DrawLevelField(jx, jy);     /* for "ErdreichAnbroeckeln()" */
4003
4004     player->last_move_dir = player->MovDir;
4005   }
4006   else
4007   {
4008     CheckGravityMovement(player);
4009
4010     player->last_move_dir = MV_NO_MOVING;
4011   }
4012
4013   TestIfHeroHitsBadThing(jx, jy);
4014
4015   if (!player->active)
4016     RemoveHero(player);
4017
4018   return moved;
4019 }
4020
4021 void ScrollFigure(struct PlayerInfo *player, int mode)
4022 {
4023   int jx = player->jx, jy = player->jy;
4024   int last_jx = player->last_jx, last_jy = player->last_jy;
4025   int move_stepsize = TILEX / player->move_delay_value;
4026
4027   if (!player->active || !player->MovPos)
4028     return;
4029
4030   if (mode == SCROLL_INIT)
4031   {
4032     player->actual_frame_counter = FrameCounter;
4033     player->GfxPos = move_stepsize * (player->MovPos / move_stepsize);
4034
4035     if (Feld[last_jx][last_jy] == EL_LEERRAUM)
4036       Feld[last_jx][last_jy] = EL_PLAYER_IS_LEAVING;
4037
4038     DrawPlayer(player);
4039     return;
4040   }
4041   else if (!FrameReached(&player->actual_frame_counter, 1))
4042     return;
4043
4044   player->MovPos += (player->MovPos > 0 ? -1 : 1) * move_stepsize;
4045   player->GfxPos = move_stepsize * (player->MovPos / move_stepsize);
4046
4047   if (Feld[last_jx][last_jy] == EL_PLAYER_IS_LEAVING)
4048     Feld[last_jx][last_jy] = EL_LEERRAUM;
4049
4050   /* before DrawPlayer() to draw correct player graphic for this case */
4051   if (player->MovPos == 0)
4052     CheckGravityMovement(player);
4053
4054   DrawPlayer(player);
4055
4056   if (player->MovPos == 0)
4057   {
4058     if (IS_QUICK_GATE(Feld[last_jx][last_jy]))
4059     {
4060       /* continue with normal speed after quickly moving through gate */
4061       HALVE_PLAYER_SPEED(player);
4062
4063       /* be able to make the next move without delay */
4064       player->move_delay = 0;
4065     }
4066
4067     player->last_jx = jx;
4068     player->last_jy = jy;
4069
4070     if (Feld[jx][jy] == EL_AUSGANG_AUF)
4071     {
4072       RemoveHero(player);
4073
4074       if (!local_player->friends_still_needed)
4075         player->LevelSolved = player->GameOver = TRUE;
4076     }
4077   }
4078 }
4079
4080 void ScrollScreen(struct PlayerInfo *player, int mode)
4081 {
4082   static unsigned long screen_frame_counter = 0;
4083
4084   if (mode == SCROLL_INIT)
4085   {
4086     /* set scrolling step size according to actual player's moving speed */
4087     ScrollStepSize = TILEX / player->move_delay_value;
4088
4089     screen_frame_counter = FrameCounter;
4090     ScreenMovDir = player->MovDir;
4091     ScreenMovPos = player->MovPos;
4092     ScreenGfxPos = ScrollStepSize * (ScreenMovPos / ScrollStepSize);
4093     return;
4094   }
4095   else if (!FrameReached(&screen_frame_counter, 1))
4096     return;
4097
4098   if (ScreenMovPos)
4099   {
4100     ScreenMovPos += (ScreenMovPos > 0 ? -1 : 1) * ScrollStepSize;
4101     ScreenGfxPos = ScrollStepSize * (ScreenMovPos / ScrollStepSize);
4102     redraw_mask |= REDRAW_FIELD;
4103   }
4104   else
4105     ScreenMovDir = MV_NO_MOVING;
4106 }
4107
4108 void TestIfGoodThingHitsBadThing(int goodx, int goody)
4109 {
4110   int i, killx = goodx, killy = goody;
4111   static int xy[4][2] =
4112   {
4113     { 0, -1 },
4114     { -1, 0 },
4115     { +1, 0 },
4116     { 0, +1 }
4117   };
4118   static int harmless[4] =
4119   {
4120     MV_UP,
4121     MV_LEFT,
4122     MV_RIGHT,
4123     MV_DOWN
4124   };
4125
4126   for (i=0; i<4; i++)
4127   {
4128     int x, y, element;
4129
4130     x = goodx + xy[i][0];
4131     y = goody + xy[i][1];
4132     if (!IN_LEV_FIELD(x, y))
4133       continue;
4134
4135 #if 0
4136     element = Feld[x][y];
4137 #else
4138     element = MovingOrBlocked2ElementIfNotLeaving(x, y);
4139 #endif
4140
4141     if (DONT_TOUCH(element))
4142     {
4143       if (MovDir[x][y] == harmless[i])
4144         continue;
4145
4146       killx = x;
4147       killy = y;
4148       break;
4149     }
4150   }
4151
4152   if (killx != goodx || killy != goody)
4153   {
4154     if (IS_PLAYER(goodx, goody))
4155       KillHero(PLAYERINFO(goodx, goody));
4156     else
4157       Bang(goodx, goody);
4158   }
4159 }
4160
4161 void TestIfBadThingHitsGoodThing(int badx, int bady)
4162 {
4163   int i, killx = badx, killy = bady;
4164   static int xy[4][2] =
4165   {
4166     { 0, -1 },
4167     { -1, 0 },
4168     { +1, 0 },
4169     { 0, +1 }
4170   };
4171   static int harmless[4] =
4172   {
4173     MV_UP,
4174     MV_LEFT,
4175     MV_RIGHT,
4176     MV_DOWN
4177   };
4178
4179   for (i=0; i<4; i++)
4180   {
4181     int x, y, element;
4182
4183     x = badx + xy[i][0];
4184     y = bady + xy[i][1];
4185     if (!IN_LEV_FIELD(x, y))
4186       continue;
4187
4188     element = Feld[x][y];
4189
4190     if (IS_PLAYER(x, y))
4191     {
4192       killx = x;
4193       killy = y;
4194       break;
4195     }
4196     else if (element == EL_PINGUIN)
4197     {
4198       if (MovDir[x][y] == harmless[i] && IS_MOVING(x, y))
4199         continue;
4200
4201       killx = x;
4202       killy = y;
4203       break;
4204     }
4205   }
4206
4207   if (killx != badx || killy != bady)
4208   {
4209     if (IS_PLAYER(killx, killy))
4210       KillHero(PLAYERINFO(killx, killy));
4211     else
4212       Bang(killx, killy);
4213   }
4214 }
4215
4216 void TestIfHeroHitsBadThing(int x, int y)
4217 {
4218   TestIfGoodThingHitsBadThing(x, y);
4219 }
4220
4221 void TestIfBadThingHitsHero(int x, int y)
4222 {
4223   TestIfBadThingHitsGoodThing(x, y);
4224 }
4225
4226 void TestIfFriendHitsBadThing(int x, int y)
4227 {
4228   TestIfGoodThingHitsBadThing(x, y);
4229 }
4230
4231 void TestIfBadThingHitsFriend(int x, int y)
4232 {
4233   TestIfBadThingHitsGoodThing(x, y);
4234 }
4235
4236 void TestIfBadThingHitsOtherBadThing(int badx, int bady)
4237 {
4238   int i, killx = badx, killy = bady;
4239   static int xy[4][2] =
4240   {
4241     { 0, -1 },
4242     { -1, 0 },
4243     { +1, 0 },
4244     { 0, +1 }
4245   };
4246
4247   for (i=0; i<4; i++)
4248   {
4249     int x, y, element;
4250
4251     x=badx + xy[i][0];
4252     y=bady + xy[i][1];
4253     if (!IN_LEV_FIELD(x, y))
4254       continue;
4255
4256     element = Feld[x][y];
4257     if (IS_AMOEBOID(element) || element == EL_LIFE ||
4258         element == EL_AMOEBING || element == EL_TROPFEN)
4259     {
4260       killx = x;
4261       killy = y;
4262       break;
4263     }
4264   }
4265
4266   if (killx != badx || killy != bady)
4267     Bang(badx, bady);
4268 }
4269
4270 void KillHero(struct PlayerInfo *player)
4271 {
4272   int jx = player->jx, jy = player->jy;
4273
4274   if (!player->active)
4275     return;
4276
4277   if (IS_PFORTE(Feld[jx][jy]))
4278     Feld[jx][jy] = EL_LEERRAUM;
4279
4280   Bang(jx, jy);
4281   BuryHero(player);
4282 }
4283
4284 void BuryHero(struct PlayerInfo *player)
4285 {
4286   int jx = player->jx, jy = player->jy;
4287
4288   if (!player->active)
4289     return;
4290
4291   PlaySoundLevel(jx, jy, SND_AUTSCH);
4292   PlaySoundLevel(jx, jy, SND_LACHEN);
4293
4294   player->GameOver = TRUE;
4295   RemoveHero(player);
4296 }
4297
4298 void RemoveHero(struct PlayerInfo *player)
4299 {
4300   int jx = player->jx, jy = player->jy;
4301   int i, found = FALSE;
4302
4303   player->present = FALSE;
4304   player->active = FALSE;
4305
4306   StorePlayer[jx][jy] = 0;
4307
4308   for (i=0; i<MAX_PLAYERS; i++)
4309     if (stored_player[i].active)
4310       found = TRUE;
4311
4312   if (!found)
4313     AllPlayersGone = TRUE;
4314
4315   ExitX = ZX = jx;
4316   ExitY = ZY = jy;
4317 }
4318
4319 int DigField(struct PlayerInfo *player,
4320              int x, int y, int real_dx, int real_dy, int mode)
4321 {
4322   int jx = player->jx, jy = player->jy;
4323   int dx = x - jx, dy = y - jy;
4324   int move_direction = (dx == -1 ? MV_LEFT :
4325                         dx == +1 ? MV_RIGHT :
4326                         dy == -1 ? MV_UP :
4327                         dy == +1 ? MV_DOWN : MV_NO_MOVING);
4328   int element;
4329
4330   if (!player->MovPos)
4331     player->Pushing = FALSE;
4332
4333   if (mode == DF_NO_PUSH)
4334   {
4335     player->push_delay = 0;
4336     return MF_NO_ACTION;
4337   }
4338
4339   if (IS_MOVING(x, y) || IS_PLAYER(x, y))
4340     return MF_NO_ACTION;
4341
4342   element = Feld[x][y];
4343
4344   switch(element)
4345   {
4346     case EL_LEERRAUM:
4347       PlaySoundLevel(x, y, SND_EMPTY);
4348       break;
4349
4350     case EL_ERDREICH:
4351       Feld[x][y] = EL_LEERRAUM;
4352       PlaySoundLevel(x, y, SND_SCHLURF);
4353       break;
4354
4355     case EL_SP_BASE:
4356     case EL_SP_BUG:
4357       Feld[x][y] = EL_LEERRAUM;
4358       PlaySoundLevel(x, y, SND_SP_BASE);
4359       break;
4360
4361     case EL_EDELSTEIN:
4362     case EL_EDELSTEIN_BD:
4363     case EL_EDELSTEIN_GELB:
4364     case EL_EDELSTEIN_ROT:
4365     case EL_EDELSTEIN_LILA:
4366     case EL_DIAMANT:
4367     case EL_SP_INFOTRON:
4368       RemoveField(x, y);
4369       local_player->gems_still_needed -= (element == EL_DIAMANT ? 3 : 1);
4370       if (local_player->gems_still_needed < 0)
4371         local_player->gems_still_needed = 0;
4372       RaiseScoreElement(element);
4373       DrawText(DX_EMERALDS, DY_EMERALDS,
4374                int2str(local_player->gems_still_needed, 3),
4375                FS_SMALL, FC_YELLOW);
4376       if (element == EL_SP_INFOTRON)
4377         PlaySoundLevel(x, y, SND_SP_INFOTRON);
4378       else
4379         PlaySoundLevel(x, y, SND_PONG);
4380       break;
4381
4382     case EL_SPEED_PILL:
4383       RemoveField(x, y);
4384       player->move_delay_value = MOVE_DELAY_HIGH_SPEED;
4385       PlaySoundLevel(x, y, SND_PONG);
4386       break;
4387
4388     case EL_DYNAMIT_AUS:
4389     case EL_SP_DISK_RED:
4390       RemoveField(x, y);
4391       player->dynamite++;
4392       RaiseScoreElement(EL_DYNAMIT);
4393       DrawText(DX_DYNAMITE, DY_DYNAMITE,
4394                int2str(local_player->dynamite, 3),
4395                FS_SMALL, FC_YELLOW);
4396       if (element == EL_SP_DISK_RED)
4397         PlaySoundLevel(x, y, SND_SP_INFOTRON);
4398       else
4399         PlaySoundLevel(x, y, SND_PONG);
4400       break;
4401
4402     case EL_DYNABOMB_NR:
4403       RemoveField(x, y);
4404       player->dynabomb_count++;
4405       player->dynabombs_left++;
4406       RaiseScoreElement(EL_DYNAMIT);
4407       PlaySoundLevel(x, y, SND_PONG);
4408       break;
4409
4410     case EL_DYNABOMB_SZ:
4411       RemoveField(x, y);
4412       player->dynabomb_size++;
4413       RaiseScoreElement(EL_DYNAMIT);
4414       PlaySoundLevel(x, y, SND_PONG);
4415       break;
4416
4417     case EL_DYNABOMB_XL:
4418       RemoveField(x, y);
4419       player->dynabomb_xl = TRUE;
4420       RaiseScoreElement(EL_DYNAMIT);
4421       PlaySoundLevel(x, y, SND_PONG);
4422       break;
4423
4424     case EL_SCHLUESSEL1:
4425     case EL_SCHLUESSEL2:
4426     case EL_SCHLUESSEL3:
4427     case EL_SCHLUESSEL4:
4428     {
4429       int key_nr = element - EL_SCHLUESSEL1;
4430
4431       RemoveField(x, y);
4432       player->key[key_nr] = TRUE;
4433       RaiseScoreElement(EL_SCHLUESSEL);
4434       DrawMiniGraphicExt(drawto, gc,
4435                          DX_KEYS+key_nr*MINI_TILEX, DY_KEYS,
4436                          GFX_SCHLUESSEL1+key_nr);
4437       DrawMiniGraphicExt(window, gc,
4438                          DX_KEYS+key_nr*MINI_TILEX, DY_KEYS,
4439                          GFX_SCHLUESSEL1+key_nr);
4440       PlaySoundLevel(x, y, SND_PONG);
4441       break;
4442     }
4443
4444     case EL_EM_KEY_1:
4445     case EL_EM_KEY_2:
4446     case EL_EM_KEY_3:
4447     case EL_EM_KEY_4:
4448     {
4449       int key_nr = element - EL_EM_KEY_1;
4450
4451       RemoveField(x, y);
4452       player->key[key_nr] = TRUE;
4453       RaiseScoreElement(EL_SCHLUESSEL);
4454       DrawMiniGraphicExt(drawto, gc,
4455                          DX_KEYS+key_nr*MINI_TILEX, DY_KEYS,
4456                          GFX_SCHLUESSEL1+key_nr);
4457       DrawMiniGraphicExt(window, gc,
4458                          DX_KEYS+key_nr*MINI_TILEX, DY_KEYS,
4459                          GFX_SCHLUESSEL1+key_nr);
4460       PlaySoundLevel(x, y, SND_PONG);
4461       break;
4462     }
4463
4464     case EL_ABLENK_AUS:
4465       Feld[x][y] = EL_ABLENK_EIN;
4466       ZX = x;
4467       ZY = y;
4468       DrawLevelField(x, y);
4469       return MF_ACTION;
4470       break;
4471
4472     case EL_SP_TERMINAL:
4473       {
4474         int xx, yy;
4475
4476         for (yy=0; yy<lev_fieldy; yy++)
4477         {
4478           for (xx=0; xx<lev_fieldx; xx++)
4479           {
4480             if (Feld[xx][yy] == EL_SP_DISK_YELLOW)
4481               Bang(xx, yy);
4482             else if (Feld[xx][yy] == EL_SP_TERMINAL)
4483               Feld[xx][yy] = EL_SP_TERMINAL_ACTIVE;
4484           }
4485         }
4486
4487         return MF_ACTION;
4488       }
4489       break;
4490
4491     case EL_SP_EXIT:
4492       if (local_player->gems_still_needed > 0)
4493         return MF_NO_ACTION;
4494
4495       player->LevelSolved = player->GameOver = TRUE;
4496       PlaySoundStereo(SND_SP_EXIT, PSND_MAX_RIGHT);
4497       break;
4498
4499     case EL_FELSBROCKEN:
4500     case EL_BOMBE:
4501     case EL_KOKOSNUSS:
4502     case EL_ZEIT_LEER:
4503     case EL_SP_ZONK:
4504     case EL_SP_DISK_ORANGE:
4505       if (dy || mode == DF_SNAP)
4506         return MF_NO_ACTION;
4507
4508       player->Pushing = TRUE;
4509
4510       if (!IN_LEV_FIELD(x+dx, y+dy) || !IS_FREE(x+dx, y+dy))
4511         return MF_NO_ACTION;
4512
4513       if (real_dy)
4514       {
4515         if (IN_LEV_FIELD(jx, jy+real_dy) && !IS_SOLID(Feld[jx][jy+real_dy]))
4516           return MF_NO_ACTION;
4517       }
4518
4519       if (player->push_delay == 0)
4520         player->push_delay = FrameCounter;
4521       if (!FrameReached(&player->push_delay, player->push_delay_value) &&
4522           !tape.playing)
4523         return MF_NO_ACTION;
4524
4525       RemoveField(x, y);
4526       Feld[x+dx][y+dy] = element;
4527
4528       player->push_delay_value = 2+RND(8);
4529
4530       DrawLevelField(x+dx, y+dy);
4531       if (element == EL_FELSBROCKEN)
4532         PlaySoundLevel(x+dx, y+dy, SND_PUSCH);
4533       else if (element == EL_KOKOSNUSS)
4534         PlaySoundLevel(x+dx, y+dy, SND_KNURK);
4535       else if (IS_SP_ELEMENT(element))
4536         PlaySoundLevel(x+dx, y+dy, SND_SP_ZONKPUSH);
4537       else
4538         PlaySoundLevel(x+dx, y+dy, SND_KLOPF);
4539       break;
4540
4541     case EL_PFORTE1:
4542     case EL_PFORTE2:
4543     case EL_PFORTE3:
4544     case EL_PFORTE4:
4545       if (!player->key[element - EL_PFORTE1])
4546         return MF_NO_ACTION;
4547       break;
4548
4549     case EL_PFORTE1X:
4550     case EL_PFORTE2X:
4551     case EL_PFORTE3X:
4552     case EL_PFORTE4X:
4553       if (!player->key[element - EL_PFORTE1X])
4554         return MF_NO_ACTION;
4555       break;
4556
4557     case EL_EM_GATE_1:
4558     case EL_EM_GATE_2:
4559     case EL_EM_GATE_3:
4560     case EL_EM_GATE_4:
4561       if (!player->key[element - EL_EM_GATE_1])
4562         return MF_NO_ACTION;
4563       if (!IN_LEV_FIELD(x + dx, y + dy) || !IS_FREE(x + dx, y + dy))
4564         return MF_NO_ACTION;
4565
4566       /* automatically move to the next field with double speed */
4567       player->programmed_action = move_direction;
4568       DOUBLE_PLAYER_SPEED(player);
4569
4570       break;
4571
4572     case EL_EM_GATE_1X:
4573     case EL_EM_GATE_2X:
4574     case EL_EM_GATE_3X:
4575     case EL_EM_GATE_4X:
4576       if (!player->key[element - EL_EM_GATE_1X])
4577         return MF_NO_ACTION;
4578       if (!IN_LEV_FIELD(x + dx, y + dy) || !IS_FREE(x + dx, y + dy))
4579         return MF_NO_ACTION;
4580
4581       /* automatically move to the next field with double speed */
4582       player->programmed_action = move_direction;
4583       DOUBLE_PLAYER_SPEED(player);
4584
4585       break;
4586
4587     case EL_SP_PORT1_LEFT:
4588     case EL_SP_PORT2_LEFT:
4589     case EL_SP_PORT1_RIGHT:
4590     case EL_SP_PORT2_RIGHT:
4591     case EL_SP_PORT1_UP:
4592     case EL_SP_PORT2_UP:
4593     case EL_SP_PORT1_DOWN:
4594     case EL_SP_PORT2_DOWN:
4595     case EL_SP_PORT_X:
4596     case EL_SP_PORT_Y:
4597     case EL_SP_PORT_XY:
4598       if ((dx == -1 &&
4599            element != EL_SP_PORT1_LEFT &&
4600            element != EL_SP_PORT2_LEFT &&
4601            element != EL_SP_PORT_X &&
4602            element != EL_SP_PORT_XY) ||
4603           (dx == +1 &&
4604            element != EL_SP_PORT1_RIGHT &&
4605            element != EL_SP_PORT2_RIGHT &&
4606            element != EL_SP_PORT_X &&
4607            element != EL_SP_PORT_XY) ||
4608           (dy == -1 &&
4609            element != EL_SP_PORT1_UP &&
4610            element != EL_SP_PORT2_UP &&
4611            element != EL_SP_PORT_Y &&
4612            element != EL_SP_PORT_XY) ||
4613           (dy == +1 &&
4614            element != EL_SP_PORT1_DOWN &&
4615            element != EL_SP_PORT2_DOWN &&
4616            element != EL_SP_PORT_Y &&
4617            element != EL_SP_PORT_XY) ||
4618           !IN_LEV_FIELD(x + dx, y + dy) ||
4619           !IS_FREE(x + dx, y + dy))
4620         return MF_NO_ACTION;
4621
4622       /* automatically move to the next field with double speed */
4623       player->programmed_action = move_direction;
4624       DOUBLE_PLAYER_SPEED(player);
4625
4626       break;
4627
4628     case EL_AUSGANG_ZU:
4629     case EL_AUSGANG_ACT:
4630       /* door is not (yet) open */
4631       return MF_NO_ACTION;
4632       break;
4633
4634     case EL_AUSGANG_AUF:
4635       if (mode == DF_SNAP)
4636         return MF_NO_ACTION;
4637
4638       PlaySoundLevel(x, y, SND_BUING);
4639
4640       break;
4641
4642     case EL_BIRNE_AUS:
4643       Feld[x][y] = EL_BIRNE_EIN;
4644       local_player->lights_still_needed--;
4645       DrawLevelField(x, y);
4646       PlaySoundLevel(x, y, SND_DENG);
4647       return MF_ACTION;
4648       break;
4649
4650     case EL_ZEIT_VOLL:
4651       Feld[x][y] = EL_ZEIT_LEER;
4652       TimeLeft += 10;
4653       DrawText(DX_TIME, DY_TIME, int2str(TimeLeft, 3), FS_SMALL, FC_YELLOW);
4654       DrawLevelField(x, y);
4655       PlaySoundStereo(SND_GONG, PSND_MAX_RIGHT);
4656       return MF_ACTION;
4657       break;
4658
4659     case EL_SOKOBAN_FELD_LEER:
4660       break;
4661
4662     case EL_SOKOBAN_FELD_VOLL:
4663     case EL_SOKOBAN_OBJEKT:
4664     case EL_SONDE:
4665     case EL_SP_DISK_YELLOW:
4666       if (mode == DF_SNAP)
4667         return MF_NO_ACTION;
4668
4669       player->Pushing = TRUE;
4670
4671       if (!IN_LEV_FIELD(x+dx, y+dy)
4672           || (!IS_FREE(x+dx, y+dy)
4673               && (Feld[x+dx][y+dy] != EL_SOKOBAN_FELD_LEER
4674                   || !IS_SB_ELEMENT(element))))
4675         return MF_NO_ACTION;
4676
4677       if (dx && real_dy)
4678       {
4679         if (IN_LEV_FIELD(jx, jy+real_dy) && !IS_SOLID(Feld[jx][jy+real_dy]))
4680           return MF_NO_ACTION;
4681       }
4682       else if (dy && real_dx)
4683       {
4684         if (IN_LEV_FIELD(jx+real_dx, jy) && !IS_SOLID(Feld[jx+real_dx][jy]))
4685           return MF_NO_ACTION;
4686       }
4687
4688       if (player->push_delay == 0)
4689         player->push_delay = FrameCounter;
4690       if (!FrameReached(&player->push_delay, player->push_delay_value) &&
4691           !tape.playing)
4692         return MF_NO_ACTION;
4693
4694       if (IS_SB_ELEMENT(element))
4695       {
4696         if (element == EL_SOKOBAN_FELD_VOLL)
4697         {
4698           Feld[x][y] = EL_SOKOBAN_FELD_LEER;
4699           local_player->sokobanfields_still_needed++;
4700         }
4701         else
4702           RemoveField(x, y);
4703
4704         if (Feld[x+dx][y+dy] == EL_SOKOBAN_FELD_LEER)
4705         {
4706           Feld[x+dx][y+dy] = EL_SOKOBAN_FELD_VOLL;
4707           local_player->sokobanfields_still_needed--;
4708           if (element == EL_SOKOBAN_OBJEKT)
4709             PlaySoundLevel(x, y, SND_DENG);
4710         }
4711         else
4712           Feld[x+dx][y+dy] = EL_SOKOBAN_OBJEKT;
4713       }
4714       else
4715       {
4716         RemoveField(x, y);
4717         Feld[x+dx][y+dy] = element;
4718       }
4719
4720       player->push_delay_value = 2;
4721
4722       DrawLevelField(x, y);
4723       DrawLevelField(x+dx, y+dy);
4724       PlaySoundLevel(x+dx, y+dy, SND_PUSCH);
4725
4726       if (IS_SB_ELEMENT(element) &&
4727           local_player->sokobanfields_still_needed == 0 &&
4728           game.emulation == EMU_SOKOBAN)
4729       {
4730         player->LevelSolved = player->GameOver = TRUE;
4731         PlaySoundLevel(x, y, SND_BUING);
4732       }
4733
4734       break;
4735
4736     case EL_MAULWURF:
4737     case EL_PINGUIN:
4738     case EL_SCHWEIN:
4739     case EL_DRACHE:
4740       break;
4741
4742     default:
4743       return MF_NO_ACTION;
4744   }
4745
4746   player->push_delay = 0;
4747
4748   return MF_MOVING;
4749 }
4750
4751 boolean SnapField(struct PlayerInfo *player, int dx, int dy)
4752 {
4753   int jx = player->jx, jy = player->jy;
4754   int x = jx + dx, y = jy + dy;
4755
4756   if (!player->active || !IN_LEV_FIELD(x, y))
4757     return FALSE;
4758
4759   if (dx && dy)
4760     return FALSE;
4761
4762   if (!dx && !dy)
4763   {
4764     player->snapped = FALSE;
4765     return FALSE;
4766   }
4767
4768   if (player->snapped)
4769     return FALSE;
4770
4771   player->MovDir = (dx < 0 ? MV_LEFT :
4772                     dx > 0 ? MV_RIGHT :
4773                     dy < 0 ? MV_UP :
4774                     dy > 0 ? MV_DOWN :  MV_NO_MOVING);
4775
4776   if (!DigField(player, x, y, 0, 0, DF_SNAP))
4777     return FALSE;
4778
4779   player->snapped = TRUE;
4780   DrawLevelField(x, y);
4781   BackToFront();
4782
4783   return TRUE;
4784 }
4785
4786 boolean PlaceBomb(struct PlayerInfo *player)
4787 {
4788   int jx = player->jx, jy = player->jy;
4789   int element;
4790
4791   if (!player->active || player->MovPos)
4792     return FALSE;
4793
4794   element = Feld[jx][jy];
4795
4796   if ((player->dynamite == 0 && player->dynabombs_left == 0) ||
4797       element == EL_DYNAMIT || element == EL_DYNABOMB ||
4798       element == EL_EXPLODING)
4799     return FALSE;
4800
4801   if (element != EL_LEERRAUM)
4802     Store[jx][jy] = element;
4803
4804   if (player->dynamite)
4805   {
4806     Feld[jx][jy] = EL_DYNAMIT;
4807     MovDelay[jx][jy] = 96;
4808     player->dynamite--;
4809     DrawText(DX_DYNAMITE, DY_DYNAMITE, int2str(local_player->dynamite, 3),
4810              FS_SMALL, FC_YELLOW);
4811     if (IN_SCR_FIELD(SCREENX(jx), SCREENY(jy)))
4812     {
4813       if (game.emulation == EMU_SUPAPLEX)
4814         DrawGraphic(SCREENX(jx), SCREENY(jy), GFX_SP_DISK_RED);
4815       else
4816         DrawGraphicThruMask(SCREENX(jx), SCREENY(jy), GFX_DYNAMIT);
4817     }
4818   }
4819   else
4820   {
4821     Feld[jx][jy] = EL_DYNABOMB;
4822     Store2[jx][jy] = player->element_nr;        /* for DynaExplode() */
4823     MovDelay[jx][jy] = 96;
4824     player->dynabombs_left--;
4825     if (IN_SCR_FIELD(SCREENX(jx), SCREENY(jy)))
4826       DrawGraphicThruMask(SCREENX(jx), SCREENY(jy), GFX_DYNABOMB);
4827   }
4828
4829   return TRUE;
4830 }
4831
4832 void PlaySoundLevel(int x, int y, int sound_nr)
4833 {
4834   int sx = SCREENX(x), sy = SCREENY(y);
4835   int volume, stereo;
4836   int silence_distance = 8;
4837
4838   if ((!setup.sound_simple && !IS_LOOP_SOUND(sound_nr)) ||
4839       (!setup.sound_loops && IS_LOOP_SOUND(sound_nr)))
4840     return;
4841
4842   if (!IN_LEV_FIELD(x, y) ||
4843       sx < -silence_distance || sx >= SCR_FIELDX+silence_distance ||
4844       sy < -silence_distance || sy >= SCR_FIELDY+silence_distance)
4845     return;
4846
4847   volume = PSND_MAX_VOLUME;
4848
4849 #ifndef MSDOS
4850   stereo = (sx - SCR_FIELDX/2) * 12;
4851 #else
4852   stereo = PSND_MIDDLE + (2 * sx - (SCR_FIELDX - 1)) * 5;
4853   if (stereo > PSND_MAX_RIGHT)
4854     stereo = PSND_MAX_RIGHT;
4855   if (stereo < PSND_MAX_LEFT)
4856     stereo = PSND_MAX_LEFT;
4857 #endif
4858
4859   if (!IN_SCR_FIELD(sx, sy))
4860   {
4861     int dx = ABS(sx - SCR_FIELDX/2) - SCR_FIELDX/2;
4862     int dy = ABS(sy - SCR_FIELDY/2) - SCR_FIELDY/2;
4863
4864     volume -= volume * (dx > dy ? dx : dy) / silence_distance;
4865   }
4866
4867   PlaySoundExt(sound_nr, volume, stereo, PSND_NO_LOOP);
4868 }
4869
4870 void RaiseScore(int value)
4871 {
4872   local_player->score += value;
4873   DrawText(DX_SCORE, DY_SCORE, int2str(local_player->score, 5),
4874            FS_SMALL, FC_YELLOW);
4875 }
4876
4877 void RaiseScoreElement(int element)
4878 {
4879   switch(element)
4880   {
4881     case EL_EDELSTEIN:
4882     case EL_EDELSTEIN_BD:
4883     case EL_EDELSTEIN_GELB:
4884     case EL_EDELSTEIN_ROT:
4885     case EL_EDELSTEIN_LILA:
4886       RaiseScore(level.score[SC_EDELSTEIN]);
4887       break;
4888     case EL_DIAMANT:
4889       RaiseScore(level.score[SC_DIAMANT]);
4890       break;
4891     case EL_KAEFER:
4892     case EL_BUTTERFLY:
4893       RaiseScore(level.score[SC_KAEFER]);
4894       break;
4895     case EL_FLIEGER:
4896     case EL_FIREFLY:
4897       RaiseScore(level.score[SC_FLIEGER]);
4898       break;
4899     case EL_MAMPFER:
4900     case EL_MAMPFER2:
4901       RaiseScore(level.score[SC_MAMPFER]);
4902       break;
4903     case EL_ROBOT:
4904       RaiseScore(level.score[SC_ROBOT]);
4905       break;
4906     case EL_PACMAN:
4907       RaiseScore(level.score[SC_PACMAN]);
4908       break;
4909     case EL_KOKOSNUSS:
4910       RaiseScore(level.score[SC_KOKOSNUSS]);
4911       break;
4912     case EL_DYNAMIT:
4913       RaiseScore(level.score[SC_DYNAMIT]);
4914       break;
4915     case EL_SCHLUESSEL:
4916       RaiseScore(level.score[SC_SCHLUESSEL]);
4917       break;
4918     default:
4919       break;
4920   }
4921 }
4922
4923 /* ---------- new game button stuff ---------------------------------------- */
4924
4925 /* graphic position values for game buttons */
4926 #define GAME_BUTTON_XSIZE       30
4927 #define GAME_BUTTON_YSIZE       30
4928 #define GAME_BUTTON_XPOS        5
4929 #define GAME_BUTTON_YPOS        215
4930 #define SOUND_BUTTON_XPOS       5
4931 #define SOUND_BUTTON_YPOS       (GAME_BUTTON_YPOS + GAME_BUTTON_YSIZE)
4932
4933 #define GAME_BUTTON_STOP_XPOS   (GAME_BUTTON_XPOS + 0 * GAME_BUTTON_XSIZE)
4934 #define GAME_BUTTON_PAUSE_XPOS  (GAME_BUTTON_XPOS + 1 * GAME_BUTTON_XSIZE)
4935 #define GAME_BUTTON_PLAY_XPOS   (GAME_BUTTON_XPOS + 2 * GAME_BUTTON_XSIZE)
4936 #define SOUND_BUTTON_MUSIC_XPOS (SOUND_BUTTON_XPOS + 0 * GAME_BUTTON_XSIZE)
4937 #define SOUND_BUTTON_LOOPS_XPOS (SOUND_BUTTON_XPOS + 1 * GAME_BUTTON_XSIZE)
4938 #define SOUND_BUTTON_SIMPLE_XPOS (SOUND_BUTTON_XPOS + 2 * GAME_BUTTON_XSIZE)
4939
4940 static struct
4941 {
4942   int x, y;
4943   int gadget_id;
4944   char *infotext;
4945 } gamebutton_info[NUM_GAME_BUTTONS] =
4946 {
4947   {
4948     GAME_BUTTON_STOP_XPOS,      GAME_BUTTON_YPOS,
4949     GAME_CTRL_ID_STOP,
4950     "stop game"
4951   },
4952   {
4953     GAME_BUTTON_PAUSE_XPOS,     GAME_BUTTON_YPOS,
4954     GAME_CTRL_ID_PAUSE,
4955     "pause game"
4956   },
4957   {
4958     GAME_BUTTON_PLAY_XPOS,      GAME_BUTTON_YPOS,
4959     GAME_CTRL_ID_PLAY,
4960     "play game"
4961   },
4962   {
4963     SOUND_BUTTON_MUSIC_XPOS,    SOUND_BUTTON_YPOS,
4964     SOUND_CTRL_ID_MUSIC,
4965     "background music on/off"
4966   },
4967   {
4968     SOUND_BUTTON_LOOPS_XPOS,    SOUND_BUTTON_YPOS,
4969     SOUND_CTRL_ID_LOOPS,
4970     "sound loops on/off"
4971   },
4972   {
4973     SOUND_BUTTON_SIMPLE_XPOS,   SOUND_BUTTON_YPOS,
4974     SOUND_CTRL_ID_SIMPLE,
4975     "normal sounds on/off"
4976   }
4977 };
4978
4979 void CreateGameButtons()
4980 {
4981   int i;
4982
4983   for (i=0; i<NUM_GAME_BUTTONS; i++)
4984   {
4985     Pixmap gd_pixmap = pix[PIX_DOOR];
4986     struct GadgetInfo *gi;
4987     int button_type;
4988     boolean checked;
4989     unsigned long event_mask;
4990     int gd_xoffset, gd_yoffset;
4991     int gd_x1, gd_x2, gd_y1, gd_y2;
4992     int id = i;
4993
4994     gd_xoffset = gamebutton_info[i].x;
4995     gd_yoffset = gamebutton_info[i].y;
4996     gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
4997     gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
4998
4999     if (id == GAME_CTRL_ID_STOP ||
5000         id == GAME_CTRL_ID_PAUSE ||
5001         id == GAME_CTRL_ID_PLAY)
5002     {
5003       button_type = GD_TYPE_NORMAL_BUTTON;
5004       checked = FALSE;
5005       event_mask = GD_EVENT_RELEASED;
5006       gd_y1  = DOOR_GFX_PAGEY1 + gd_yoffset - GAME_BUTTON_YSIZE;
5007       gd_y2  = DOOR_GFX_PAGEY1 + gd_yoffset - GAME_BUTTON_YSIZE;
5008     }
5009     else
5010     {
5011       button_type = GD_TYPE_CHECK_BUTTON;
5012       checked =
5013         ((id == SOUND_CTRL_ID_MUSIC && setup.sound_music) ||
5014          (id == SOUND_CTRL_ID_LOOPS && setup.sound_loops) ||
5015          (id == SOUND_CTRL_ID_SIMPLE && setup.sound_simple) ? TRUE : FALSE);
5016       event_mask = GD_EVENT_PRESSED;
5017       gd_y1  = DOOR_GFX_PAGEY1 + gd_yoffset;
5018       gd_y2  = DOOR_GFX_PAGEY1 + gd_yoffset - GAME_BUTTON_YSIZE;
5019     }
5020
5021     gi = CreateGadget(GDI_CUSTOM_ID, id,
5022                       GDI_INFO_TEXT, gamebutton_info[i].infotext,
5023                       GDI_X, DX + gd_xoffset,
5024                       GDI_Y, DY + gd_yoffset,
5025                       GDI_WIDTH, GAME_BUTTON_XSIZE,
5026                       GDI_HEIGHT, GAME_BUTTON_YSIZE,
5027                       GDI_TYPE, button_type,
5028                       GDI_STATE, GD_BUTTON_UNPRESSED,
5029                       GDI_CHECKED, checked,
5030                       GDI_DESIGN_UNPRESSED, gd_pixmap, gd_x1, gd_y1,
5031                       GDI_DESIGN_PRESSED, gd_pixmap, gd_x2, gd_y1,
5032                       GDI_ALT_DESIGN_UNPRESSED, gd_pixmap, gd_x1, gd_y2,
5033                       GDI_ALT_DESIGN_PRESSED, gd_pixmap, gd_x2, gd_y2,
5034                       GDI_EVENT_MASK, event_mask,
5035                       GDI_CALLBACK_ACTION, HandleGameButtons,
5036                       GDI_END);
5037
5038     if (gi == NULL)
5039       Error(ERR_EXIT, "cannot create gadget");
5040
5041     game_gadget[id] = gi;
5042   }
5043 }
5044
5045 static void MapGameButtons()
5046 {
5047   int i;
5048
5049   for (i=0; i<NUM_GAME_BUTTONS; i++)
5050     MapGadget(game_gadget[i]);
5051 }
5052
5053 void UnmapGameButtons()
5054 {
5055   int i;
5056
5057   for (i=0; i<NUM_GAME_BUTTONS; i++)
5058     UnmapGadget(game_gadget[i]);
5059 }
5060
5061 static void HandleGameButtons(struct GadgetInfo *gi)
5062 {
5063   int id = gi->custom_id;
5064
5065   if (game_status != PLAYING)
5066     return;
5067
5068   switch (id)
5069   {
5070     case GAME_CTRL_ID_STOP:
5071       if (AllPlayersGone)
5072       {
5073         CloseDoor(DOOR_CLOSE_1);
5074         game_status = MAINMENU;
5075         DrawMainMenu();
5076         break;
5077       }
5078
5079       if (level_editor_test_game ||
5080           Request("Do you really want to quit the game ?",
5081                   REQ_ASK | REQ_STAY_CLOSED))
5082       { 
5083 #ifndef MSDOS
5084         if (options.network)
5085           SendToServer_StopPlaying();
5086         else
5087 #endif
5088         {
5089           game_status = MAINMENU;
5090           DrawMainMenu();
5091         }
5092       }
5093       else
5094         OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
5095       break;
5096
5097     case GAME_CTRL_ID_PAUSE:
5098       if (options.network)
5099       {
5100 #ifndef MSDOS
5101         if (tape.pausing)
5102           SendToServer_ContinuePlaying();
5103         else
5104           SendToServer_PausePlaying();
5105 #endif
5106       }
5107       else
5108         TapeTogglePause();
5109       break;
5110
5111     case GAME_CTRL_ID_PLAY:
5112       if (tape.pausing)
5113       {
5114 #ifndef MSDOS
5115         if (options.network)
5116           SendToServer_ContinuePlaying();
5117         else
5118 #endif
5119         {
5120           tape.pausing = FALSE;
5121           DrawVideoDisplay(VIDEO_STATE_PAUSE_OFF,0);
5122         }
5123       }
5124       break;
5125
5126     case SOUND_CTRL_ID_MUSIC:
5127       if (setup.sound_music)
5128       { 
5129         setup.sound_music = FALSE;
5130         FadeSound(background_loop[level_nr % num_bg_loops]);
5131       }
5132       else if (sound_loops_allowed)
5133       { 
5134         setup.sound = setup.sound_music = TRUE;
5135         PlaySoundLoop(background_loop[level_nr % num_bg_loops]);
5136       }
5137       break;
5138
5139     case SOUND_CTRL_ID_LOOPS:
5140       if (setup.sound_loops)
5141         setup.sound_loops = FALSE;
5142       else if (sound_loops_allowed)
5143         setup.sound = setup.sound_loops = TRUE;
5144       break;
5145
5146     case SOUND_CTRL_ID_SIMPLE:
5147       if (setup.sound_simple)
5148         setup.sound_simple = FALSE;
5149       else if (sound_status==SOUND_AVAILABLE)
5150         setup.sound = setup.sound_simple = TRUE;
5151       break;
5152
5153     default:
5154       break;
5155   }
5156 }