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