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