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