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