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