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