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