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