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