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