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