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