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