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