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