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