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