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