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