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