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