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