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