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