rnd-19990809-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 void Impact(int x, int y)
1527 {
1528   boolean lastline = (y == lev_fieldy-1);
1529   boolean object_hit = FALSE;
1530   int element = Feld[x][y];
1531   int smashed = 0;
1532
1533   if (!lastline)        /* check if element below was hit */
1534   {
1535     if (Feld[x][y+1] == EL_PLAYER_IS_LEAVING)
1536       return;
1537
1538     object_hit = (!IS_FREE(x, y+1) && (!IS_MOVING(x, y+1) ||
1539                                       MovDir[x][y+1]!=MV_DOWN ||
1540                                       MovPos[x][y+1]<=TILEY/2));
1541     if (object_hit)
1542       smashed = MovingOrBlocked2Element(x, y+1);
1543   }
1544
1545   if (!lastline && smashed == EL_SALZSAEURE)    /* element falls into acid */
1546   {
1547     Blurb(x, y);
1548     return;
1549   }
1550
1551   if ((element == EL_BOMBE || element == EL_SP_DISK_ORANGE) &&
1552       (lastline || object_hit)) /* element is bomb */
1553   {
1554     Bang(x, y);
1555     return;
1556   }
1557
1558   if (element == EL_TROPFEN && (lastline || object_hit))        /* acid drop */
1559   {
1560     if (object_hit && IS_PLAYER(x, y+1))
1561       KillHero(PLAYERINFO(x, y+1));
1562     else if (object_hit && (smashed == EL_MAULWURF || smashed == EL_PINGUIN))
1563       Bang(x, y+1);
1564     else
1565     {
1566       Feld[x][y] = EL_AMOEBING;
1567       Store[x][y] = EL_AMOEBE_NASS;
1568     }
1569     return;
1570   }
1571
1572   if (!lastline && object_hit)          /* check which object was hit */
1573   {
1574     if (CAN_CHANGE(element) && 
1575         (smashed == EL_SIEB_INAKTIV || smashed == EL_SIEB2_INAKTIV))
1576     {
1577       int x, y;
1578       int activated_magic_wall =
1579         (smashed == EL_SIEB_INAKTIV ? EL_SIEB_LEER : EL_SIEB2_LEER);
1580
1581       /* activate magic wall / mill */
1582
1583       for (y=0; y<lev_fieldy; y++)
1584         for (x=0; x<lev_fieldx; x++)
1585           if (Feld[x][y] == smashed)
1586             Feld[x][y] = activated_magic_wall;
1587
1588       game.magic_wall_time_left = level.time_magic_wall * FRAMES_PER_SECOND;
1589       game.magic_wall_active = TRUE;
1590     }
1591
1592     if (IS_PLAYER(x, y+1))
1593     {
1594       KillHero(PLAYERINFO(x, y+1));
1595       return;
1596     }
1597     else if (smashed == EL_MAULWURF || smashed == EL_PINGUIN)
1598     {
1599       Bang(x, y+1);
1600       return;
1601     }
1602     else if (element == EL_EDELSTEIN_BD)
1603     {
1604       if (IS_ENEMY(smashed) && IS_BD_ELEMENT(smashed))
1605       {
1606         Bang(x, y+1);
1607         return;
1608       }
1609     }
1610     else if (element == EL_FELSBROCKEN || element == EL_SP_ZONK)
1611     {
1612       if (IS_ENEMY(smashed) ||
1613           smashed == EL_BOMBE || smashed == EL_SP_DISK_ORANGE ||
1614           smashed == EL_SONDE || smashed == EL_SCHWEIN || smashed == EL_DRACHE)
1615       {
1616         Bang(x, y+1);
1617         return;
1618       }
1619       else if (!IS_MOVING(x, y+1))
1620       {
1621         if (smashed == EL_BIRNE_AUS || smashed == EL_BIRNE_EIN)
1622         {
1623           Bang(x, y+1);
1624           return;
1625         }
1626         else if (smashed == EL_KOKOSNUSS)
1627         {
1628           Feld[x][y+1] = EL_CRACKINGNUT;
1629           PlaySoundLevel(x, y, SND_KNACK);
1630           RaiseScoreElement(EL_KOKOSNUSS);
1631           return;
1632         }
1633         else if (smashed == EL_DIAMANT)
1634         {
1635           Feld[x][y+1] = EL_LEERRAUM;
1636           PlaySoundLevel(x, y, SND_QUIRK);
1637           return;
1638         }
1639       }
1640     }
1641   }
1642
1643   /* play sound of magic wall / mill */
1644   if (!lastline &&
1645       (Feld[x][y+1] == EL_SIEB_LEER || Feld[x][y+1] == EL_SIEB2_LEER))
1646   {
1647     PlaySoundLevel(x, y, SND_QUIRK);
1648     return;
1649   }
1650
1651   /* play sound of object that hits the ground */
1652   if (lastline || object_hit)
1653   {
1654     int sound;
1655
1656     switch(element)
1657     {
1658       case EL_EDELSTEIN:
1659       case EL_EDELSTEIN_BD:
1660       case EL_EDELSTEIN_GELB:
1661       case EL_EDELSTEIN_ROT:
1662       case EL_EDELSTEIN_LILA:
1663       case EL_DIAMANT:
1664       case EL_SP_INFOTRON:
1665         sound = SND_PLING;
1666         break;
1667       case EL_KOKOSNUSS:
1668         sound = SND_KLUMPF;
1669         break;
1670       case EL_FELSBROCKEN:
1671         sound = SND_KLOPF;
1672         break;
1673       case EL_SP_ZONK:
1674         sound = SND_SP_ZONKDOWN;
1675         break;
1676       case EL_SCHLUESSEL:
1677       case EL_SCHLUESSEL1:
1678       case EL_SCHLUESSEL2:
1679       case EL_SCHLUESSEL3:
1680       case EL_SCHLUESSEL4:
1681       case EL_EM_KEY_1:
1682       case EL_EM_KEY_2:
1683       case EL_EM_KEY_3:
1684       case EL_EM_KEY_4:
1685         sound = SND_KINK;
1686         break;
1687       case EL_ZEIT_VOLL:
1688       case EL_ZEIT_LEER:
1689         sound = SND_DENG;
1690         break;
1691       default:
1692         sound = -1;
1693         break;
1694     }
1695
1696     if (sound>=0)
1697       PlaySoundLevel(x, y, sound);
1698   }
1699 }
1700
1701 void TurnRound(int x, int y)
1702 {
1703   static struct
1704   {
1705     int x, y;
1706   } move_xy[] =
1707   {
1708     { 0, 0 },
1709     {-1, 0 },
1710     {+1, 0 },
1711     { 0, 0 },
1712     { 0, -1 },
1713     { 0, 0 }, { 0, 0 }, { 0, 0 },
1714     { 0, +1 }
1715   };
1716   static struct
1717   {
1718     int left, right, back;
1719   } turn[] =
1720   {
1721     { 0,        0,              0 },
1722     { MV_DOWN,  MV_UP,          MV_RIGHT },
1723     { MV_UP,    MV_DOWN,        MV_LEFT },
1724     { 0,        0,              0 },
1725     { MV_LEFT,  MV_RIGHT,       MV_DOWN },
1726     { 0,0,0 },  { 0,0,0 },      { 0,0,0 },
1727     { MV_RIGHT, MV_LEFT,        MV_UP }
1728   };
1729
1730   int element = Feld[x][y];
1731   int old_move_dir = MovDir[x][y];
1732   int left_dir = turn[old_move_dir].left;
1733   int right_dir = turn[old_move_dir].right;
1734   int back_dir = turn[old_move_dir].back;
1735
1736   int left_dx = move_xy[left_dir].x, left_dy = move_xy[left_dir].y;
1737   int right_dx = move_xy[right_dir].x, right_dy = move_xy[right_dir].y;
1738   int move_dx = move_xy[old_move_dir].x, move_dy = move_xy[old_move_dir].y;
1739   int back_dx = move_xy[back_dir].x, back_dy = move_xy[back_dir].y;
1740
1741   int left_x = x+left_dx, left_y = y+left_dy;
1742   int right_x = x+right_dx, right_y = y+right_dy;
1743   int move_x = x+move_dx, move_y = y+move_dy;
1744
1745   if (element == EL_KAEFER || element == EL_BUTTERFLY)
1746   {
1747     TestIfBadThingHitsOtherBadThing(x, y);
1748
1749     if (IN_LEV_FIELD(right_x, right_y) &&
1750         IS_FREE_OR_PLAYER(right_x, right_y))
1751       MovDir[x][y] = right_dir;
1752     else if (!IN_LEV_FIELD(move_x, move_y) ||
1753              !IS_FREE_OR_PLAYER(move_x, move_y))
1754       MovDir[x][y] = left_dir;
1755
1756     if (element == EL_KAEFER && MovDir[x][y] != old_move_dir)
1757       MovDelay[x][y] = 9;
1758     else if (element == EL_BUTTERFLY)   /* && MovDir[x][y] == left_dir) */
1759       MovDelay[x][y] = 1;
1760   }
1761   else if (element == EL_FLIEGER || element == EL_FIREFLY ||
1762            element == EL_SP_SNIKSNAK || element == EL_SP_ELECTRON)
1763   {
1764     TestIfBadThingHitsOtherBadThing(x, y);
1765
1766     if (IN_LEV_FIELD(left_x, left_y) &&
1767         IS_FREE_OR_PLAYER(left_x, left_y))
1768       MovDir[x][y] = left_dir;
1769     else if (!IN_LEV_FIELD(move_x, move_y) ||
1770              !IS_FREE_OR_PLAYER(move_x, move_y))
1771       MovDir[x][y] = right_dir;
1772
1773     if ((element == EL_FLIEGER ||
1774          element == EL_SP_SNIKSNAK || element == EL_SP_ELECTRON)
1775         && MovDir[x][y] != old_move_dir)
1776       MovDelay[x][y] = 9;
1777     else if (element == EL_FIREFLY)     /* && MovDir[x][y] == right_dir) */
1778       MovDelay[x][y] = 1;
1779   }
1780   else if (element == EL_MAMPFER)
1781   {
1782     boolean can_turn_left = FALSE, can_turn_right = FALSE;
1783
1784     if (IN_LEV_FIELD(left_x, left_y) &&
1785         (IS_FREE_OR_PLAYER(left_x, left_y) ||
1786          Feld[left_x][left_y] == EL_DIAMANT))
1787       can_turn_left = TRUE;
1788     if (IN_LEV_FIELD(right_x, right_y) &&
1789         (IS_FREE_OR_PLAYER(right_x, right_y) ||
1790          Feld[right_x][right_y] == EL_DIAMANT))
1791       can_turn_right = TRUE;
1792
1793     if (can_turn_left && can_turn_right)
1794       MovDir[x][y] = (RND(3) ? (RND(2) ? left_dir : right_dir) : back_dir);
1795     else if (can_turn_left)
1796       MovDir[x][y] = (RND(2) ? left_dir : back_dir);
1797     else if (can_turn_right)
1798       MovDir[x][y] = (RND(2) ? right_dir : back_dir);
1799     else
1800       MovDir[x][y] = back_dir;
1801
1802     MovDelay[x][y] = 16+16*RND(3);
1803   }
1804   else if (element == EL_MAMPFER2)
1805   {
1806     boolean can_turn_left = FALSE, can_turn_right = FALSE;
1807
1808     if (IN_LEV_FIELD(left_x, left_y) &&
1809         (IS_FREE_OR_PLAYER(left_x, left_y) ||
1810          IS_MAMPF2(Feld[left_x][left_y])))
1811       can_turn_left = TRUE;
1812     if (IN_LEV_FIELD(right_x, right_y) &&
1813         (IS_FREE_OR_PLAYER(right_x, right_y) ||
1814          IS_MAMPF2(Feld[right_x][right_y])))
1815       can_turn_right = TRUE;
1816
1817     if (can_turn_left && can_turn_right)
1818       MovDir[x][y] = (RND(3) ? (RND(2) ? left_dir : right_dir) : back_dir);
1819     else if (can_turn_left)
1820       MovDir[x][y] = (RND(2) ? left_dir : back_dir);
1821     else if (can_turn_right)
1822       MovDir[x][y] = (RND(2) ? right_dir : back_dir);
1823     else
1824       MovDir[x][y] = back_dir;
1825
1826     MovDelay[x][y] = 16+16*RND(3);
1827   }
1828   else if (element == EL_PACMAN)
1829   {
1830     boolean can_turn_left = FALSE, can_turn_right = FALSE;
1831
1832     if (IN_LEV_FIELD(left_x, left_y) &&
1833         (IS_FREE_OR_PLAYER(left_x, left_y) ||
1834          IS_AMOEBOID(Feld[left_x][left_y])))
1835       can_turn_left = TRUE;
1836     if (IN_LEV_FIELD(right_x, right_y) &&
1837         (IS_FREE_OR_PLAYER(right_x, right_y) ||
1838          IS_AMOEBOID(Feld[right_x][right_y])))
1839       can_turn_right = TRUE;
1840
1841     if (can_turn_left && can_turn_right)
1842       MovDir[x][y] = (RND(3) ? (RND(2) ? left_dir : right_dir) : back_dir);
1843     else if (can_turn_left)
1844       MovDir[x][y] = (RND(2) ? left_dir : back_dir);
1845     else if (can_turn_right)
1846       MovDir[x][y] = (RND(2) ? right_dir : back_dir);
1847     else
1848       MovDir[x][y] = back_dir;
1849
1850     MovDelay[x][y] = 6+RND(40);
1851   }
1852   else if (element == EL_SCHWEIN)
1853   {
1854     boolean can_turn_left = FALSE, can_turn_right = FALSE, can_move_on = FALSE;
1855     boolean should_turn_left = FALSE, should_turn_right = FALSE;
1856     boolean should_move_on = FALSE;
1857     int rnd_value = 24;
1858     int rnd = RND(rnd_value);
1859
1860     if (IN_LEV_FIELD(left_x, left_y) &&
1861         (IS_FREE(left_x, left_y) || IS_GEM(Feld[left_x][left_y])))
1862       can_turn_left = TRUE;
1863     if (IN_LEV_FIELD(right_x, right_y) &&
1864         (IS_FREE(right_x, right_y) || IS_GEM(Feld[right_x][right_y])))
1865       can_turn_right = TRUE;
1866     if (IN_LEV_FIELD(move_x, move_y) &&
1867         (IS_FREE(move_x, move_y) || IS_GEM(Feld[move_x][move_y])))
1868       can_move_on = TRUE;
1869
1870     if (can_turn_left &&
1871         (!can_move_on ||
1872          (IN_LEV_FIELD(x+back_dx+left_dx, y+back_dy+left_dy) &&
1873           !IS_FREE(x+back_dx+left_dx, y+back_dy+left_dy))))
1874       should_turn_left = TRUE;
1875     if (can_turn_right &&
1876         (!can_move_on ||
1877          (IN_LEV_FIELD(x+back_dx+right_dx, y+back_dy+right_dy) &&
1878           !IS_FREE(x+back_dx+right_dx, y+back_dy+right_dy))))
1879       should_turn_right = TRUE;
1880     if (can_move_on &&
1881         (!can_turn_left || !can_turn_right ||
1882          (IN_LEV_FIELD(x+move_dx+left_dx, y+move_dy+left_dy) &&
1883           !IS_FREE(x+move_dx+left_dx, y+move_dy+left_dy)) ||
1884          (IN_LEV_FIELD(x+move_dx+right_dx, y+move_dy+right_dy) &&
1885           !IS_FREE(x+move_dx+right_dx, y+move_dy+right_dy))))
1886       should_move_on = TRUE;
1887
1888     if (should_turn_left || should_turn_right || should_move_on)
1889     {
1890       if (should_turn_left && should_turn_right && should_move_on)
1891         MovDir[x][y] = (rnd < rnd_value/3 ? left_dir :
1892                         rnd < 2*rnd_value/3 ? right_dir :
1893                         old_move_dir);
1894       else if (should_turn_left && should_turn_right)
1895         MovDir[x][y] = (rnd < rnd_value/2 ? left_dir : right_dir);
1896       else if (should_turn_left && should_move_on)
1897         MovDir[x][y] = (rnd < rnd_value/2 ? left_dir : old_move_dir);
1898       else if (should_turn_right && should_move_on)
1899         MovDir[x][y] = (rnd < rnd_value/2 ? right_dir : old_move_dir);
1900       else if (should_turn_left)
1901         MovDir[x][y] = left_dir;
1902       else if (should_turn_right)
1903         MovDir[x][y] = right_dir;
1904       else if (should_move_on)
1905         MovDir[x][y] = old_move_dir;
1906     }
1907     else if (can_move_on && rnd > rnd_value/8)
1908       MovDir[x][y] = old_move_dir;
1909     else if (can_turn_left && can_turn_right)
1910       MovDir[x][y] = (rnd < rnd_value/2 ? left_dir : right_dir);
1911     else if (can_turn_left && rnd > rnd_value/8)
1912       MovDir[x][y] = left_dir;
1913     else if (can_turn_right && rnd > rnd_value/8)
1914       MovDir[x][y] = right_dir;
1915     else
1916       MovDir[x][y] = back_dir;
1917
1918     if (!IS_FREE(x+move_xy[MovDir[x][y]].x, y+move_xy[MovDir[x][y]].y) &&
1919         !IS_GEM(Feld[x+move_xy[MovDir[x][y]].x][y+move_xy[MovDir[x][y]].y]))
1920       MovDir[x][y] = old_move_dir;
1921
1922     MovDelay[x][y] = 0;
1923   }
1924   else if (element == EL_DRACHE)
1925   {
1926     boolean can_turn_left = FALSE, can_turn_right = FALSE, can_move_on = FALSE;
1927     int rnd_value = 24;
1928     int rnd = RND(rnd_value);
1929
1930     if (IN_LEV_FIELD(left_x, left_y) && IS_FREE(left_x, left_y))
1931       can_turn_left = TRUE;
1932     if (IN_LEV_FIELD(right_x, right_y) && IS_FREE(right_x, right_y))
1933       can_turn_right = TRUE;
1934     if (IN_LEV_FIELD(move_x, move_y) && IS_FREE(move_x, move_y))
1935       can_move_on = TRUE;
1936
1937     if (can_move_on && rnd > rnd_value/8)
1938       MovDir[x][y] = old_move_dir;
1939     else if (can_turn_left && can_turn_right)
1940       MovDir[x][y] = (rnd < rnd_value/2 ? left_dir : right_dir);
1941     else if (can_turn_left && rnd > rnd_value/8)
1942       MovDir[x][y] = left_dir;
1943     else if (can_turn_right && rnd > rnd_value/8)
1944       MovDir[x][y] = right_dir;
1945     else
1946       MovDir[x][y] = back_dir;
1947
1948     if (!IS_FREE(x+move_xy[MovDir[x][y]].x, y+move_xy[MovDir[x][y]].y))
1949       MovDir[x][y] = old_move_dir;
1950
1951     MovDelay[x][y] = 0;
1952   }
1953   else if (element == EL_ROBOT || element == EL_SONDE ||
1954            element == EL_MAULWURF || element == EL_PINGUIN)
1955   {
1956     int attr_x = -1, attr_y = -1;
1957
1958     if (AllPlayersGone)
1959     {
1960       attr_x = ExitX;
1961       attr_y = ExitY;
1962     }
1963     else
1964     {
1965       int i;
1966
1967       for (i=0; i<MAX_PLAYERS; i++)
1968       {
1969         struct PlayerInfo *player = &stored_player[i];
1970         int jx = player->jx, jy = player->jy;
1971
1972         if (!player->active)
1973           continue;
1974
1975         if (attr_x == -1 || ABS(jx-x)+ABS(jy-y) < ABS(attr_x-x)+ABS(attr_y-y))
1976         {
1977           attr_x = jx;
1978           attr_y = jy;
1979         }
1980       }
1981     }
1982
1983     if (element == EL_ROBOT && ZX>=0 && ZY>=0)
1984     {
1985       attr_x = ZX;
1986       attr_y = ZY;
1987     }
1988
1989     if (element == EL_MAULWURF || element == EL_PINGUIN)
1990     {
1991       int i;
1992       static int xy[4][2] =
1993       {
1994         { 0, -1 },
1995         { -1, 0 },
1996         { +1, 0 },
1997         { 0, +1 }
1998       };
1999
2000       for (i=0; i<4; i++)
2001       {
2002         int ex = x + xy[i%4][0];
2003         int ey = y + xy[i%4][1];
2004
2005         if (IN_LEV_FIELD(ex, ey) && Feld[ex][ey] == EL_AUSGANG_AUF)
2006         {
2007           attr_x = ex;
2008           attr_y = ey;
2009           break;
2010         }
2011       }
2012     }
2013
2014     MovDir[x][y] = MV_NO_MOVING;
2015     if (attr_x<x)
2016       MovDir[x][y] |= (AllPlayersGone ? MV_RIGHT : MV_LEFT);
2017     else if (attr_x>x)
2018       MovDir[x][y] |= (AllPlayersGone ? MV_LEFT : MV_RIGHT);
2019     if (attr_y<y)
2020       MovDir[x][y] |= (AllPlayersGone ? MV_DOWN : MV_UP);
2021     else if (attr_y>y)
2022       MovDir[x][y] |= (AllPlayersGone ? MV_UP : MV_DOWN);
2023
2024     if (element == EL_ROBOT)
2025     {
2026       int newx, newy;
2027
2028       if ((MovDir[x][y]&(MV_LEFT|MV_RIGHT)) && (MovDir[x][y]&(MV_UP|MV_DOWN)))
2029         MovDir[x][y] &= (RND(2) ? (MV_LEFT|MV_RIGHT) : (MV_UP|MV_DOWN));
2030       Moving2Blocked(x, y, &newx, &newy);
2031
2032       if (IN_LEV_FIELD(newx, newy) && IS_FREE_OR_PLAYER(newx, newy))
2033         MovDelay[x][y] = 8+8*!RND(3);
2034       else
2035         MovDelay[x][y] = 16;
2036     }
2037     else
2038     {
2039       int newx, newy;
2040
2041       MovDelay[x][y] = 1;
2042
2043       if ((MovDir[x][y]&(MV_LEFT|MV_RIGHT)) && (MovDir[x][y]&(MV_UP|MV_DOWN)))
2044       {
2045         boolean first_horiz = RND(2);
2046         int new_move_dir = MovDir[x][y];
2047
2048         MovDir[x][y] =
2049           new_move_dir & (first_horiz ? (MV_LEFT|MV_RIGHT) : (MV_UP|MV_DOWN));
2050         Moving2Blocked(x, y, &newx, &newy);
2051
2052         if (IN_LEV_FIELD(newx, newy) &&
2053             (IS_FREE(newx, newy) ||
2054              Feld[newx][newy] == EL_SALZSAEURE ||
2055              ((element == EL_MAULWURF || element == EL_PINGUIN) &&
2056               (Feld[newx][newy] == EL_AUSGANG_AUF ||
2057                IS_MAMPF3(Feld[newx][newy])))))
2058           return;
2059
2060         MovDir[x][y] =
2061           new_move_dir & (!first_horiz ? (MV_LEFT|MV_RIGHT) : (MV_UP|MV_DOWN));
2062         Moving2Blocked(x, y, &newx, &newy);
2063
2064         if (IN_LEV_FIELD(newx, newy) &&
2065             (IS_FREE(newx, newy) ||
2066              Feld[newx][newy] == EL_SALZSAEURE ||
2067              ((element == EL_MAULWURF || element == EL_PINGUIN) &&
2068               (Feld[newx][newy] == EL_AUSGANG_AUF ||
2069                IS_MAMPF3(Feld[newx][newy])))))
2070           return;
2071
2072         MovDir[x][y] = old_move_dir;
2073         return;
2074       }
2075     }
2076   }
2077 }
2078
2079 static boolean JustBeingPushed(int x, int y)
2080 {
2081   int i;
2082
2083   for (i=0; i<MAX_PLAYERS; i++)
2084   {
2085     struct PlayerInfo *player = &stored_player[i];
2086
2087     if (player->active && player->Pushing && player->MovPos)
2088     {
2089       int next_jx = player->jx + (player->jx - player->last_jx);
2090       int next_jy = player->jy + (player->jy - player->last_jy);
2091
2092       if (x == next_jx && y == next_jy)
2093         return TRUE;
2094     }
2095   }
2096
2097   return FALSE;
2098 }
2099
2100 void StartMoving(int x, int y)
2101 {
2102   int element = Feld[x][y];
2103
2104   if (Stop[x][y])
2105     return;
2106
2107   if (CAN_FALL(element) && y<lev_fieldy-1)
2108   {
2109     if ((x>0 && IS_PLAYER(x-1, y)) || (x<lev_fieldx-1 && IS_PLAYER(x+1, y)))
2110       if (JustBeingPushed(x, y))
2111         return;
2112
2113     if (element == EL_MORAST_VOLL)
2114     {
2115       if (IS_FREE(x, y+1))
2116       {
2117         InitMovingField(x, y, MV_DOWN);
2118         Feld[x][y] = EL_FELSBROCKEN;
2119         Store[x][y] = EL_MORAST_LEER;
2120       }
2121       else if (Feld[x][y+1] == EL_MORAST_LEER)
2122       {
2123         if (!MovDelay[x][y])
2124           MovDelay[x][y] = TILEY + 1;
2125
2126         if (MovDelay[x][y])
2127         {
2128           MovDelay[x][y]--;
2129           if (MovDelay[x][y])
2130             return;
2131         }
2132
2133         Feld[x][y] = EL_MORAST_LEER;
2134         Feld[x][y+1] = EL_MORAST_VOLL;
2135       }
2136     }
2137     else if (element == EL_FELSBROCKEN && Feld[x][y+1] == EL_MORAST_LEER)
2138     {
2139       InitMovingField(x, y, MV_DOWN);
2140       Store[x][y] = EL_MORAST_VOLL;
2141     }
2142     else if (element == EL_SIEB_VOLL)
2143     {
2144       if (IS_FREE(x, y+1))
2145       {
2146         InitMovingField(x, y, MV_DOWN);
2147         Feld[x][y] = EL_CHANGED(Store2[x][y]);
2148         Store[x][y] = EL_SIEB_LEER;
2149       }
2150       else if (Feld[x][y+1] == EL_SIEB_LEER)
2151       {
2152         if (!MovDelay[x][y])
2153           MovDelay[x][y] = TILEY/4 + 1;
2154
2155         if (MovDelay[x][y])
2156         {
2157           MovDelay[x][y]--;
2158           if (MovDelay[x][y])
2159             return;
2160         }
2161
2162         Feld[x][y] = EL_SIEB_LEER;
2163         Feld[x][y+1] = EL_SIEB_VOLL;
2164         Store2[x][y+1] = EL_CHANGED(Store2[x][y]);
2165         Store2[x][y] = 0;
2166       }
2167     }
2168     else if (element == EL_SIEB2_VOLL)
2169     {
2170       if (IS_FREE(x, y+1))
2171       {
2172         InitMovingField(x, y, MV_DOWN);
2173         Feld[x][y] = EL_CHANGED2(Store2[x][y]);
2174         Store[x][y] = EL_SIEB2_LEER;
2175       }
2176       else if (Feld[x][y+1] == EL_SIEB2_LEER)
2177       {
2178         if (!MovDelay[x][y])
2179           MovDelay[x][y] = TILEY/4 + 1;
2180
2181         if (MovDelay[x][y])
2182         {
2183           MovDelay[x][y]--;
2184           if (MovDelay[x][y])
2185             return;
2186         }
2187
2188         Feld[x][y] = EL_SIEB2_LEER;
2189         Feld[x][y+1] = EL_SIEB2_VOLL;
2190         Store2[x][y+1] = EL_CHANGED2(Store2[x][y]);
2191         Store2[x][y] = 0;
2192       }
2193     }
2194     else if (CAN_CHANGE(element) &&
2195              (Feld[x][y+1] == EL_SIEB_LEER || Feld[x][y+1] == EL_SIEB2_LEER))
2196     {
2197       InitMovingField(x, y, MV_DOWN);
2198       Store[x][y] =
2199         (Feld[x][y+1] == EL_SIEB_LEER ? EL_SIEB_VOLL : EL_SIEB2_VOLL);
2200       Store2[x][y+1] = element;
2201     }
2202     else if (CAN_SMASH(element) && Feld[x][y+1] == EL_SALZSAEURE)
2203     {
2204       Blurb(x, y);
2205       InitMovingField(x, y, MV_DOWN);
2206       Store[x][y] = EL_SALZSAEURE;
2207     }
2208     else if (CAN_SMASH(element) && Feld[x][y+1] == EL_BLOCKED &&
2209              JustStopped[x][y])
2210     {
2211       Impact(x, y);
2212     }
2213     else if (IS_FREE(x, y+1))
2214     {
2215       InitMovingField(x, y, MV_DOWN);
2216     }
2217     else if (element == EL_TROPFEN)
2218     {
2219       Feld[x][y] = EL_AMOEBING;
2220       Store[x][y] = EL_AMOEBE_NASS;
2221     }
2222 #if OLD_GAME_BEHAVIOUR
2223     else if (IS_SLIPPERY(Feld[x][y+1]) && !Store[x][y+1])
2224 #else
2225     else if (IS_SLIPPERY(Feld[x][y+1]) && !Store[x][y+1] &&
2226              !IS_FALLING(x, y+1) && !JustStopped[x][y+1])
2227 #endif
2228     {
2229       boolean left  = (x>0 && IS_FREE(x-1, y) &&
2230                        (IS_FREE(x-1, y+1) || Feld[x-1][y+1] == EL_SALZSAEURE));
2231       boolean right = (x<lev_fieldx-1 && IS_FREE(x+1, y) &&
2232                        (IS_FREE(x+1, y+1) || Feld[x+1][y+1] == EL_SALZSAEURE));
2233
2234       if (left || right)
2235       {
2236         if (left && right && game.emulation != EMU_BOULDERDASH)
2237           left = !(right = RND(2));
2238
2239         InitMovingField(x, y, left ? MV_LEFT : MV_RIGHT);
2240       }
2241     }
2242     else if (IS_BELT(Feld[x][y+1]))
2243     {
2244       boolean left_is_free  = (x>0 && IS_FREE(x-1, y));
2245       boolean right_is_free = (x<lev_fieldx-1 && IS_FREE(x+1, y));
2246       int belt_nr = getBeltNrFromElement(Feld[x][y+1]);
2247       int belt_dir = game.belt_dir[belt_nr];
2248
2249       if ((belt_dir == MV_LEFT  && left_is_free) ||
2250           (belt_dir == MV_RIGHT && right_is_free))
2251         InitMovingField(x, y, belt_dir);
2252     }
2253   }
2254   else if (CAN_MOVE(element))
2255   {
2256     int newx, newy;
2257
2258     if (element == EL_SONDE && JustBeingPushed(x, y))
2259       return;
2260
2261     if (!MovDelay[x][y])        /* start new movement phase */
2262     {
2263       /* all objects that can change their move direction after each step */
2264       /* (MAMPFER, MAMPFER2 and PACMAN go straight until they hit a wall  */
2265
2266       if (element!=EL_MAMPFER && element!=EL_MAMPFER2 && element!=EL_PACMAN)
2267       {
2268         TurnRound(x, y);
2269         if (MovDelay[x][y] && (element == EL_KAEFER || element == EL_FLIEGER ||
2270                                element == EL_SP_SNIKSNAK ||
2271                                element == EL_SP_ELECTRON))
2272           DrawLevelField(x, y);
2273       }
2274     }
2275
2276     if (MovDelay[x][y])         /* wait some time before next movement */
2277     {
2278       MovDelay[x][y]--;
2279
2280       if (element == EL_ROBOT ||
2281           element == EL_MAMPFER || element == EL_MAMPFER2)
2282       {
2283         int phase = MovDelay[x][y] % 8;
2284
2285         if (phase>3)
2286           phase = 7-phase;
2287
2288         if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
2289           DrawGraphic(SCREENX(x), SCREENY(y), el2gfx(element)+phase);
2290
2291         if ((element == EL_MAMPFER || element == EL_MAMPFER2)
2292             && MovDelay[x][y]%4 == 3)
2293           PlaySoundLevel(x, y, SND_NJAM);
2294       }
2295       else if (element == EL_SP_ELECTRON)
2296         DrawGraphicAnimation(x, y, GFX2_SP_ELECTRON, 8, 2, ANIM_NORMAL);
2297       else if (element == EL_DRACHE)
2298       {
2299         int i;
2300         int dir = MovDir[x][y];
2301         int dx = (dir == MV_LEFT ? -1 : dir == MV_RIGHT ? +1 : 0);
2302         int dy = (dir == MV_UP   ? -1 : dir == MV_DOWN  ? +1 : 0);
2303         int graphic = (dir == MV_LEFT   ? GFX_FLAMMEN_LEFT :
2304                        dir == MV_RIGHT  ? GFX_FLAMMEN_RIGHT :
2305                        dir == MV_UP     ? GFX_FLAMMEN_UP :
2306                        dir == MV_DOWN   ? GFX_FLAMMEN_DOWN : GFX_LEERRAUM);
2307         int phase = FrameCounter % 2;
2308
2309         for (i=1; i<=3; i++)
2310         {
2311           int xx = x + i*dx, yy = y + i*dy;
2312           int sx = SCREENX(xx), sy = SCREENY(yy);
2313
2314           if (!IN_LEV_FIELD(xx, yy) ||
2315               IS_SOLID(Feld[xx][yy]) || Feld[xx][yy] == EL_EXPLODING)
2316             break;
2317
2318           if (MovDelay[x][y])
2319           {
2320             int flamed = MovingOrBlocked2Element(xx, yy);
2321
2322             if (IS_ENEMY(flamed) || IS_EXPLOSIVE(flamed))
2323               Bang(xx, yy);
2324             else
2325               RemoveMovingField(xx, yy);
2326
2327             Feld[xx][yy] = EL_BURNING;
2328             if (IN_SCR_FIELD(sx, sy))
2329               DrawGraphic(sx, sy, graphic + phase*3 + i-1);
2330           }
2331           else
2332           {
2333             if (Feld[xx][yy] == EL_BURNING)
2334               Feld[xx][yy] = EL_LEERRAUM;
2335             DrawLevelField(xx, yy);
2336           }
2337         }
2338       }
2339
2340       if (MovDelay[x][y])
2341         return;
2342     }
2343
2344     if (element == EL_KAEFER || element == EL_BUTTERFLY)
2345     {
2346       PlaySoundLevel(x, y, SND_KLAPPER);
2347     }
2348     else if (element == EL_FLIEGER || element == EL_FIREFLY)
2349     {
2350       PlaySoundLevel(x, y, SND_ROEHR);
2351     }
2352
2353     /* now make next step */
2354
2355     Moving2Blocked(x, y, &newx, &newy); /* get next screen position */
2356
2357     if (IS_ENEMY(element) && IS_PLAYER(newx, newy))
2358     {
2359       /* enemy got the player */
2360       MovDir[x][y] = 0;
2361       KillHero(PLAYERINFO(newx, newy));
2362       return;
2363     }
2364     else if ((element == EL_MAULWURF || element == EL_PINGUIN ||
2365               element == EL_ROBOT || element == EL_SONDE) &&
2366              IN_LEV_FIELD(newx, newy) &&
2367              MovDir[x][y] == MV_DOWN && Feld[newx][newy] == EL_SALZSAEURE)
2368     {
2369       Blurb(x, y);
2370       Store[x][y] = EL_SALZSAEURE;
2371     }
2372     else if ((element == EL_MAULWURF || element == EL_PINGUIN) &&
2373              IN_LEV_FIELD(newx, newy))
2374     {
2375       if (Feld[newx][newy] == EL_AUSGANG_AUF)
2376       {
2377         Feld[x][y] = EL_LEERRAUM;
2378         DrawLevelField(x, y);
2379
2380         PlaySoundLevel(newx, newy, SND_BUING);
2381         if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
2382           DrawGraphicThruMask(SCREENX(newx), SCREENY(newy), el2gfx(element));
2383
2384         local_player->friends_still_needed--;
2385         if (!local_player->friends_still_needed &&
2386             !local_player->GameOver && AllPlayersGone)
2387           local_player->LevelSolved = local_player->GameOver = TRUE;
2388
2389         return;
2390       }
2391       else if (IS_MAMPF3(Feld[newx][newy]))
2392       {
2393         if (DigField(local_player, newx, newy, 0, 0, DF_DIG) == MF_MOVING)
2394           DrawLevelField(newx, newy);
2395         else
2396           MovDir[x][y] = MV_NO_MOVING;
2397       }
2398       else if (!IS_FREE(newx, newy))
2399       {
2400         if (IS_PLAYER(x, y))
2401           DrawPlayerField(x, y);
2402         else
2403           DrawLevelField(x, y);
2404         return;
2405       }
2406     }
2407     else if (element == EL_SCHWEIN && IN_LEV_FIELD(newx, newy))
2408     {
2409       if (IS_GEM(Feld[newx][newy]))
2410       {
2411         if (IS_MOVING(newx, newy))
2412           RemoveMovingField(newx, newy);
2413         else
2414         {
2415           Feld[newx][newy] = EL_LEERRAUM;
2416           DrawLevelField(newx, newy);
2417         }
2418       }
2419       else if (!IS_FREE(newx, newy))
2420       {
2421         if (IS_PLAYER(x, y))
2422           DrawPlayerField(x, y);
2423         else
2424           DrawLevelField(x, y);
2425         return;
2426       }
2427     }
2428     else if (element == EL_DRACHE && IN_LEV_FIELD(newx, newy))
2429     {
2430       if (!IS_FREE(newx, newy))
2431       {
2432         if (IS_PLAYER(x, y))
2433           DrawPlayerField(x, y);
2434         else
2435           DrawLevelField(x, y);
2436         return;
2437       }
2438       else
2439       {
2440         boolean wanna_flame = !RND(10);
2441         int dx = newx - x, dy = newy - y;
2442         int newx1 = newx+1*dx, newy1 = newy+1*dy;
2443         int newx2 = newx+2*dx, newy2 = newy+2*dy;
2444         int element1 = (IN_LEV_FIELD(newx1, newy1) ?
2445                         MovingOrBlocked2Element(newx1, newy1) : EL_BETON);
2446         int element2 = (IN_LEV_FIELD(newx2, newy2) ?
2447                         MovingOrBlocked2Element(newx2, newy2) : EL_BETON);
2448
2449         if ((wanna_flame || IS_ENEMY(element1) || IS_ENEMY(element2)) &&
2450             element1 != EL_DRACHE && element2 != EL_DRACHE &&
2451             element1 != EL_BURNING && element2 != EL_BURNING)
2452         {
2453           if (IS_PLAYER(x, y))
2454             DrawPlayerField(x, y);
2455           else
2456             DrawLevelField(x, y);
2457
2458           MovDelay[x][y] = 50;
2459           Feld[newx][newy] = EL_BURNING;
2460           if (IN_LEV_FIELD(newx1, newy1) && Feld[newx1][newy1] == EL_LEERRAUM)
2461             Feld[newx1][newy1] = EL_BURNING;
2462           if (IN_LEV_FIELD(newx2, newy2) && Feld[newx2][newy2] == EL_LEERRAUM)
2463             Feld[newx2][newy2] = EL_BURNING;
2464           return;
2465         }
2466       }
2467     }
2468     else if (element == EL_MAMPFER && IN_LEV_FIELD(newx, newy) &&
2469              Feld[newx][newy] == EL_DIAMANT)
2470     {
2471       if (IS_MOVING(newx, newy))
2472         RemoveMovingField(newx, newy);
2473       else
2474       {
2475         Feld[newx][newy] = EL_LEERRAUM;
2476         DrawLevelField(newx, newy);
2477       }
2478     }
2479     else if (element == EL_MAMPFER2 && IN_LEV_FIELD(newx, newy) &&
2480              IS_MAMPF2(Feld[newx][newy]))
2481     {
2482       if (AmoebaNr[newx][newy])
2483       {
2484         AmoebaCnt2[AmoebaNr[newx][newy]]--;
2485         if (Feld[newx][newy] == EL_AMOEBE_VOLL ||
2486             Feld[newx][newy] == EL_AMOEBE_BD)
2487           AmoebaCnt[AmoebaNr[newx][newy]]--;
2488       }
2489
2490       if (IS_MOVING(newx, newy))
2491         RemoveMovingField(newx, newy);
2492       else
2493       {
2494         Feld[newx][newy] = EL_LEERRAUM;
2495         DrawLevelField(newx, newy);
2496       }
2497     }
2498     else if (element == EL_PACMAN && IN_LEV_FIELD(newx, newy) &&
2499              IS_AMOEBOID(Feld[newx][newy]))
2500     {
2501       if (AmoebaNr[newx][newy])
2502       {
2503         AmoebaCnt2[AmoebaNr[newx][newy]]--;
2504         if (Feld[newx][newy] == EL_AMOEBE_VOLL ||
2505             Feld[newx][newy] == EL_AMOEBE_BD)
2506           AmoebaCnt[AmoebaNr[newx][newy]]--;
2507       }
2508
2509       Feld[newx][newy] = EL_LEERRAUM;
2510       DrawLevelField(newx, newy);
2511     }
2512     else if (!IN_LEV_FIELD(newx, newy) || !IS_FREE(newx, newy))
2513     {
2514       /* object was running against a wall */
2515
2516       TurnRound(x, y);
2517
2518       if (element == EL_KAEFER || element == EL_FLIEGER ||
2519           element == EL_SP_SNIKSNAK)
2520         DrawLevelField(x, y);
2521       else if (element == EL_BUTTERFLY || element == EL_FIREFLY)
2522         DrawGraphicAnimation(x, y, el2gfx(element), 2, 4, ANIM_NORMAL);
2523       else if (element == EL_SONDE)
2524         DrawGraphicAnimation(x, y, GFX_SONDE_START, 8, 2, ANIM_NORMAL);
2525       else if (element == EL_SP_ELECTRON)
2526         DrawGraphicAnimation(x, y, GFX2_SP_ELECTRON, 8, 2, ANIM_NORMAL);
2527
2528       return;
2529     }
2530
2531     if (element == EL_ROBOT && IN_SCR_FIELD(x, y))
2532       PlaySoundLevel(x, y, SND_SCHLURF);
2533
2534     InitMovingField(x, y, MovDir[x][y]);
2535   }
2536
2537   if (MovDir[x][y])
2538     ContinueMoving(x, y);
2539 }
2540
2541 void ContinueMoving(int x, int y)
2542 {
2543   int element = Feld[x][y];
2544   int direction = MovDir[x][y];
2545   int dx = (direction == MV_LEFT ? -1 : direction == MV_RIGHT ? +1 : 0);
2546   int dy = (direction == MV_UP   ? -1 : direction == MV_DOWN  ? +1 : 0);
2547   int horiz_move = (dx!=0);
2548   int newx = x + dx, newy = y + dy;
2549   int step = (horiz_move ? dx : dy) * TILEX / 8;
2550
2551   if (element == EL_TROPFEN)
2552     step /= 2;
2553   else if (Store[x][y] == EL_MORAST_VOLL || Store[x][y] == EL_MORAST_LEER)
2554     step /= 4;
2555   else if (CAN_FALL(element) && horiz_move &&
2556            y < lev_fieldy-1 && IS_BELT(Feld[x][y+1]))
2557     step /= 2;
2558
2559 #if OLD_GAME_BEHAVIOUR
2560   else if (CAN_FALL(element) && horiz_move && !IS_SP_ELEMENT(element))
2561     step*=2;
2562 #endif
2563
2564   MovPos[x][y] += step;
2565
2566   if (ABS(MovPos[x][y])>=TILEX)         /* object reached its destination */
2567   {
2568     Feld[x][y] = EL_LEERRAUM;
2569     Feld[newx][newy] = element;
2570
2571     if (Store[x][y] == EL_MORAST_VOLL)
2572     {
2573       Store[x][y] = 0;
2574       Feld[newx][newy] = EL_MORAST_VOLL;
2575       element = EL_MORAST_VOLL;
2576     }
2577     else if (Store[x][y] == EL_MORAST_LEER)
2578     {
2579       Store[x][y] = 0;
2580       Feld[x][y] = EL_MORAST_LEER;
2581     }
2582     else if (Store[x][y] == EL_SIEB_VOLL)
2583     {
2584       Store[x][y] = 0;
2585       element = Feld[newx][newy] =
2586         (game.magic_wall_active ? EL_SIEB_VOLL : EL_SIEB_TOT);
2587     }
2588     else if (Store[x][y] == EL_SIEB_LEER)
2589     {
2590       Store[x][y] = Store2[x][y] = 0;
2591       Feld[x][y] = (game.magic_wall_active ? EL_SIEB_LEER : EL_SIEB_TOT);
2592     }
2593     else if (Store[x][y] == EL_SIEB2_VOLL)
2594     {
2595       Store[x][y] = 0;
2596       element = Feld[newx][newy] =
2597         (game.magic_wall_active ? EL_SIEB2_VOLL : EL_SIEB2_TOT);
2598     }
2599     else if (Store[x][y] == EL_SIEB2_LEER)
2600     {
2601       Store[x][y] = Store2[x][y] = 0;
2602       Feld[x][y] = (game.magic_wall_active ? EL_SIEB2_LEER : EL_SIEB2_TOT);
2603     }
2604     else if (Store[x][y] == EL_SALZSAEURE)
2605     {
2606       Store[x][y] = 0;
2607       Feld[newx][newy] = EL_SALZSAEURE;
2608       element = EL_SALZSAEURE;
2609     }
2610     else if (Store[x][y] == EL_AMOEBE_NASS)
2611     {
2612       Store[x][y] = 0;
2613       Feld[x][y] = EL_AMOEBE_NASS;
2614     }
2615
2616     MovPos[x][y] = MovDir[x][y] = MovDelay[x][y] = 0;
2617     MovDelay[newx][newy] = 0;
2618
2619     if (!CAN_MOVE(element))
2620       MovDir[newx][newy] = 0;
2621
2622     DrawLevelField(x, y);
2623     DrawLevelField(newx, newy);
2624
2625     Stop[newx][newy] = TRUE;
2626     JustStopped[newx][newy] = 3;
2627
2628     if (DONT_TOUCH(element))    /* object may be nasty to player or others */
2629     {
2630       TestIfBadThingHitsHero(newx, newy);
2631       TestIfBadThingHitsFriend(newx, newy);
2632       TestIfBadThingHitsOtherBadThing(newx, newy);
2633     }
2634     else if (element == EL_PINGUIN)
2635       TestIfFriendHitsBadThing(newx, newy);
2636
2637     if (CAN_SMASH(element) && direction == MV_DOWN &&
2638         (newy == lev_fieldy-1 || !IS_FREE(x, newy+1)))
2639       Impact(x, newy);
2640   }
2641   else                          /* still moving on */
2642     DrawLevelField(x, y);
2643 }
2644
2645 int AmoebeNachbarNr(int ax, int ay)
2646 {
2647   int i;
2648   int element = Feld[ax][ay];
2649   int group_nr = 0;
2650   static int xy[4][2] =
2651   {
2652     { 0, -1 },
2653     { -1, 0 },
2654     { +1, 0 },
2655     { 0, +1 }
2656   };
2657
2658   for (i=0; i<4; i++)
2659   {
2660     int x = ax + xy[i][0];
2661     int y = ay + xy[i][1];
2662
2663     if (!IN_LEV_FIELD(x, y))
2664       continue;
2665
2666     if (Feld[x][y] == element && AmoebaNr[x][y] > 0)
2667       group_nr = AmoebaNr[x][y];
2668   }
2669
2670   return group_nr;
2671 }
2672
2673 void AmoebenVereinigen(int ax, int ay)
2674 {
2675   int i, x, y, xx, yy;
2676   int new_group_nr = AmoebaNr[ax][ay];
2677   static int xy[4][2] =
2678   {
2679     { 0, -1 },
2680     { -1, 0 },
2681     { +1, 0 },
2682     { 0, +1 }
2683   };
2684
2685   if (new_group_nr == 0)
2686     return;
2687
2688   for (i=0; i<4; i++)
2689   {
2690     x = ax + xy[i][0];
2691     y = ay + xy[i][1];
2692
2693     if (!IN_LEV_FIELD(x, y))
2694       continue;
2695
2696     if ((Feld[x][y] == EL_AMOEBE_VOLL ||
2697          Feld[x][y] == EL_AMOEBE_BD ||
2698          Feld[x][y] == EL_AMOEBE_TOT) &&
2699         AmoebaNr[x][y] != new_group_nr)
2700     {
2701       int old_group_nr = AmoebaNr[x][y];
2702
2703       if (old_group_nr == 0)
2704         return;
2705
2706       AmoebaCnt[new_group_nr] += AmoebaCnt[old_group_nr];
2707       AmoebaCnt[old_group_nr] = 0;
2708       AmoebaCnt2[new_group_nr] += AmoebaCnt2[old_group_nr];
2709       AmoebaCnt2[old_group_nr] = 0;
2710
2711       for (yy=0; yy<lev_fieldy; yy++)
2712       {
2713         for (xx=0; xx<lev_fieldx; xx++)
2714         {
2715           if (AmoebaNr[xx][yy] == old_group_nr)
2716             AmoebaNr[xx][yy] = new_group_nr;
2717         }
2718       }
2719     }
2720   }
2721 }
2722
2723 void AmoebeUmwandeln(int ax, int ay)
2724 {
2725   int i, x, y;
2726
2727   if (Feld[ax][ay] == EL_AMOEBE_TOT)
2728   {
2729     int group_nr = AmoebaNr[ax][ay];
2730
2731 #ifdef DEBUG
2732     if (group_nr == 0)
2733     {
2734       printf("AmoebeUmwandeln(): ax = %d, ay = %d\n", ax, ay);
2735       printf("AmoebeUmwandeln(): This should never happen!\n");
2736       return;
2737     }
2738 #endif
2739
2740     for (y=0; y<lev_fieldy; y++)
2741     {
2742       for (x=0; x<lev_fieldx; x++)
2743       {
2744         if (Feld[x][y] == EL_AMOEBE_TOT && AmoebaNr[x][y] == group_nr)
2745         {
2746           AmoebaNr[x][y] = 0;
2747           Feld[x][y] = EL_AMOEBA2DIAM;
2748         }
2749       }
2750     }
2751     Bang(ax, ay);
2752   }
2753   else
2754   {
2755     static int xy[4][2] =
2756     {
2757       { 0, -1 },
2758       { -1, 0 },
2759       { +1, 0 },
2760       { 0, +1 }
2761     };
2762
2763     for (i=0; i<4; i++)
2764     {
2765       x = ax + xy[i][0];
2766       y = ay + xy[i][1];
2767
2768       if (!IN_LEV_FIELD(x, y))
2769         continue;
2770
2771       if (Feld[x][y] == EL_AMOEBA2DIAM)
2772         Bang(x, y);
2773     }
2774   }
2775 }
2776
2777 void AmoebeUmwandelnBD(int ax, int ay, int new_element)
2778 {
2779   int x, y;
2780   int group_nr = AmoebaNr[ax][ay];
2781   boolean done = FALSE;
2782
2783 #ifdef DEBUG
2784   if (group_nr == 0)
2785   {
2786     printf("AmoebeUmwandelnBD(): ax = %d, ay = %d\n", ax, ay);
2787     printf("AmoebeUmwandelnBD(): This should never happen!\n");
2788     return;
2789   }
2790 #endif
2791
2792   for (y=0; y<lev_fieldy; y++)
2793   {
2794     for (x=0; x<lev_fieldx; x++)
2795     {
2796       if (AmoebaNr[x][y] == group_nr &&
2797           (Feld[x][y] == EL_AMOEBE_TOT ||
2798            Feld[x][y] == EL_AMOEBE_BD ||
2799            Feld[x][y] == EL_AMOEBING))
2800       {
2801         AmoebaNr[x][y] = 0;
2802         Feld[x][y] = new_element;
2803         InitField(x, y, FALSE);
2804         DrawLevelField(x, y);
2805         done = TRUE;
2806       }
2807     }
2808   }
2809
2810   if (done)
2811     PlaySoundLevel(ax, ay,
2812                    (new_element == EL_FELSBROCKEN ? SND_KLOPF : SND_PLING));
2813 }
2814
2815 void AmoebeWaechst(int x, int y)
2816 {
2817   static unsigned long sound_delay = 0;
2818   static unsigned long sound_delay_value = 0;
2819
2820   if (!MovDelay[x][y])          /* start new growing cycle */
2821   {
2822     MovDelay[x][y] = 7;
2823
2824     if (DelayReached(&sound_delay, sound_delay_value))
2825     {
2826       PlaySoundLevel(x, y, SND_AMOEBE);
2827       sound_delay_value = 30;
2828     }
2829   }
2830
2831   if (MovDelay[x][y])           /* wait some time before growing bigger */
2832   {
2833     MovDelay[x][y]--;
2834     if (MovDelay[x][y]/2 && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
2835       DrawGraphic(SCREENX(x), SCREENY(y), GFX_AMOEBING + 3 - MovDelay[x][y]/2);
2836
2837     if (!MovDelay[x][y])
2838     {
2839       Feld[x][y] = Store[x][y];
2840       Store[x][y] = 0;
2841       DrawLevelField(x, y);
2842     }
2843   }
2844 }
2845
2846 void AmoebeAbleger(int ax, int ay)
2847 {
2848   int i;
2849   int element = Feld[ax][ay];
2850   int newax = ax, neway = ay;
2851   static int xy[4][2] =
2852   {
2853     { 0, -1 },
2854     { -1, 0 },
2855     { +1, 0 },
2856     { 0, +1 }
2857   };
2858
2859   if (!level.amoeba_speed)
2860   {
2861     Feld[ax][ay] = EL_AMOEBE_TOT;
2862     DrawLevelField(ax, ay);
2863     return;
2864   }
2865
2866   if (!MovDelay[ax][ay])        /* start making new amoeba field */
2867     MovDelay[ax][ay] = RND(FRAMES_PER_SECOND * 25 / (1 + level.amoeba_speed));
2868
2869   if (MovDelay[ax][ay])         /* wait some time before making new amoeba */
2870   {
2871     MovDelay[ax][ay]--;
2872     if (MovDelay[ax][ay])
2873       return;
2874   }
2875
2876   if (element == EL_AMOEBE_NASS)        /* object is an acid / amoeba drop */
2877   {
2878     int start = RND(4);
2879     int x = ax + xy[start][0];
2880     int y = ay + xy[start][1];
2881
2882     if (!IN_LEV_FIELD(x, y))
2883       return;
2884
2885     if (IS_FREE(x, y) ||
2886         Feld[x][y] == EL_ERDREICH || Feld[x][y] == EL_MORAST_LEER)
2887     {
2888       newax = x;
2889       neway = y;
2890     }
2891
2892     if (newax == ax && neway == ay)
2893       return;
2894   }
2895   else                          /* normal or "filled" (BD style) amoeba */
2896   {
2897     int start = RND(4);
2898     boolean waiting_for_player = FALSE;
2899
2900     for (i=0; i<4; i++)
2901     {
2902       int j = (start + i) % 4;
2903       int x = ax + xy[j][0];
2904       int y = ay + xy[j][1];
2905
2906       if (!IN_LEV_FIELD(x, y))
2907         continue;
2908
2909       if (IS_FREE(x, y) ||
2910           Feld[x][y] == EL_ERDREICH || Feld[x][y] == EL_MORAST_LEER)
2911       {
2912         newax = x;
2913         neway = y;
2914         break;
2915       }
2916       else if (IS_PLAYER(x, y))
2917         waiting_for_player = TRUE;
2918     }
2919
2920     if (newax == ax && neway == ay)             /* amoeba cannot grow */
2921     {
2922       if (i == 4 && (!waiting_for_player || game.emulation == EMU_BOULDERDASH))
2923       {
2924         Feld[ax][ay] = EL_AMOEBE_TOT;
2925         DrawLevelField(ax, ay);
2926         AmoebaCnt[AmoebaNr[ax][ay]]--;
2927
2928         if (AmoebaCnt[AmoebaNr[ax][ay]] <= 0)   /* amoeba is completely dead */
2929         {
2930           if (element == EL_AMOEBE_VOLL)
2931             AmoebeUmwandeln(ax, ay);
2932           else if (element == EL_AMOEBE_BD)
2933             AmoebeUmwandelnBD(ax, ay, level.amoeba_content);
2934         }
2935       }
2936       return;
2937     }
2938     else if (element == EL_AMOEBE_VOLL || element == EL_AMOEBE_BD)
2939     {
2940       /* amoeba gets larger by growing in some direction */
2941
2942       int new_group_nr = AmoebaNr[ax][ay];
2943
2944 #ifdef DEBUG
2945   if (new_group_nr == 0)
2946   {
2947     printf("AmoebeAbleger(): newax = %d, neway = %d\n", newax, neway);
2948     printf("AmoebeAbleger(): This should never happen!\n");
2949     return;
2950   }
2951 #endif
2952
2953       AmoebaNr[newax][neway] = new_group_nr;
2954       AmoebaCnt[new_group_nr]++;
2955       AmoebaCnt2[new_group_nr]++;
2956
2957       /* if amoeba touches other amoeba(s) after growing, unify them */
2958       AmoebenVereinigen(newax, neway);
2959
2960       if (element == EL_AMOEBE_BD && AmoebaCnt2[new_group_nr] >= 200)
2961       {
2962         AmoebeUmwandelnBD(newax, neway, EL_FELSBROCKEN);
2963         return;
2964       }
2965     }
2966   }
2967
2968   if (element != EL_AMOEBE_NASS || neway < ay || !IS_FREE(newax, neway) ||
2969       (neway == lev_fieldy - 1 && newax != ax))
2970   {
2971     Feld[newax][neway] = EL_AMOEBING;
2972     Store[newax][neway] = element;
2973   }
2974   else if (neway == ay)
2975     Feld[newax][neway] = EL_TROPFEN;
2976   else
2977   {
2978     InitMovingField(ax, ay, MV_DOWN);
2979     Feld[ax][ay] = EL_TROPFEN;
2980     Store[ax][ay] = EL_AMOEBE_NASS;
2981     ContinueMoving(ax, ay);
2982     return;
2983   }
2984
2985   DrawLevelField(newax, neway);
2986 }
2987
2988 void Life(int ax, int ay)
2989 {
2990   int x1, y1, x2, y2;
2991   static int life[4] = { 2, 3, 3, 3 };  /* parameters for "game of life" */
2992   int life_time = 40;
2993   int element = Feld[ax][ay];
2994
2995   if (Stop[ax][ay])
2996     return;
2997
2998   if (!MovDelay[ax][ay])        /* start new "game of life" cycle */
2999     MovDelay[ax][ay] = life_time;
3000
3001   if (MovDelay[ax][ay])         /* wait some time before next cycle */
3002   {
3003     MovDelay[ax][ay]--;
3004     if (MovDelay[ax][ay])
3005       return;
3006   }
3007
3008   for (y1=-1; y1<2; y1++) for(x1=-1; x1<2; x1++)
3009   {
3010     int xx = ax+x1, yy = ay+y1;
3011     int nachbarn = 0;
3012
3013     if (!IN_LEV_FIELD(xx, yy))
3014       continue;
3015
3016     for (y2=-1; y2<2; y2++) for (x2=-1; x2<2; x2++)
3017     {
3018       int x = xx+x2, y = yy+y2;
3019
3020       if (!IN_LEV_FIELD(x, y) || (x == xx && y == yy))
3021         continue;
3022
3023       if (((Feld[x][y] == element ||
3024             (element == EL_LIFE && IS_PLAYER(x, y))) &&
3025            !Stop[x][y]) ||
3026           (IS_FREE(x, y) && Stop[x][y]))
3027         nachbarn++;
3028     }
3029
3030     if (xx == ax && yy == ay)           /* field in the middle */
3031     {
3032       if (nachbarn<life[0] || nachbarn>life[1])
3033       {
3034         Feld[xx][yy] = EL_LEERRAUM;
3035         if (!Stop[xx][yy])
3036           DrawLevelField(xx, yy);
3037         Stop[xx][yy] = TRUE;
3038       }
3039     }
3040     else if (IS_FREE(xx, yy) || Feld[xx][yy] == EL_ERDREICH)
3041     {                                   /* free border field */
3042       if (nachbarn>=life[2] && nachbarn<=life[3])
3043       {
3044         Feld[xx][yy] = element;
3045         MovDelay[xx][yy] = (element == EL_LIFE ? 0 : life_time-1);
3046         if (!Stop[xx][yy])
3047           DrawLevelField(xx, yy);
3048         Stop[xx][yy] = TRUE;
3049       }
3050     }
3051   }
3052 }
3053
3054 void Ablenk(int x, int y)
3055 {
3056   if (!MovDelay[x][y])          /* next animation frame */
3057     MovDelay[x][y] = level.time_wheel * FRAMES_PER_SECOND;
3058
3059   if (MovDelay[x][y])           /* wait some time before next frame */
3060   {
3061     MovDelay[x][y]--;
3062     if (MovDelay[x][y])
3063     {
3064       if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
3065         DrawGraphic(SCREENX(x), SCREENY(y), GFX_ABLENK+MovDelay[x][y]%4);
3066       if (!(MovDelay[x][y]%4))
3067         PlaySoundLevel(x, y, SND_MIEP);
3068       return;
3069     }
3070   }
3071
3072   Feld[x][y] = EL_ABLENK_AUS;
3073   DrawLevelField(x, y);
3074   if (ZX == x && ZY == y)
3075     ZX = ZY = -1;
3076 }
3077
3078 void Birne(int x, int y)
3079 {
3080   if (!MovDelay[x][y])          /* next animation frame */
3081     MovDelay[x][y] = 800;
3082
3083   if (MovDelay[x][y])           /* wait some time before next frame */
3084   {
3085     MovDelay[x][y]--;
3086     if (MovDelay[x][y])
3087     {
3088       if (!(MovDelay[x][y]%5))
3089       {
3090         if (!(MovDelay[x][y]%10))
3091           Feld[x][y]=EL_ABLENK_EIN;
3092         else
3093           Feld[x][y]=EL_ABLENK_AUS;
3094         DrawLevelField(x, y);
3095         Feld[x][y]=EL_ABLENK_EIN;
3096       }
3097       return;
3098     }
3099   }
3100
3101   Feld[x][y]=EL_ABLENK_AUS;
3102   DrawLevelField(x, y);
3103   if (ZX == x && ZY == y)
3104     ZX=ZY=-1;
3105 }
3106
3107 void Blubber(int x, int y)
3108 {
3109   if (y > 0 && IS_MOVING(x, y-1) && MovDir[x][y-1] == MV_DOWN)
3110     DrawLevelField(x, y-1);
3111   else
3112     DrawGraphicAnimation(x, y, GFX_GEBLUBBER, 4, 10, ANIM_NORMAL);
3113 }
3114
3115 void NussKnacken(int x, int y)
3116 {
3117   if (!MovDelay[x][y])          /* next animation frame */
3118     MovDelay[x][y] = 7;
3119
3120   if (MovDelay[x][y])           /* wait some time before next frame */
3121   {
3122     MovDelay[x][y]--;
3123     if (MovDelay[x][y]/2 && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
3124       DrawGraphic(SCREENX(x), SCREENY(y), GFX_CRACKINGNUT+3-MovDelay[x][y]/2);
3125
3126     if (!MovDelay[x][y])
3127     {
3128       Feld[x][y] = EL_EDELSTEIN;
3129       DrawLevelField(x, y);
3130     }
3131   }
3132 }
3133
3134 void SiebAktivieren(int x, int y, int typ)
3135 {
3136   int graphic = (typ == 1 ? GFX_SIEB_VOLL : GFX_SIEB2_VOLL) + 3;
3137
3138   DrawGraphicAnimation(x, y, graphic, 4, 4, ANIM_REVERSE);
3139 }
3140
3141 void AusgangstuerPruefen(int x, int y)
3142 {
3143   if (!local_player->gems_still_needed &&
3144       !local_player->sokobanfields_still_needed &&
3145       !local_player->lights_still_needed)
3146   {
3147     Feld[x][y] = EL_AUSGANG_ACT;
3148
3149     PlaySoundLevel(x < LEVELX(BX1) ? LEVELX(BX1) :
3150                    (x > LEVELX(BX2) ? LEVELX(BX2) : x),
3151                    y < LEVELY(BY1) ? LEVELY(BY1) :
3152                    (y > LEVELY(BY2) ? LEVELY(BY2) : y),
3153                    SND_OEFFNEN);
3154   }
3155 }
3156
3157 void AusgangstuerOeffnen(int x, int y)
3158 {
3159   int delay = 6;
3160
3161   if (!MovDelay[x][y])          /* next animation frame */
3162     MovDelay[x][y] = 5*delay;
3163
3164   if (MovDelay[x][y])           /* wait some time before next frame */
3165   {
3166     int tuer;
3167
3168     MovDelay[x][y]--;
3169     tuer = MovDelay[x][y]/delay;
3170     if (!(MovDelay[x][y]%delay) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
3171       DrawGraphic(SCREENX(x), SCREENY(y), GFX_AUSGANG_AUF-tuer);
3172
3173     if (!MovDelay[x][y])
3174     {
3175       Feld[x][y] = EL_AUSGANG_AUF;
3176       DrawLevelField(x, y);
3177     }
3178   }
3179 }
3180
3181 void AusgangstuerBlinken(int x, int y)
3182 {
3183   DrawGraphicAnimation(x, y, GFX_AUSGANG_AUF, 4, 4, ANIM_OSCILLATE);
3184 }
3185
3186 void OpenSwitchgate(int x, int y)
3187 {
3188   int delay = 6;
3189
3190   if (!MovDelay[x][y])          /* next animation frame */
3191     MovDelay[x][y] = 5 * delay;
3192
3193   if (MovDelay[x][y])           /* wait some time before next frame */
3194   {
3195     int phase;
3196
3197     MovDelay[x][y]--;
3198     phase = MovDelay[x][y] / delay;
3199     if (!(MovDelay[x][y] % delay) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
3200       DrawGraphic(SCREENX(x), SCREENY(y), GFX_SWITCHGATE_OPEN - phase);
3201
3202     if (!MovDelay[x][y])
3203     {
3204       Feld[x][y] = EL_SWITCHGATE_OPEN;
3205       DrawLevelField(x, y);
3206     }
3207   }
3208 }
3209
3210 void CloseSwitchgate(int x, int y)
3211 {
3212   int delay = 6;
3213
3214   if (!MovDelay[x][y])          /* next animation frame */
3215     MovDelay[x][y] = 5 * delay;
3216
3217   if (MovDelay[x][y])           /* wait some time before next frame */
3218   {
3219     int phase;
3220
3221     MovDelay[x][y]--;
3222     phase = MovDelay[x][y] / delay;
3223     if (!(MovDelay[x][y] % delay) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
3224       DrawGraphic(SCREENX(x), SCREENY(y), GFX_SWITCHGATE_CLOSED + phase);
3225
3226     if (!MovDelay[x][y])
3227     {
3228       Feld[x][y] = EL_SWITCHGATE_CLOSED;
3229       DrawLevelField(x, y);
3230     }
3231   }
3232 }
3233
3234 void EdelsteinFunkeln(int x, int y)
3235 {
3236   if (!IN_SCR_FIELD(SCREENX(x), SCREENY(y)) || IS_MOVING(x, y))
3237     return;
3238
3239   if (Feld[x][y] == EL_EDELSTEIN_BD)
3240     DrawGraphicAnimation(x, y, GFX_EDELSTEIN_BD, 4, 4, ANIM_REVERSE);
3241   else
3242   {
3243     if (!MovDelay[x][y])        /* next animation frame */
3244       MovDelay[x][y] = 11 * !SimpleRND(500);
3245
3246     if (MovDelay[x][y])         /* wait some time before next frame */
3247     {
3248       MovDelay[x][y]--;
3249
3250       if (setup.direct_draw && MovDelay[x][y])
3251         SetDrawtoField(DRAW_BUFFERED);
3252
3253       DrawGraphic(SCREENX(x), SCREENY(y), el2gfx(Feld[x][y]));
3254
3255       if (MovDelay[x][y])
3256       {
3257         int phase = (MovDelay[x][y]-1)/2;
3258
3259         if (phase > 2)
3260           phase = 4-phase;
3261
3262         DrawGraphicThruMask(SCREENX(x), SCREENY(y), GFX_FUNKELN_WEISS + phase);
3263
3264         if (setup.direct_draw)
3265         {
3266           int dest_x, dest_y;
3267
3268           dest_x = FX + SCREENX(x)*TILEX;
3269           dest_y = FY + SCREENY(y)*TILEY;
3270
3271           XCopyArea(display, drawto_field, window, gc,
3272                     dest_x, dest_y, TILEX, TILEY, dest_x, dest_y);
3273           SetDrawtoField(DRAW_DIRECT);
3274         }
3275       }
3276     }
3277   }
3278 }
3279
3280 void MauerWaechst(int x, int y)
3281 {
3282   int delay = 6;
3283
3284   if (!MovDelay[x][y])          /* next animation frame */
3285     MovDelay[x][y] = 3*delay;
3286
3287   if (MovDelay[x][y])           /* wait some time before next frame */
3288   {
3289     int phase;
3290
3291     MovDelay[x][y]--;
3292     phase = 2-MovDelay[x][y]/delay;
3293     if (!(MovDelay[x][y]%delay) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
3294       DrawGraphic(SCREENX(x), SCREENY(y),
3295                   (MovDir[x][y] == MV_LEFT  ? GFX_MAUER_LEFT  :
3296                    MovDir[x][y] == MV_RIGHT ? GFX_MAUER_RIGHT :
3297                    MovDir[x][y] == MV_UP    ? GFX_MAUER_UP    :
3298                                               GFX_MAUER_DOWN  ) + phase);
3299
3300     if (!MovDelay[x][y])
3301     {
3302       if (MovDir[x][y] == MV_LEFT)
3303       {
3304         if (IN_LEV_FIELD(x-1, y) && IS_MAUER(Feld[x-1][y]))
3305           DrawLevelField(x-1, y);
3306       }
3307       else if (MovDir[x][y] == MV_RIGHT)
3308       {
3309         if (IN_LEV_FIELD(x+1, y) && IS_MAUER(Feld[x+1][y]))
3310           DrawLevelField(x+1, y);
3311       }
3312       else if (MovDir[x][y] == MV_UP)
3313       {
3314         if (IN_LEV_FIELD(x, y-1) && IS_MAUER(Feld[x][y-1]))
3315           DrawLevelField(x, y-1);
3316       }
3317       else
3318       {
3319         if (IN_LEV_FIELD(x, y+1) && IS_MAUER(Feld[x][y+1]))
3320           DrawLevelField(x, y+1);
3321       }
3322
3323       Feld[x][y] = Store[x][y];
3324       Store[x][y] = 0;
3325       MovDir[x][y] = MV_NO_MOVING;
3326       DrawLevelField(x, y);
3327     }
3328   }
3329 }
3330
3331 void MauerAbleger(int ax, int ay)
3332 {
3333   int element = Feld[ax][ay];
3334   boolean oben_frei = FALSE, unten_frei = FALSE;
3335   boolean links_frei = FALSE, rechts_frei = FALSE;
3336   boolean oben_massiv = FALSE, unten_massiv = FALSE;
3337   boolean links_massiv = FALSE, rechts_massiv = FALSE;
3338
3339   if (!MovDelay[ax][ay])        /* start building new wall */
3340     MovDelay[ax][ay] = 6;
3341
3342   if (MovDelay[ax][ay])         /* wait some time before building new wall */
3343   {
3344     MovDelay[ax][ay]--;
3345     if (MovDelay[ax][ay])
3346       return;
3347   }
3348
3349   if (IN_LEV_FIELD(ax, ay-1) && IS_FREE(ax, ay-1))
3350     oben_frei = TRUE;
3351   if (IN_LEV_FIELD(ax, ay+1) && IS_FREE(ax, ay+1))
3352     unten_frei = TRUE;
3353   if (IN_LEV_FIELD(ax-1, ay) && IS_FREE(ax-1, ay))
3354     links_frei = TRUE;
3355   if (IN_LEV_FIELD(ax+1, ay) && IS_FREE(ax+1, ay))
3356     rechts_frei = TRUE;
3357
3358   if (element == EL_MAUER_Y || element == EL_MAUER_XY)
3359   {
3360     if (oben_frei)
3361     {
3362       Feld[ax][ay-1] = EL_MAUERND;
3363       Store[ax][ay-1] = element;
3364       MovDir[ax][ay-1] = MV_UP;
3365       if (IN_SCR_FIELD(SCREENX(ax), SCREENY(ay-1)))
3366         DrawGraphic(SCREENX(ax), SCREENY(ay-1), GFX_MAUER_UP);
3367     }
3368     if (unten_frei)
3369     {
3370       Feld[ax][ay+1] = EL_MAUERND;
3371       Store[ax][ay+1] = element;
3372       MovDir[ax][ay+1] = MV_DOWN;
3373       if (IN_SCR_FIELD(SCREENX(ax), SCREENY(ay+1)))
3374         DrawGraphic(SCREENX(ax), SCREENY(ay+1), GFX_MAUER_DOWN);
3375     }
3376   }
3377
3378   if (element == EL_MAUER_X || element == EL_MAUER_XY ||
3379       element == EL_MAUER_LEBT)
3380   {
3381     if (links_frei)
3382     {
3383       Feld[ax-1][ay] = EL_MAUERND;
3384       Store[ax-1][ay] = element;
3385       MovDir[ax-1][ay] = MV_LEFT;
3386       if (IN_SCR_FIELD(SCREENX(ax-1), SCREENY(ay)))
3387         DrawGraphic(SCREENX(ax-1), SCREENY(ay), GFX_MAUER_LEFT);
3388     }
3389     if (rechts_frei)
3390     {
3391       Feld[ax+1][ay] = EL_MAUERND;
3392       Store[ax+1][ay] = element;
3393       MovDir[ax+1][ay] = MV_RIGHT;
3394       if (IN_SCR_FIELD(SCREENX(ax+1), SCREENY(ay)))
3395         DrawGraphic(SCREENX(ax+1), SCREENY(ay), GFX_MAUER_RIGHT);
3396     }
3397   }
3398
3399   if (element == EL_MAUER_LEBT && (links_frei || rechts_frei))
3400     DrawLevelField(ax, ay);
3401
3402   if (!IN_LEV_FIELD(ax, ay-1) || IS_MAUER(Feld[ax][ay-1]))
3403     oben_massiv = TRUE;
3404   if (!IN_LEV_FIELD(ax, ay+1) || IS_MAUER(Feld[ax][ay+1]))
3405     unten_massiv = TRUE;
3406   if (!IN_LEV_FIELD(ax-1, ay) || IS_MAUER(Feld[ax-1][ay]))
3407     links_massiv = TRUE;
3408   if (!IN_LEV_FIELD(ax+1, ay) || IS_MAUER(Feld[ax+1][ay]))
3409     rechts_massiv = TRUE;
3410
3411   if (((oben_massiv && unten_massiv) ||
3412        element == EL_MAUER_X || element == EL_MAUER_LEBT) &&
3413       ((links_massiv && rechts_massiv) ||
3414        element == EL_MAUER_Y))
3415     Feld[ax][ay] = EL_MAUERWERK;
3416 }
3417
3418 void CheckForDragon(int x, int y)
3419 {
3420   int i, j;
3421   boolean dragon_found = FALSE;
3422   static int xy[4][2] =
3423   {
3424     { 0, -1 },
3425     { -1, 0 },
3426     { +1, 0 },
3427     { 0, +1 }
3428   };
3429
3430   for (i=0; i<4; i++)
3431   {
3432     for (j=0; j<4; j++)
3433     {
3434       int xx = x + j*xy[i][0], yy = y + j*xy[i][1];
3435
3436       if (IN_LEV_FIELD(xx, yy) &&
3437           (Feld[xx][yy] == EL_BURNING || Feld[xx][yy] == EL_DRACHE))
3438       {
3439         if (Feld[xx][yy] == EL_DRACHE)
3440           dragon_found = TRUE;
3441       }
3442       else
3443         break;
3444     }
3445   }
3446
3447   if (!dragon_found)
3448   {
3449     for (i=0; i<4; i++)
3450     {
3451       for (j=0; j<3; j++)
3452       {
3453         int xx = x + j*xy[i][0], yy = y + j*xy[i][1];
3454   
3455         if (IN_LEV_FIELD(xx, yy) && Feld[xx][yy] == EL_BURNING)
3456         {
3457           Feld[xx][yy] = EL_LEERRAUM;
3458           DrawLevelField(xx, yy);
3459         }
3460         else
3461           break;
3462       }
3463     }
3464   }
3465 }
3466
3467 static void CheckBuggyBase(int x, int y)
3468 {
3469   int element = Feld[x][y];
3470
3471   if (element == EL_SP_BUG)
3472   {
3473     if (!MovDelay[x][y])        /* start activating buggy base */
3474       MovDelay[x][y] = 2 * FRAMES_PER_SECOND + RND(5 * FRAMES_PER_SECOND);
3475
3476     if (MovDelay[x][y])         /* wait some time before activating base */
3477     {
3478       MovDelay[x][y]--;
3479       if (MovDelay[x][y] < 5 && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
3480         DrawGraphic(SCREENX(x), SCREENY(y), GFX_SP_BUG_WARNING);
3481       if (MovDelay[x][y])
3482         return;
3483
3484       Feld[x][y] = EL_SP_BUG_ACTIVE;
3485     }
3486   }
3487   else if (element == EL_SP_BUG_ACTIVE)
3488   {
3489     if (!MovDelay[x][y])        /* start activating buggy base */
3490       MovDelay[x][y] = 1 * FRAMES_PER_SECOND + RND(1 * FRAMES_PER_SECOND);
3491
3492     if (MovDelay[x][y])         /* wait some time before activating base */
3493     {
3494       MovDelay[x][y]--;
3495       if (MovDelay[x][y])
3496       {
3497         int i;
3498         static int xy[4][2] =
3499         {
3500           { 0, -1 },
3501           { -1, 0 },
3502           { +1, 0 },
3503           { 0, +1 }
3504         };
3505
3506         if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
3507           DrawGraphic(SCREENX(x),SCREENY(y), GFX_SP_BUG_ACTIVE + SimpleRND(4));
3508
3509         for (i=0; i<4; i++)
3510         {
3511           int xx = x + xy[i][0], yy = y + xy[i][1];
3512
3513           if (IS_PLAYER(xx, yy))
3514           {
3515             PlaySoundLevel(x, y, SND_SP_BUG);
3516             break;
3517           }
3518         }
3519
3520         return;
3521       }
3522
3523       Feld[x][y] = EL_SP_BUG;
3524       DrawLevelField(x, y);
3525     }
3526   }
3527 }
3528
3529 static void DrawBeltAnimation(int x, int y, int element)
3530 {
3531   int belt_nr = getBeltNrFromElement(element);
3532   int belt_dir = game.belt_dir[belt_nr];
3533
3534   if (belt_dir != MV_NO_MOVING)
3535   {
3536     int delay = 2;
3537     int mode = (belt_dir == MV_LEFT ? ANIM_NORMAL : ANIM_REVERSE);
3538     int graphic = el2gfx(element) + (belt_dir == MV_LEFT ? 0 : 7);
3539
3540     DrawGraphicAnimation(x, y, graphic, 8, delay, mode);
3541   }
3542 }
3543
3544 static void PlayerActions(struct PlayerInfo *player, byte player_action)
3545 {
3546   static byte stored_player_action[MAX_PLAYERS];
3547   static int num_stored_actions = 0;
3548   static boolean save_tape_entry = FALSE;
3549   boolean moved = FALSE, snapped = FALSE, bombed = FALSE;
3550   int jx = player->jx, jy = player->jy;
3551   int left      = player_action & JOY_LEFT;
3552   int right     = player_action & JOY_RIGHT;
3553   int up        = player_action & JOY_UP;
3554   int down      = player_action & JOY_DOWN;
3555   int button1   = player_action & JOY_BUTTON_1;
3556   int button2   = player_action & JOY_BUTTON_2;
3557   int dx        = (left ? -1    : right ? 1     : 0);
3558   int dy        = (up   ? -1    : down  ? 1     : 0);
3559
3560   stored_player_action[player->index_nr] = 0;
3561   num_stored_actions++;
3562
3563   if (!player->active || tape.pausing)
3564     return;
3565
3566   if (player_action)
3567   {
3568     save_tape_entry = TRUE;
3569     player->frame_reset_delay = 0;
3570
3571     if (button1)
3572       snapped = SnapField(player, dx, dy);
3573     else
3574     {
3575       if (button2)
3576         bombed = PlaceBomb(player);
3577       moved = MoveFigure(player, dx, dy);
3578     }
3579
3580     if (tape.recording && (moved || snapped || bombed))
3581     {
3582       if (bombed && !moved)
3583         player_action &= JOY_BUTTON;
3584
3585       stored_player_action[player->index_nr] = player_action;
3586     }
3587     else if (tape.playing && snapped)
3588       SnapField(player, 0, 0);                  /* stop snapping */
3589   }
3590   else
3591   {
3592     /* no actions for this player (no input at player's configured device) */
3593
3594     DigField(player, 0, 0, 0, 0, DF_NO_PUSH);
3595     SnapField(player, 0, 0);
3596     CheckGravityMovement(player);
3597
3598     if (++player->frame_reset_delay > player->move_delay_value)
3599       player->Frame = 0;
3600   }
3601
3602   if (tape.recording && num_stored_actions >= MAX_PLAYERS && save_tape_entry)
3603   {
3604     TapeRecordAction(stored_player_action);
3605     num_stored_actions = 0;
3606     save_tape_entry = FALSE;
3607   }
3608
3609   if (tape.playing && !tape.pausing && !player_action &&
3610       tape.counter < tape.length)
3611   {
3612     int next_joy =
3613       tape.pos[tape.counter].action[player->index_nr] & (JOY_LEFT|JOY_RIGHT);
3614
3615     if ((next_joy == JOY_LEFT || next_joy == JOY_RIGHT) &&
3616         (player->MovDir != JOY_UP && player->MovDir != JOY_DOWN))
3617     {
3618       int dx = (next_joy == JOY_LEFT ? -1 : +1);
3619
3620       if (IN_LEV_FIELD(jx+dx, jy) && IS_PUSHABLE(Feld[jx+dx][jy]))
3621       {
3622         int el = Feld[jx+dx][jy];
3623         int push_delay = (IS_SB_ELEMENT(el) || el == EL_SONDE ? 2 : 10);
3624
3625         if (tape.delay_played + push_delay >= tape.pos[tape.counter].delay)
3626         {
3627           player->MovDir = next_joy;
3628           player->Frame = FrameCounter % 4;
3629           player->Pushing = TRUE;
3630         }
3631       }
3632     }
3633   }
3634 }
3635
3636 void GameActions()
3637 {
3638   static unsigned long action_delay = 0;
3639   unsigned long action_delay_value;
3640   int sieb_x = 0, sieb_y = 0;
3641   int i, x, y, element;
3642   byte *recorded_player_action;
3643   byte summarized_player_action = 0;
3644
3645   if (game_status != PLAYING)
3646     return;
3647
3648   action_delay_value =
3649     (tape.playing && tape.fast_forward ? FfwdFrameDelay : GameFrameDelay);
3650
3651   /* ---------- main game synchronization point ---------- */
3652
3653   WaitUntilDelayReached(&action_delay, action_delay_value);
3654
3655   if (network_playing && !network_player_action_received)
3656   {
3657     /*
3658 #ifdef DEBUG
3659     printf("DEBUG: try to get network player actions in time\n");
3660 #endif
3661     */
3662
3663 #ifndef MSDOS
3664     /* last chance to get network player actions without main loop delay */
3665     HandleNetworking();
3666 #endif
3667
3668     if (game_status != PLAYING)
3669       return;
3670
3671     if (!network_player_action_received)
3672     {
3673       /*
3674 #ifdef DEBUG
3675       printf("DEBUG: failed to get network player actions in time\n");
3676 #endif
3677       */
3678       return;
3679     }
3680   }
3681
3682   if (tape.pausing)
3683     return;
3684
3685   if (tape.playing)
3686     TapePlayDelay();
3687   else if (tape.recording)
3688     TapeRecordDelay();
3689
3690   recorded_player_action = (tape.playing ? TapePlayAction() : NULL);
3691
3692   for (i=0; i<MAX_PLAYERS; i++)
3693   {
3694     summarized_player_action |= stored_player[i].action;
3695
3696     if (!network_playing)
3697       stored_player[i].effective_action = stored_player[i].action;
3698   }
3699
3700 #ifndef MSDOS
3701   if (network_playing)
3702     SendToServer_MovePlayer(summarized_player_action);
3703 #endif
3704
3705   if (!options.network && !setup.team_mode)
3706     local_player->effective_action = summarized_player_action;
3707
3708   for (i=0; i<MAX_PLAYERS; i++)
3709   {
3710     int actual_player_action = stored_player[i].effective_action;
3711
3712     if (stored_player[i].programmed_action)
3713       actual_player_action = stored_player[i].programmed_action;
3714
3715     if (recorded_player_action)
3716       actual_player_action = recorded_player_action[i];
3717
3718     PlayerActions(&stored_player[i], actual_player_action);
3719     ScrollFigure(&stored_player[i], SCROLL_GO_ON);
3720   }
3721
3722   network_player_action_received = FALSE;
3723
3724   ScrollScreen(NULL, SCROLL_GO_ON);
3725
3726
3727
3728 #ifdef DEBUG
3729 #if 0
3730   if (TimeFrames == 0 && local_player->active)
3731   {
3732     extern unsigned int last_RND();
3733
3734     printf("DEBUG: %03d last RND was %d \t [state checksum is %d]\n",
3735            TimePlayed, last_RND(), getStateCheckSum(TimePlayed));
3736   }
3737 #endif
3738 #endif
3739
3740 #ifdef DEBUG
3741 #if 0
3742   if (GameFrameDelay >= 500)
3743     printf("FrameCounter == %d\n", FrameCounter);
3744 #endif
3745 #endif
3746
3747
3748
3749   FrameCounter++;
3750   TimeFrames++;
3751
3752   for (y=0; y<lev_fieldy; y++) for (x=0; x<lev_fieldx; x++)
3753   {
3754     Stop[x][y] = FALSE;
3755     if (JustStopped[x][y] > 0)
3756       JustStopped[x][y]--;
3757
3758 #if DEBUG
3759     if (IS_BLOCKED(x, y))
3760     {
3761       int oldx, oldy;
3762
3763       Blocked2Moving(x, y, &oldx, &oldy);
3764       if (!IS_MOVING(oldx, oldy))
3765       {
3766         printf("GameActions(): (BLOCKED => MOVING) context corrupted!\n");
3767         printf("GameActions(): BLOCKED: x = %d, y = %d\n", x, y);
3768         printf("GameActions(): !MOVING: oldx = %d, oldy = %d\n", oldx, oldy);
3769         printf("GameActions(): This should never happen!\n");
3770       }
3771     }
3772 #endif
3773   }
3774
3775   for (y=0; y<lev_fieldy; y++) for (x=0; x<lev_fieldx; x++)
3776   {
3777     element = Feld[x][y];
3778
3779     if (IS_INACTIVE(element))
3780       continue;
3781
3782     if (!IS_MOVING(x, y) && (CAN_FALL(element) || CAN_MOVE(element)))
3783     {
3784       StartMoving(x, y);
3785
3786       if (IS_GEM(element))
3787         EdelsteinFunkeln(x, y);
3788     }
3789     else if (IS_MOVING(x, y))
3790       ContinueMoving(x, y);
3791     else if (IS_ACTIVE_BOMB(element))
3792       CheckDynamite(x, y);
3793     else if (element == EL_EXPLODING)
3794       Explode(x, y, Frame[x][y], EX_NORMAL);
3795     else if (element == EL_AMOEBING)
3796       AmoebeWaechst(x, y);
3797     else if (IS_AMOEBALIVE(element))
3798       AmoebeAbleger(x, y);
3799     else if (element == EL_LIFE || element == EL_LIFE_ASYNC)
3800       Life(x, y);
3801     else if (element == EL_ABLENK_EIN)
3802       Ablenk(x, y);
3803     else if (element == EL_SALZSAEURE)
3804       Blubber(x, y);
3805     else if (element == EL_BLURB_LEFT || element == EL_BLURB_RIGHT)
3806       Blurb(x, y);
3807     else if (element == EL_CRACKINGNUT)
3808       NussKnacken(x, y);
3809     else if (element == EL_AUSGANG_ZU)
3810       AusgangstuerPruefen(x, y);
3811     else if (element == EL_AUSGANG_ACT)
3812       AusgangstuerOeffnen(x, y);
3813     else if (element == EL_AUSGANG_AUF)
3814       AusgangstuerBlinken(x, y);
3815     else if (element == EL_MAUERND)
3816       MauerWaechst(x, y);
3817     else if (element == EL_MAUER_LEBT ||
3818              element == EL_MAUER_X ||
3819              element == EL_MAUER_Y ||
3820              element == EL_MAUER_XY)
3821       MauerAbleger(x, y);
3822     else if (element == EL_BURNING)
3823       CheckForDragon(x, y);
3824     else if (element == EL_SP_BUG || element == EL_SP_BUG_ACTIVE)
3825       CheckBuggyBase(x, y);
3826     else if (element == EL_SP_TERMINAL)
3827       DrawGraphicAnimation(x, y, GFX2_SP_TERMINAL, 7, 12, ANIM_NORMAL);
3828     else if (element == EL_SP_TERMINAL_ACTIVE)
3829       DrawGraphicAnimation(x, y, GFX2_SP_TERMINAL_ACTIVE, 7, 4, ANIM_NORMAL);
3830     else if (IS_BELT(element))
3831       DrawBeltAnimation(x, y, element);
3832     else if (element == EL_SWITCHGATE_OPENING)
3833       OpenSwitchgate(x, y);
3834     else if (element == EL_SWITCHGATE_CLOSING)
3835       CloseSwitchgate(x, y);
3836
3837     if (game.magic_wall_active)
3838     {
3839       boolean sieb = FALSE;
3840       int jx = local_player->jx, jy = local_player->jy;
3841
3842       if (element == EL_SIEB_LEER || element == EL_SIEB_VOLL ||
3843           Store[x][y] == EL_SIEB_LEER)
3844       {
3845         SiebAktivieren(x, y, 1);
3846         sieb = TRUE;
3847       }
3848       else if (element == EL_SIEB2_LEER || element == EL_SIEB2_VOLL ||
3849                Store[x][y] == EL_SIEB2_LEER)
3850       {
3851         SiebAktivieren(x, y, 2);
3852         sieb = TRUE;
3853       }
3854
3855       /* play the element sound at the position nearest to the player */
3856       if (sieb && ABS(x-jx)+ABS(y-jy) < ABS(sieb_x-jx)+ABS(sieb_y-jy))
3857       {
3858         sieb_x = x;
3859         sieb_y = y;
3860       }
3861     }
3862   }
3863
3864   if (game.magic_wall_active)
3865   {
3866     if (!(game.magic_wall_time_left % 4))
3867       PlaySoundLevel(sieb_x, sieb_y, SND_MIEP);
3868
3869     if (game.magic_wall_time_left > 0)
3870     {
3871       game.magic_wall_time_left--;
3872       if (!game.magic_wall_time_left)
3873       {
3874         for (y=0; y<lev_fieldy; y++) for (x=0; x<lev_fieldx; x++)
3875         {
3876           element = Feld[x][y];
3877
3878           if (element == EL_SIEB_LEER || element == EL_SIEB_VOLL)
3879           {
3880             Feld[x][y] = EL_SIEB_TOT;
3881             DrawLevelField(x, y);
3882           }
3883           else if (element == EL_SIEB2_LEER || element == EL_SIEB2_VOLL)
3884           {
3885             Feld[x][y] = EL_SIEB2_TOT;
3886             DrawLevelField(x, y);
3887           }
3888         }
3889
3890         game.magic_wall_active = FALSE;
3891       }
3892     }
3893   }
3894
3895   if (game.light_time_left > 0)
3896   {
3897     game.light_time_left--;
3898
3899     if (game.light_time_left == 0)
3900     {
3901       for (y=0; y<lev_fieldy; y++) for (x=0; x<lev_fieldx; x++)
3902       {
3903         element = Feld[x][y];
3904
3905         if (element == EL_LIGHT_SWITCH_ON)
3906         {
3907           Feld[x][y] = EL_LIGHT_SWITCH_OFF;
3908           DrawLevelField(x, y);
3909         }
3910         else if (element == EL_INVISIBLE_STEEL ||
3911                  element == EL_UNSICHTBAR ||
3912                  element == EL_SAND_INVISIBLE)
3913           DrawLevelField(x, y);
3914       }
3915     }
3916   }
3917
3918   if (TimeFrames >= (1000 / GameFrameDelay) && !tape.pausing)
3919   {
3920     TimeFrames = 0;
3921     TimePlayed++;
3922
3923     if (tape.recording || tape.playing)
3924       DrawVideoDisplay(VIDEO_STATE_TIME_ON, TimePlayed);
3925
3926     if (TimeLeft > 0)
3927     {
3928       TimeLeft--;
3929
3930       if (TimeLeft <= 10)
3931         PlaySoundStereo(SND_GONG, PSND_MAX_RIGHT);
3932
3933       DrawText(DX_TIME, DY_TIME, int2str(TimeLeft, 3), FS_SMALL, FC_YELLOW);
3934
3935       if (!TimeLeft)
3936         for (i=0; i<MAX_PLAYERS; i++)
3937           KillHero(&stored_player[i]);
3938     }
3939     else if (level.time == 0)           /* level without time limit */
3940       DrawText(DX_TIME, DY_TIME, int2str(TimePlayed, 3), FS_SMALL, FC_YELLOW);
3941   }
3942
3943   DrawAllPlayers();
3944 }
3945
3946 static boolean AllPlayersInSight(struct PlayerInfo *player, int x, int y)
3947 {
3948   int min_x = x, min_y = y, max_x = x, max_y = y;
3949   int i;
3950
3951   for (i=0; i<MAX_PLAYERS; i++)
3952   {
3953     int jx = stored_player[i].jx, jy = stored_player[i].jy;
3954
3955     if (!stored_player[i].active || &stored_player[i] == player)
3956       continue;
3957
3958     min_x = MIN(min_x, jx);
3959     min_y = MIN(min_y, jy);
3960     max_x = MAX(max_x, jx);
3961     max_y = MAX(max_y, jy);
3962   }
3963
3964   return (max_x - min_x < SCR_FIELDX && max_y - min_y < SCR_FIELDY);
3965 }
3966
3967 static boolean AllPlayersInVisibleScreen()
3968 {
3969   int i;
3970
3971   for (i=0; i<MAX_PLAYERS; i++)
3972   {
3973     int jx = stored_player[i].jx, jy = stored_player[i].jy;
3974
3975     if (!stored_player[i].active)
3976       continue;
3977
3978     if (!IN_VIS_FIELD(SCREENX(jx), SCREENY(jy)))
3979       return FALSE;
3980   }
3981
3982   return TRUE;
3983 }
3984
3985 void ScrollLevel(int dx, int dy)
3986 {
3987   int softscroll_offset = (setup.soft_scrolling ? TILEX : 0);
3988   int x, y;
3989
3990   XCopyArea(display, drawto_field, drawto_field, gc,
3991             FX + TILEX*(dx == -1) - softscroll_offset,
3992             FY + TILEY*(dy == -1) - softscroll_offset,
3993             SXSIZE - TILEX*(dx!=0) + 2*softscroll_offset,
3994             SYSIZE - TILEY*(dy!=0) + 2*softscroll_offset,
3995             FX + TILEX*(dx == 1) - softscroll_offset,
3996             FY + TILEY*(dy == 1) - softscroll_offset);
3997
3998   if (dx)
3999   {
4000     x = (dx == 1 ? BX1 : BX2);
4001     for (y=BY1; y<=BY2; y++)
4002       DrawScreenField(x, y);
4003   }
4004   if (dy)
4005   {
4006     y = (dy == 1 ? BY1 : BY2);
4007     for (x=BX1; x<=BX2; x++)
4008       DrawScreenField(x, y);
4009   }
4010
4011   redraw_mask |= REDRAW_FIELD;
4012 }
4013
4014 static void CheckGravityMovement(struct PlayerInfo *player)
4015 {
4016   if (level.gravity && !player->programmed_action)
4017   {
4018     int move_dir_vertical = player->action & (MV_UP | MV_DOWN);
4019     int move_dir_horizontal = player->action & (MV_LEFT | MV_RIGHT);
4020     int move_dir =
4021       (player->last_move_dir & (MV_LEFT | MV_RIGHT) ?
4022        (move_dir_vertical ? move_dir_vertical : move_dir_horizontal) :
4023        (move_dir_horizontal ? move_dir_horizontal : move_dir_vertical));
4024     int jx = player->jx, jy = player->jy;
4025     int dx = (move_dir & MV_LEFT ? -1 : move_dir & MV_RIGHT ? +1 : 0);
4026     int dy = (move_dir & MV_UP ? -1 : move_dir & MV_DOWN ? +1 : 0);
4027     int new_jx = jx + dx, new_jy = jy + dy;
4028     boolean field_under_player_is_free =
4029       (IN_LEV_FIELD(jx, jy + 1) && IS_FREE(jx, jy + 1));
4030     boolean player_is_moving_to_valid_field =
4031       (IN_LEV_FIELD(new_jx, new_jy) &&
4032        (Feld[new_jx][new_jy] == EL_SP_BASE ||
4033         Feld[new_jx][new_jy] == EL_ERDREICH));
4034
4035     if (field_under_player_is_free && !player_is_moving_to_valid_field)
4036       player->programmed_action = MV_DOWN;
4037   }
4038 }
4039
4040 boolean MoveFigureOneStep(struct PlayerInfo *player,
4041                           int dx, int dy, int real_dx, int real_dy)
4042 {
4043   int jx = player->jx, jy = player->jy;
4044   int new_jx = jx+dx, new_jy = jy+dy;
4045   int element;
4046   int can_move;
4047
4048   if (!player->active || (!dx && !dy))
4049     return MF_NO_ACTION;
4050
4051   player->MovDir = (dx < 0 ? MV_LEFT :
4052                     dx > 0 ? MV_RIGHT :
4053                     dy < 0 ? MV_UP :
4054                     dy > 0 ? MV_DOWN :  MV_NO_MOVING);
4055
4056   if (!IN_LEV_FIELD(new_jx, new_jy))
4057     return MF_NO_ACTION;
4058
4059   if (!options.network && !AllPlayersInSight(player, new_jx, new_jy))
4060     return MF_NO_ACTION;
4061
4062 #if 0
4063   element = MovingOrBlocked2Element(new_jx, new_jy);
4064 #else
4065   element = MovingOrBlocked2ElementIfNotLeaving(new_jx, new_jy);
4066 #endif
4067
4068   if (DONT_GO_TO(element))
4069   {
4070     if (element == EL_SALZSAEURE && dx == 0 && dy == 1)
4071     {
4072       Blurb(jx, jy);
4073       Feld[jx][jy] = EL_SPIELFIGUR;
4074       InitMovingField(jx, jy, MV_DOWN);
4075       Store[jx][jy] = EL_SALZSAEURE;
4076       ContinueMoving(jx, jy);
4077       BuryHero(player);
4078     }
4079     else
4080       KillHero(player);
4081
4082     return MF_MOVING;
4083   }
4084
4085   can_move = DigField(player, new_jx, new_jy, real_dx, real_dy, DF_DIG);
4086   if (can_move != MF_MOVING)
4087     return can_move;
4088
4089   StorePlayer[jx][jy] = 0;
4090   player->last_jx = jx;
4091   player->last_jy = jy;
4092   jx = player->jx = new_jx;
4093   jy = player->jy = new_jy;
4094   StorePlayer[jx][jy] = player->element_nr;
4095
4096   player->MovPos =
4097     (dx > 0 || dy > 0 ? -1 : 1) * (TILEX - TILEX / player->move_delay_value);
4098
4099   ScrollFigure(player, SCROLL_INIT);
4100
4101   return MF_MOVING;
4102 }
4103
4104 boolean MoveFigure(struct PlayerInfo *player, int dx, int dy)
4105 {
4106   int jx = player->jx, jy = player->jy;
4107   int old_jx = jx, old_jy = jy;
4108   int moved = MF_NO_ACTION;
4109
4110   if (!player->active || (!dx && !dy))
4111     return FALSE;
4112
4113   if (!FrameReached(&player->move_delay, player->move_delay_value) &&
4114       !tape.playing)
4115     return FALSE;
4116
4117   /* remove the last programmed player action */
4118   player->programmed_action = 0;
4119
4120   if (player->MovPos)
4121   {
4122     /* should only happen if pre-1.2 tape recordings are played */
4123     /* this is only for backward compatibility */
4124
4125     int original_move_delay_value = player->move_delay_value;
4126
4127 #if DEBUG
4128     printf("THIS SHOULD ONLY HAPPEN WITH PRE-1.2 LEVEL TAPES.\n");
4129 #endif
4130
4131     /* scroll remaining steps with finest movement resolution */
4132     player->move_delay_value = MOVE_DELAY_NORMAL_SPEED;
4133
4134     while (player->MovPos)
4135     {
4136       ScrollFigure(player, SCROLL_GO_ON);
4137       ScrollScreen(NULL, SCROLL_GO_ON);
4138       FrameCounter++;
4139       DrawAllPlayers();
4140       BackToFront();
4141     }
4142
4143     player->move_delay_value = original_move_delay_value;
4144   }
4145
4146   if (player->last_move_dir & (MV_LEFT | MV_RIGHT))
4147   {
4148     if (!(moved |= MoveFigureOneStep(player, 0, dy, dx, dy)))
4149       moved |= MoveFigureOneStep(player, dx, 0, dx, dy);
4150   }
4151   else
4152   {
4153     if (!(moved |= MoveFigureOneStep(player, dx, 0, dx, dy)))
4154       moved |= MoveFigureOneStep(player, 0, dy, dx, dy);
4155   }
4156
4157   jx = player->jx;
4158   jy = player->jy;
4159
4160   if (moved & MF_MOVING && !ScreenMovPos &&
4161       (player == local_player || !options.network))
4162   {
4163     int old_scroll_x = scroll_x, old_scroll_y = scroll_y;
4164     int offset = (setup.scroll_delay ? 3 : 0);
4165
4166     if (!IN_VIS_FIELD(SCREENX(jx), SCREENY(jy)))
4167     {
4168       /* actual player has left the screen -- scroll in that direction */
4169       if (jx != old_jx)         /* player has moved horizontally */
4170         scroll_x += (jx - old_jx);
4171       else                      /* player has moved vertically */
4172         scroll_y += (jy - old_jy);
4173     }
4174     else
4175     {
4176       if (jx != old_jx)         /* player has moved horizontally */
4177       {
4178         if ((player->MovDir == MV_LEFT && scroll_x > jx - MIDPOSX + offset) ||
4179             (player->MovDir == MV_RIGHT && scroll_x < jx - MIDPOSX - offset))
4180           scroll_x = jx-MIDPOSX + (scroll_x < jx-MIDPOSX ? -offset : +offset);
4181
4182         /* don't scroll over playfield boundaries */
4183         if (scroll_x < SBX_Left || scroll_x > SBX_Right)
4184           scroll_x = (scroll_x < SBX_Left ? SBX_Left : SBX_Right);
4185
4186         /* don't scroll more than one field at a time */
4187         scroll_x = old_scroll_x + SIGN(scroll_x - old_scroll_x);
4188
4189         /* don't scroll against the player's moving direction */
4190         if ((player->MovDir == MV_LEFT && scroll_x > old_scroll_x) ||
4191             (player->MovDir == MV_RIGHT && scroll_x < old_scroll_x))
4192           scroll_x = old_scroll_x;
4193       }
4194       else                      /* player has moved vertically */
4195       {
4196         if ((player->MovDir == MV_UP && scroll_y > jy - MIDPOSY + offset) ||
4197             (player->MovDir == MV_DOWN && scroll_y < jy - MIDPOSY - offset))
4198           scroll_y = jy-MIDPOSY + (scroll_y < jy-MIDPOSY ? -offset : +offset);
4199
4200         /* don't scroll over playfield boundaries */
4201         if (scroll_y < SBY_Upper || scroll_y > SBY_Lower)
4202           scroll_y = (scroll_y < SBY_Upper ? SBY_Upper : SBY_Lower);
4203
4204         /* don't scroll more than one field at a time */
4205         scroll_y = old_scroll_y + SIGN(scroll_y - old_scroll_y);
4206
4207         /* don't scroll against the player's moving direction */
4208         if ((player->MovDir == MV_UP && scroll_y > old_scroll_y) ||
4209             (player->MovDir == MV_DOWN && scroll_y < old_scroll_y))
4210           scroll_y = old_scroll_y;
4211       }
4212     }
4213
4214     if (scroll_x != old_scroll_x || scroll_y != old_scroll_y)
4215     {
4216       if (!options.network && !AllPlayersInVisibleScreen())
4217       {
4218         scroll_x = old_scroll_x;
4219         scroll_y = old_scroll_y;
4220       }
4221       else
4222       {
4223         ScrollScreen(player, SCROLL_INIT);
4224         ScrollLevel(old_scroll_x - scroll_x, old_scroll_y - scroll_y);
4225       }
4226     }
4227   }
4228
4229   if (!(moved & MF_MOVING) && !player->Pushing)
4230     player->Frame = 0;
4231   else
4232     player->Frame = (player->Frame + 1) % 4;
4233
4234   if (moved & MF_MOVING)
4235   {
4236     if (old_jx != jx && old_jy == jy)
4237       player->MovDir = (old_jx < jx ? MV_RIGHT : MV_LEFT);
4238     else if (old_jx == jx && old_jy != jy)
4239       player->MovDir = (old_jy < jy ? MV_DOWN : MV_UP);
4240
4241     DrawLevelField(jx, jy);     /* for "ErdreichAnbroeckeln()" */
4242
4243     player->last_move_dir = player->MovDir;
4244   }
4245   else
4246   {
4247     CheckGravityMovement(player);
4248
4249     player->last_move_dir = MV_NO_MOVING;
4250   }
4251
4252   TestIfHeroHitsBadThing(jx, jy);
4253
4254   if (!player->active)
4255     RemoveHero(player);
4256
4257   return moved;
4258 }
4259
4260 void ScrollFigure(struct PlayerInfo *player, int mode)
4261 {
4262   int jx = player->jx, jy = player->jy;
4263   int last_jx = player->last_jx, last_jy = player->last_jy;
4264   int move_stepsize = TILEX / player->move_delay_value;
4265
4266   if (!player->active || !player->MovPos)
4267     return;
4268
4269   if (mode == SCROLL_INIT)
4270   {
4271     player->actual_frame_counter = FrameCounter;
4272     player->GfxPos = move_stepsize * (player->MovPos / move_stepsize);
4273
4274     if (Feld[last_jx][last_jy] == EL_LEERRAUM)
4275       Feld[last_jx][last_jy] = EL_PLAYER_IS_LEAVING;
4276
4277     DrawPlayer(player);
4278     return;
4279   }
4280   else if (!FrameReached(&player->actual_frame_counter, 1))
4281     return;
4282
4283   player->MovPos += (player->MovPos > 0 ? -1 : 1) * move_stepsize;
4284   player->GfxPos = move_stepsize * (player->MovPos / move_stepsize);
4285
4286   if (Feld[last_jx][last_jy] == EL_PLAYER_IS_LEAVING)
4287     Feld[last_jx][last_jy] = EL_LEERRAUM;
4288
4289   /* before DrawPlayer() to draw correct player graphic for this case */
4290   if (player->MovPos == 0)
4291     CheckGravityMovement(player);
4292
4293   DrawPlayer(player);
4294
4295   if (player->MovPos == 0)
4296   {
4297     if (IS_QUICK_GATE(Feld[last_jx][last_jy]))
4298     {
4299       /* continue with normal speed after quickly moving through gate */
4300       HALVE_PLAYER_SPEED(player);
4301
4302       /* be able to make the next move without delay */
4303       player->move_delay = 0;
4304     }
4305
4306     player->last_jx = jx;
4307     player->last_jy = jy;
4308
4309     if (Feld[jx][jy] == EL_AUSGANG_AUF)
4310     {
4311       RemoveHero(player);
4312
4313       if (!local_player->friends_still_needed)
4314         player->LevelSolved = player->GameOver = TRUE;
4315     }
4316   }
4317 }
4318
4319 void ScrollScreen(struct PlayerInfo *player, int mode)
4320 {
4321   static unsigned long screen_frame_counter = 0;
4322
4323   if (mode == SCROLL_INIT)
4324   {
4325     /* set scrolling step size according to actual player's moving speed */
4326     ScrollStepSize = TILEX / player->move_delay_value;
4327
4328     screen_frame_counter = FrameCounter;
4329     ScreenMovDir = player->MovDir;
4330     ScreenMovPos = player->MovPos;
4331     ScreenGfxPos = ScrollStepSize * (ScreenMovPos / ScrollStepSize);
4332     return;
4333   }
4334   else if (!FrameReached(&screen_frame_counter, 1))
4335     return;
4336
4337   if (ScreenMovPos)
4338   {
4339     ScreenMovPos += (ScreenMovPos > 0 ? -1 : 1) * ScrollStepSize;
4340     ScreenGfxPos = ScrollStepSize * (ScreenMovPos / ScrollStepSize);
4341     redraw_mask |= REDRAW_FIELD;
4342   }
4343   else
4344     ScreenMovDir = MV_NO_MOVING;
4345 }
4346
4347 void TestIfGoodThingHitsBadThing(int goodx, int goody)
4348 {
4349   int i, killx = goodx, killy = goody;
4350   static int xy[4][2] =
4351   {
4352     { 0, -1 },
4353     { -1, 0 },
4354     { +1, 0 },
4355     { 0, +1 }
4356   };
4357   static int harmless[4] =
4358   {
4359     MV_UP,
4360     MV_LEFT,
4361     MV_RIGHT,
4362     MV_DOWN
4363   };
4364
4365   for (i=0; i<4; i++)
4366   {
4367     int x, y, element;
4368
4369     x = goodx + xy[i][0];
4370     y = goody + xy[i][1];
4371     if (!IN_LEV_FIELD(x, y))
4372       continue;
4373
4374 #if 0
4375     element = Feld[x][y];
4376 #else
4377     element = MovingOrBlocked2ElementIfNotLeaving(x, y);
4378 #endif
4379
4380     if (DONT_TOUCH(element))
4381     {
4382       if (MovDir[x][y] == harmless[i])
4383         continue;
4384
4385       killx = x;
4386       killy = y;
4387       break;
4388     }
4389   }
4390
4391   if (killx != goodx || killy != goody)
4392   {
4393     if (IS_PLAYER(goodx, goody))
4394       KillHero(PLAYERINFO(goodx, goody));
4395     else
4396       Bang(goodx, goody);
4397   }
4398 }
4399
4400 void TestIfBadThingHitsGoodThing(int badx, int bady)
4401 {
4402   int i, killx = badx, killy = bady;
4403   static int xy[4][2] =
4404   {
4405     { 0, -1 },
4406     { -1, 0 },
4407     { +1, 0 },
4408     { 0, +1 }
4409   };
4410   static int harmless[4] =
4411   {
4412     MV_UP,
4413     MV_LEFT,
4414     MV_RIGHT,
4415     MV_DOWN
4416   };
4417
4418   for (i=0; i<4; i++)
4419   {
4420     int x, y, element;
4421
4422     x = badx + xy[i][0];
4423     y = bady + xy[i][1];
4424     if (!IN_LEV_FIELD(x, y))
4425       continue;
4426
4427     element = Feld[x][y];
4428
4429     if (IS_PLAYER(x, y))
4430     {
4431       killx = x;
4432       killy = y;
4433       break;
4434     }
4435     else if (element == EL_PINGUIN)
4436     {
4437       if (MovDir[x][y] == harmless[i] && IS_MOVING(x, y))
4438         continue;
4439
4440       killx = x;
4441       killy = y;
4442       break;
4443     }
4444   }
4445
4446   if (killx != badx || killy != bady)
4447   {
4448     if (IS_PLAYER(killx, killy))
4449       KillHero(PLAYERINFO(killx, killy));
4450     else
4451       Bang(killx, killy);
4452   }
4453 }
4454
4455 void TestIfHeroHitsBadThing(int x, int y)
4456 {
4457   TestIfGoodThingHitsBadThing(x, y);
4458 }
4459
4460 void TestIfBadThingHitsHero(int x, int y)
4461 {
4462   TestIfBadThingHitsGoodThing(x, y);
4463 }
4464
4465 void TestIfFriendHitsBadThing(int x, int y)
4466 {
4467   TestIfGoodThingHitsBadThing(x, y);
4468 }
4469
4470 void TestIfBadThingHitsFriend(int x, int y)
4471 {
4472   TestIfBadThingHitsGoodThing(x, y);
4473 }
4474
4475 void TestIfBadThingHitsOtherBadThing(int badx, int bady)
4476 {
4477   int i, killx = badx, killy = bady;
4478   static int xy[4][2] =
4479   {
4480     { 0, -1 },
4481     { -1, 0 },
4482     { +1, 0 },
4483     { 0, +1 }
4484   };
4485
4486   for (i=0; i<4; i++)
4487   {
4488     int x, y, element;
4489
4490     x=badx + xy[i][0];
4491     y=bady + xy[i][1];
4492     if (!IN_LEV_FIELD(x, y))
4493       continue;
4494
4495     element = Feld[x][y];
4496     if (IS_AMOEBOID(element) || element == EL_LIFE ||
4497         element == EL_AMOEBING || element == EL_TROPFEN)
4498     {
4499       killx = x;
4500       killy = y;
4501       break;
4502     }
4503   }
4504
4505   if (killx != badx || killy != bady)
4506     Bang(badx, bady);
4507 }
4508
4509 void KillHero(struct PlayerInfo *player)
4510 {
4511   int jx = player->jx, jy = player->jy;
4512
4513   if (!player->active)
4514     return;
4515
4516   if (IS_PFORTE(Feld[jx][jy]))
4517     Feld[jx][jy] = EL_LEERRAUM;
4518
4519   Bang(jx, jy);
4520   BuryHero(player);
4521 }
4522
4523 void BuryHero(struct PlayerInfo *player)
4524 {
4525   int jx = player->jx, jy = player->jy;
4526
4527   if (!player->active)
4528     return;
4529
4530   PlaySoundLevel(jx, jy, SND_AUTSCH);
4531   PlaySoundLevel(jx, jy, SND_LACHEN);
4532
4533   player->GameOver = TRUE;
4534   RemoveHero(player);
4535 }
4536
4537 void RemoveHero(struct PlayerInfo *player)
4538 {
4539   int jx = player->jx, jy = player->jy;
4540   int i, found = FALSE;
4541
4542   player->present = FALSE;
4543   player->active = FALSE;
4544
4545   StorePlayer[jx][jy] = 0;
4546
4547   for (i=0; i<MAX_PLAYERS; i++)
4548     if (stored_player[i].active)
4549       found = TRUE;
4550
4551   if (!found)
4552     AllPlayersGone = TRUE;
4553
4554   ExitX = ZX = jx;
4555   ExitY = ZY = jy;
4556 }
4557
4558 int DigField(struct PlayerInfo *player,
4559              int x, int y, int real_dx, int real_dy, int mode)
4560 {
4561   int jx = player->jx, jy = player->jy;
4562   int dx = x - jx, dy = y - jy;
4563   int move_direction = (dx == -1 ? MV_LEFT :
4564                         dx == +1 ? MV_RIGHT :
4565                         dy == -1 ? MV_UP :
4566                         dy == +1 ? MV_DOWN : MV_NO_MOVING);
4567   int element;
4568
4569   if (!player->MovPos)
4570     player->Pushing = FALSE;
4571
4572   if (mode == DF_NO_PUSH)
4573   {
4574     player->Switching = FALSE;
4575     player->push_delay = 0;
4576     return MF_NO_ACTION;
4577   }
4578
4579   if (IS_MOVING(x, y) || IS_PLAYER(x, y))
4580     return MF_NO_ACTION;
4581
4582   element = Feld[x][y];
4583
4584   switch (element)
4585   {
4586     case EL_LEERRAUM:
4587       PlaySoundLevel(x, y, SND_EMPTY);
4588       break;
4589
4590     case EL_ERDREICH:
4591     case EL_SAND_INVISIBLE:
4592       Feld[x][y] = EL_LEERRAUM;
4593       PlaySoundLevel(x, y, SND_SCHLURF);
4594       break;
4595
4596     case EL_SP_BASE:
4597     case EL_SP_BUG:
4598       Feld[x][y] = EL_LEERRAUM;
4599       PlaySoundLevel(x, y, SND_SP_BASE);
4600       break;
4601
4602     case EL_EDELSTEIN:
4603     case EL_EDELSTEIN_BD:
4604     case EL_EDELSTEIN_GELB:
4605     case EL_EDELSTEIN_ROT:
4606     case EL_EDELSTEIN_LILA:
4607     case EL_DIAMANT:
4608     case EL_SP_INFOTRON:
4609       RemoveField(x, y);
4610       local_player->gems_still_needed -= (element == EL_DIAMANT ? 3 : 1);
4611       if (local_player->gems_still_needed < 0)
4612         local_player->gems_still_needed = 0;
4613       RaiseScoreElement(element);
4614       DrawText(DX_EMERALDS, DY_EMERALDS,
4615                int2str(local_player->gems_still_needed, 3),
4616                FS_SMALL, FC_YELLOW);
4617       if (element == EL_SP_INFOTRON)
4618         PlaySoundLevel(x, y, SND_SP_INFOTRON);
4619       else
4620         PlaySoundLevel(x, y, SND_PONG);
4621       break;
4622
4623     case EL_SPEED_PILL:
4624       RemoveField(x, y);
4625       player->move_delay_value = MOVE_DELAY_HIGH_SPEED;
4626       PlaySoundLevel(x, y, SND_PONG);
4627       break;
4628
4629     case EL_ENVELOPE:
4630       Feld[x][y] = EL_LEERRAUM;
4631       PlaySoundLevel(x, y, SND_PONG);
4632       break;
4633
4634     case EL_DYNAMITE_INACTIVE:
4635     case EL_SP_DISK_RED:
4636       RemoveField(x, y);
4637       player->dynamite++;
4638       RaiseScoreElement(EL_DYNAMITE_INACTIVE);
4639       DrawText(DX_DYNAMITE, DY_DYNAMITE,
4640                int2str(local_player->dynamite, 3),
4641                FS_SMALL, FC_YELLOW);
4642       if (element == EL_SP_DISK_RED)
4643         PlaySoundLevel(x, y, SND_SP_INFOTRON);
4644       else
4645         PlaySoundLevel(x, y, SND_PONG);
4646       break;
4647
4648     case EL_DYNABOMB_NR:
4649       RemoveField(x, y);
4650       player->dynabomb_count++;
4651       player->dynabombs_left++;
4652       RaiseScoreElement(EL_DYNAMITE_INACTIVE);
4653       PlaySoundLevel(x, y, SND_PONG);
4654       break;
4655
4656     case EL_DYNABOMB_SZ:
4657       RemoveField(x, y);
4658       player->dynabomb_size++;
4659       RaiseScoreElement(EL_DYNAMITE_INACTIVE);
4660       PlaySoundLevel(x, y, SND_PONG);
4661       break;
4662
4663     case EL_DYNABOMB_XL:
4664       RemoveField(x, y);
4665       player->dynabomb_xl = TRUE;
4666       RaiseScoreElement(EL_DYNAMITE_INACTIVE);
4667       PlaySoundLevel(x, y, SND_PONG);
4668       break;
4669
4670     case EL_SCHLUESSEL1:
4671     case EL_SCHLUESSEL2:
4672     case EL_SCHLUESSEL3:
4673     case EL_SCHLUESSEL4:
4674     {
4675       int key_nr = element - EL_SCHLUESSEL1;
4676
4677       RemoveField(x, y);
4678       player->key[key_nr] = TRUE;
4679       RaiseScoreElement(EL_SCHLUESSEL);
4680       DrawMiniGraphicExt(drawto, gc,
4681                          DX_KEYS+key_nr*MINI_TILEX, DY_KEYS,
4682                          GFX_SCHLUESSEL1+key_nr);
4683       DrawMiniGraphicExt(window, gc,
4684                          DX_KEYS+key_nr*MINI_TILEX, DY_KEYS,
4685                          GFX_SCHLUESSEL1+key_nr);
4686       PlaySoundLevel(x, y, SND_PONG);
4687       break;
4688     }
4689
4690     case EL_EM_KEY_1:
4691     case EL_EM_KEY_2:
4692     case EL_EM_KEY_3:
4693     case EL_EM_KEY_4:
4694     {
4695       int key_nr = element - EL_EM_KEY_1;
4696
4697       RemoveField(x, y);
4698       player->key[key_nr] = TRUE;
4699       RaiseScoreElement(EL_SCHLUESSEL);
4700       DrawMiniGraphicExt(drawto, gc,
4701                          DX_KEYS+key_nr*MINI_TILEX, DY_KEYS,
4702                          GFX_SCHLUESSEL1+key_nr);
4703       DrawMiniGraphicExt(window, gc,
4704                          DX_KEYS+key_nr*MINI_TILEX, DY_KEYS,
4705                          GFX_SCHLUESSEL1+key_nr);
4706       PlaySoundLevel(x, y, SND_PONG);
4707       break;
4708     }
4709
4710     case EL_ABLENK_AUS:
4711       Feld[x][y] = EL_ABLENK_EIN;
4712       ZX = x;
4713       ZY = y;
4714       DrawLevelField(x, y);
4715       return MF_ACTION;
4716       break;
4717
4718     case EL_SP_TERMINAL:
4719       {
4720         int xx, yy;
4721
4722         for (yy=0; yy<lev_fieldy; yy++)
4723         {
4724           for (xx=0; xx<lev_fieldx; xx++)
4725           {
4726             if (Feld[xx][yy] == EL_SP_DISK_YELLOW)
4727               Bang(xx, yy);
4728             else if (Feld[xx][yy] == EL_SP_TERMINAL)
4729               Feld[xx][yy] = EL_SP_TERMINAL_ACTIVE;
4730           }
4731         }
4732
4733         return MF_ACTION;
4734       }
4735       break;
4736
4737     case EL_BELT1_SWITCH_L:
4738     case EL_BELT1_SWITCH_M:
4739     case EL_BELT1_SWITCH_R:
4740     case EL_BELT2_SWITCH_L:
4741     case EL_BELT2_SWITCH_M:
4742     case EL_BELT2_SWITCH_R:
4743     case EL_BELT3_SWITCH_L:
4744     case EL_BELT3_SWITCH_M:
4745     case EL_BELT3_SWITCH_R:
4746     case EL_BELT4_SWITCH_L:
4747     case EL_BELT4_SWITCH_M:
4748     case EL_BELT4_SWITCH_R:
4749       {
4750         static int belt_base_element[4] =
4751         {
4752           EL_BELT1_SWITCH_L,
4753           EL_BELT2_SWITCH_L,
4754           EL_BELT3_SWITCH_L,
4755           EL_BELT4_SWITCH_L
4756         };
4757         static int belt_move_dir[4] =
4758         {
4759           MV_LEFT,
4760           MV_NO_MOVING,
4761           MV_RIGHT,
4762           MV_NO_MOVING,
4763         };
4764
4765         int belt_nr = getBeltNrFromSwitchElement(element);
4766         int belt_dir_nr = (game.belt_dir_nr[belt_nr] + 1) % 4;
4767         int belt_dir = belt_move_dir[belt_dir_nr];
4768         int xx, yy;
4769
4770         if (player->Switching)
4771           return MF_ACTION;
4772
4773         player->Switching = TRUE;
4774
4775         game.belt_dir_nr[belt_nr] = belt_dir_nr;
4776         game.belt_dir[belt_nr] = belt_dir;
4777
4778         if (belt_dir_nr == 3)
4779           belt_dir_nr = 1;
4780
4781         for (yy=0; yy<lev_fieldy; yy++)
4782         {
4783           for (xx=0; xx<lev_fieldx; xx++)
4784           {
4785             int element = Feld[xx][yy];
4786
4787             if (IS_BELT_SWITCH(element))
4788             {
4789               int e_belt_nr = getBeltNrFromSwitchElement(element);
4790
4791               if (e_belt_nr == belt_nr)
4792               {
4793                 Feld[xx][yy] = belt_base_element[belt_nr] + belt_dir_nr;
4794                 DrawLevelField(xx, yy);
4795               }
4796             }
4797             else if (belt_dir == MV_NO_MOVING && IS_BELT(element))
4798             {
4799               int e_belt_nr = getBeltNrFromElement(element);
4800
4801               if (e_belt_nr == belt_nr)
4802                 DrawLevelField(xx, yy);    /* set belt to parking position */
4803             }
4804           }
4805         }
4806
4807         return MF_ACTION;
4808       }
4809       break;
4810
4811     case EL_SWITCHGATE_SWITCH_1:
4812     case EL_SWITCHGATE_SWITCH_2:
4813       {
4814         int xx, yy;
4815
4816         if (player->Switching)
4817           return MF_ACTION;
4818
4819         player->Switching = TRUE;
4820
4821         game.switchgate_pos = !game.switchgate_pos;
4822
4823         for (yy=0; yy<lev_fieldy; yy++)
4824         {
4825           for (xx=0; xx<lev_fieldx; xx++)
4826           {
4827             int element = Feld[xx][yy];
4828
4829             if (element == EL_SWITCHGATE_SWITCH_1 ||
4830                 element == EL_SWITCHGATE_SWITCH_2)
4831             {
4832               Feld[xx][yy] = EL_SWITCHGATE_SWITCH_1 + game.switchgate_pos;
4833               DrawLevelField(xx, yy);
4834             }
4835             else if (element == EL_SWITCHGATE_OPEN ||
4836                      element == EL_SWITCHGATE_OPENING)
4837             {
4838               Feld[xx][yy] = EL_SWITCHGATE_CLOSING;
4839               PlaySoundLevel(xx, yy, SND_OEFFNEN);
4840             }
4841             else if (element == EL_SWITCHGATE_CLOSED ||
4842                      element == EL_SWITCHGATE_CLOSING)
4843             {
4844               Feld[xx][yy] = EL_SWITCHGATE_OPENING;
4845               PlaySoundLevel(xx, yy, SND_OEFFNEN);
4846             }
4847           }
4848         }
4849
4850         return MF_ACTION;
4851       }
4852       break;
4853
4854     case EL_LIGHT_SWITCH_OFF:
4855     case EL_LIGHT_SWITCH_ON:
4856       {
4857         int xx, yy;
4858
4859         if (player->Switching)
4860           return MF_ACTION;
4861
4862         player->Switching = TRUE;
4863
4864         game.light_time_left =
4865           (element == EL_LIGHT_SWITCH_OFF ? 10 * FRAMES_PER_SECOND : 0);
4866
4867         for (yy=0; yy<lev_fieldy; yy++)
4868         {
4869           for (xx=0; xx<lev_fieldx; xx++)
4870           {
4871             int element = Feld[xx][yy];
4872
4873             if (element == EL_LIGHT_SWITCH_OFF &&
4874                 game.light_time_left > 0)
4875             {
4876               Feld[xx][yy] = EL_LIGHT_SWITCH_ON;
4877               DrawLevelField(xx, yy);
4878             }
4879             else if (element == EL_LIGHT_SWITCH_ON &&
4880                      game.light_time_left == 0)
4881             {
4882               Feld[xx][yy] = EL_LIGHT_SWITCH_OFF;
4883               DrawLevelField(xx, yy);
4884             }
4885
4886             if (element == EL_INVISIBLE_STEEL ||
4887                 element == EL_UNSICHTBAR ||
4888                 element == EL_SAND_INVISIBLE)
4889               DrawLevelField(xx, yy);
4890           }
4891         }
4892
4893         return MF_ACTION;
4894       }
4895       break;
4896
4897     case EL_SP_EXIT:
4898       if (local_player->gems_still_needed > 0)
4899         return MF_NO_ACTION;
4900
4901       player->LevelSolved = player->GameOver = TRUE;
4902       PlaySoundStereo(SND_SP_EXIT, PSND_MAX_RIGHT);
4903       break;
4904
4905     case EL_FELSBROCKEN:
4906     case EL_BOMBE:
4907     case EL_KOKOSNUSS:
4908     case EL_ZEIT_LEER:
4909     case EL_SP_ZONK:
4910     case EL_SP_DISK_ORANGE:
4911       if (dy || mode == DF_SNAP)
4912         return MF_NO_ACTION;
4913
4914       player->Pushing = TRUE;
4915
4916       if (!IN_LEV_FIELD(x+dx, y+dy) || !IS_FREE(x+dx, y+dy))
4917         return MF_NO_ACTION;
4918
4919       if (real_dy)
4920       {
4921         if (IN_LEV_FIELD(jx, jy+real_dy) && !IS_SOLID(Feld[jx][jy+real_dy]))
4922           return MF_NO_ACTION;
4923       }
4924
4925       if (player->push_delay == 0)
4926         player->push_delay = FrameCounter;
4927       if (!FrameReached(&player->push_delay, player->push_delay_value) &&
4928           !tape.playing)
4929         return MF_NO_ACTION;
4930
4931       RemoveField(x, y);
4932       Feld[x+dx][y+dy] = element;
4933
4934       player->push_delay_value = 2+RND(8);
4935
4936       DrawLevelField(x+dx, y+dy);
4937       if (element == EL_FELSBROCKEN)
4938         PlaySoundLevel(x+dx, y+dy, SND_PUSCH);
4939       else if (element == EL_KOKOSNUSS)
4940         PlaySoundLevel(x+dx, y+dy, SND_KNURK);
4941       else if (IS_SP_ELEMENT(element))
4942         PlaySoundLevel(x+dx, y+dy, SND_SP_ZONKPUSH);
4943       else
4944         PlaySoundLevel(x+dx, y+dy, SND_KLOPF);
4945       break;
4946
4947     case EL_PFORTE1:
4948     case EL_PFORTE2:
4949     case EL_PFORTE3:
4950     case EL_PFORTE4:
4951       if (!player->key[element - EL_PFORTE1])
4952         return MF_NO_ACTION;
4953       break;
4954
4955     case EL_PFORTE1X:
4956     case EL_PFORTE2X:
4957     case EL_PFORTE3X:
4958     case EL_PFORTE4X:
4959       if (!player->key[element - EL_PFORTE1X])
4960         return MF_NO_ACTION;
4961       break;
4962
4963     case EL_EM_GATE_1:
4964     case EL_EM_GATE_2:
4965     case EL_EM_GATE_3:
4966     case EL_EM_GATE_4:
4967       if (!player->key[element - EL_EM_GATE_1])
4968         return MF_NO_ACTION;
4969       if (!IN_LEV_FIELD(x + dx, y + dy) || !IS_FREE(x + dx, y + dy))
4970         return MF_NO_ACTION;
4971
4972       /* automatically move to the next field with double speed */
4973       player->programmed_action = move_direction;
4974       DOUBLE_PLAYER_SPEED(player);
4975
4976       PlaySoundLevel(x, y, SND_GATE);
4977
4978       break;
4979
4980     case EL_EM_GATE_1X:
4981     case EL_EM_GATE_2X:
4982     case EL_EM_GATE_3X:
4983     case EL_EM_GATE_4X:
4984       if (!player->key[element - EL_EM_GATE_1X])
4985         return MF_NO_ACTION;
4986       if (!IN_LEV_FIELD(x + dx, y + dy) || !IS_FREE(x + dx, y + dy))
4987         return MF_NO_ACTION;
4988
4989       /* automatically move to the next field with double speed */
4990       player->programmed_action = move_direction;
4991       DOUBLE_PLAYER_SPEED(player);
4992
4993       PlaySoundLevel(x, y, SND_GATE);
4994
4995       break;
4996
4997     case EL_SWITCHGATE_OPEN:
4998       if (!IN_LEV_FIELD(x + dx, y + dy) || !IS_FREE(x + dx, y + dy))
4999         return MF_NO_ACTION;
5000
5001       /* automatically move to the next field with double speed */
5002       player->programmed_action = move_direction;
5003       DOUBLE_PLAYER_SPEED(player);
5004
5005       PlaySoundLevel(x, y, SND_GATE);
5006
5007       break;
5008
5009     case EL_SP_PORT1_LEFT:
5010     case EL_SP_PORT2_LEFT:
5011     case EL_SP_PORT1_RIGHT:
5012     case EL_SP_PORT2_RIGHT:
5013     case EL_SP_PORT1_UP:
5014     case EL_SP_PORT2_UP:
5015     case EL_SP_PORT1_DOWN:
5016     case EL_SP_PORT2_DOWN:
5017     case EL_SP_PORT_X:
5018     case EL_SP_PORT_Y:
5019     case EL_SP_PORT_XY:
5020       if ((dx == -1 &&
5021            element != EL_SP_PORT1_LEFT &&
5022            element != EL_SP_PORT2_LEFT &&
5023            element != EL_SP_PORT_X &&
5024            element != EL_SP_PORT_XY) ||
5025           (dx == +1 &&
5026            element != EL_SP_PORT1_RIGHT &&
5027            element != EL_SP_PORT2_RIGHT &&
5028            element != EL_SP_PORT_X &&
5029            element != EL_SP_PORT_XY) ||
5030           (dy == -1 &&
5031            element != EL_SP_PORT1_UP &&
5032            element != EL_SP_PORT2_UP &&
5033            element != EL_SP_PORT_Y &&
5034            element != EL_SP_PORT_XY) ||
5035           (dy == +1 &&
5036            element != EL_SP_PORT1_DOWN &&
5037            element != EL_SP_PORT2_DOWN &&
5038            element != EL_SP_PORT_Y &&
5039            element != EL_SP_PORT_XY) ||
5040           !IN_LEV_FIELD(x + dx, y + dy) ||
5041           !IS_FREE(x + dx, y + dy))
5042         return MF_NO_ACTION;
5043
5044       /* automatically move to the next field with double speed */
5045       player->programmed_action = move_direction;
5046       DOUBLE_PLAYER_SPEED(player);
5047
5048       PlaySoundLevel(x, y, SND_GATE);
5049
5050       break;
5051
5052     case EL_AUSGANG_ZU:
5053     case EL_AUSGANG_ACT:
5054       /* door is not (yet) open */
5055       return MF_NO_ACTION;
5056       break;
5057
5058     case EL_AUSGANG_AUF:
5059       if (mode == DF_SNAP)
5060         return MF_NO_ACTION;
5061
5062       PlaySoundLevel(x, y, SND_BUING);
5063
5064       break;
5065
5066     case EL_BIRNE_AUS:
5067       Feld[x][y] = EL_BIRNE_EIN;
5068       local_player->lights_still_needed--;
5069       DrawLevelField(x, y);
5070       PlaySoundLevel(x, y, SND_DENG);
5071       return MF_ACTION;
5072       break;
5073
5074     case EL_ZEIT_VOLL:
5075       Feld[x][y] = EL_ZEIT_LEER;
5076       TimeLeft += 10;
5077       DrawText(DX_TIME, DY_TIME, int2str(TimeLeft, 3), FS_SMALL, FC_YELLOW);
5078       DrawLevelField(x, y);
5079       PlaySoundStereo(SND_GONG, PSND_MAX_RIGHT);
5080       return MF_ACTION;
5081       break;
5082
5083     case EL_SOKOBAN_FELD_LEER:
5084       break;
5085
5086     case EL_SOKOBAN_FELD_VOLL:
5087     case EL_SOKOBAN_OBJEKT:
5088     case EL_SONDE:
5089     case EL_SP_DISK_YELLOW:
5090       if (mode == DF_SNAP)
5091         return MF_NO_ACTION;
5092
5093       player->Pushing = TRUE;
5094
5095       if (!IN_LEV_FIELD(x+dx, y+dy)
5096           || (!IS_FREE(x+dx, y+dy)
5097               && (Feld[x+dx][y+dy] != EL_SOKOBAN_FELD_LEER
5098                   || !IS_SB_ELEMENT(element))))
5099         return MF_NO_ACTION;
5100
5101       if (dx && real_dy)
5102       {
5103         if (IN_LEV_FIELD(jx, jy+real_dy) && !IS_SOLID(Feld[jx][jy+real_dy]))
5104           return MF_NO_ACTION;
5105       }
5106       else if (dy && real_dx)
5107       {
5108         if (IN_LEV_FIELD(jx+real_dx, jy) && !IS_SOLID(Feld[jx+real_dx][jy]))
5109           return MF_NO_ACTION;
5110       }
5111
5112       if (player->push_delay == 0)
5113         player->push_delay = FrameCounter;
5114       if (!FrameReached(&player->push_delay, player->push_delay_value) &&
5115           !tape.playing)
5116         return MF_NO_ACTION;
5117
5118       if (IS_SB_ELEMENT(element))
5119       {
5120         if (element == EL_SOKOBAN_FELD_VOLL)
5121         {
5122           Feld[x][y] = EL_SOKOBAN_FELD_LEER;
5123           local_player->sokobanfields_still_needed++;
5124         }
5125         else
5126           RemoveField(x, y);
5127
5128         if (Feld[x+dx][y+dy] == EL_SOKOBAN_FELD_LEER)
5129         {
5130           Feld[x+dx][y+dy] = EL_SOKOBAN_FELD_VOLL;
5131           local_player->sokobanfields_still_needed--;
5132           if (element == EL_SOKOBAN_OBJEKT)
5133             PlaySoundLevel(x, y, SND_DENG);
5134         }
5135         else
5136           Feld[x+dx][y+dy] = EL_SOKOBAN_OBJEKT;
5137       }
5138       else
5139       {
5140         RemoveField(x, y);
5141         Feld[x+dx][y+dy] = element;
5142       }
5143
5144       player->push_delay_value = 2;
5145
5146       DrawLevelField(x, y);
5147       DrawLevelField(x+dx, y+dy);
5148       PlaySoundLevel(x+dx, y+dy, SND_PUSCH);
5149
5150       if (IS_SB_ELEMENT(element) &&
5151           local_player->sokobanfields_still_needed == 0 &&
5152           game.emulation == EMU_SOKOBAN)
5153       {
5154         player->LevelSolved = player->GameOver = TRUE;
5155         PlaySoundLevel(x, y, SND_BUING);
5156       }
5157
5158       break;
5159
5160     case EL_MAULWURF:
5161     case EL_PINGUIN:
5162     case EL_SCHWEIN:
5163     case EL_DRACHE:
5164       break;
5165
5166     default:
5167       return MF_NO_ACTION;
5168   }
5169
5170   player->push_delay = 0;
5171
5172   return MF_MOVING;
5173 }
5174
5175 boolean SnapField(struct PlayerInfo *player, int dx, int dy)
5176 {
5177   int jx = player->jx, jy = player->jy;
5178   int x = jx + dx, y = jy + dy;
5179
5180   if (!player->active || !IN_LEV_FIELD(x, y))
5181     return FALSE;
5182
5183   if (dx && dy)
5184     return FALSE;
5185
5186   if (!dx && !dy)
5187   {
5188     player->snapped = FALSE;
5189     return FALSE;
5190   }
5191
5192   if (player->snapped)
5193     return FALSE;
5194
5195   player->MovDir = (dx < 0 ? MV_LEFT :
5196                     dx > 0 ? MV_RIGHT :
5197                     dy < 0 ? MV_UP :
5198                     dy > 0 ? MV_DOWN :  MV_NO_MOVING);
5199
5200   if (!DigField(player, x, y, 0, 0, DF_SNAP))
5201     return FALSE;
5202
5203   player->snapped = TRUE;
5204   DrawLevelField(x, y);
5205   BackToFront();
5206
5207   return TRUE;
5208 }
5209
5210 boolean PlaceBomb(struct PlayerInfo *player)
5211 {
5212   int jx = player->jx, jy = player->jy;
5213   int element;
5214
5215   if (!player->active || player->MovPos)
5216     return FALSE;
5217
5218   element = Feld[jx][jy];
5219
5220   if ((player->dynamite == 0 && player->dynabombs_left == 0) ||
5221       IS_ACTIVE_BOMB(element) || element == EL_EXPLODING)
5222     return FALSE;
5223
5224   if (element != EL_LEERRAUM)
5225     Store[jx][jy] = element;
5226
5227   if (player->dynamite)
5228   {
5229     Feld[jx][jy] = EL_DYNAMITE_ACTIVE;
5230     MovDelay[jx][jy] = 96;
5231     player->dynamite--;
5232     DrawText(DX_DYNAMITE, DY_DYNAMITE, int2str(local_player->dynamite, 3),
5233              FS_SMALL, FC_YELLOW);
5234     if (IN_SCR_FIELD(SCREENX(jx), SCREENY(jy)))
5235     {
5236       if (game.emulation == EMU_SUPAPLEX)
5237         DrawGraphic(SCREENX(jx), SCREENY(jy), GFX_SP_DISK_RED);
5238       else
5239         DrawGraphicThruMask(SCREENX(jx), SCREENY(jy), GFX_DYNAMIT);
5240     }
5241   }
5242   else
5243   {
5244     Feld[jx][jy] = EL_DYNABOMB_ACTIVE_1 + (player->element_nr - EL_SPIELER1);
5245     MovDelay[jx][jy] = 96;
5246     player->dynabombs_left--;
5247     if (IN_SCR_FIELD(SCREENX(jx), SCREENY(jy)))
5248       DrawGraphicThruMask(SCREENX(jx), SCREENY(jy), GFX_DYNABOMB);
5249   }
5250
5251   return TRUE;
5252 }
5253
5254 void PlaySoundLevel(int x, int y, int sound_nr)
5255 {
5256   int sx = SCREENX(x), sy = SCREENY(y);
5257   int volume, stereo;
5258   int silence_distance = 8;
5259
5260   if ((!setup.sound_simple && !IS_LOOP_SOUND(sound_nr)) ||
5261       (!setup.sound_loops && IS_LOOP_SOUND(sound_nr)))
5262     return;
5263
5264   if (!IN_LEV_FIELD(x, y) ||
5265       sx < -silence_distance || sx >= SCR_FIELDX+silence_distance ||
5266       sy < -silence_distance || sy >= SCR_FIELDY+silence_distance)
5267     return;
5268
5269   volume = PSND_MAX_VOLUME;
5270
5271 #ifndef MSDOS
5272   stereo = (sx - SCR_FIELDX/2) * 12;
5273 #else
5274   stereo = PSND_MIDDLE + (2 * sx - (SCR_FIELDX - 1)) * 5;
5275   if (stereo > PSND_MAX_RIGHT)
5276     stereo = PSND_MAX_RIGHT;
5277   if (stereo < PSND_MAX_LEFT)
5278     stereo = PSND_MAX_LEFT;
5279 #endif
5280
5281   if (!IN_SCR_FIELD(sx, sy))
5282   {
5283     int dx = ABS(sx - SCR_FIELDX/2) - SCR_FIELDX/2;
5284     int dy = ABS(sy - SCR_FIELDY/2) - SCR_FIELDY/2;
5285
5286     volume -= volume * (dx > dy ? dx : dy) / silence_distance;
5287   }
5288
5289   PlaySoundExt(sound_nr, volume, stereo, PSND_NO_LOOP);
5290 }
5291
5292 void RaiseScore(int value)
5293 {
5294   local_player->score += value;
5295   DrawText(DX_SCORE, DY_SCORE, int2str(local_player->score, 5),
5296            FS_SMALL, FC_YELLOW);
5297 }
5298
5299 void RaiseScoreElement(int element)
5300 {
5301   switch(element)
5302   {
5303     case EL_EDELSTEIN:
5304     case EL_EDELSTEIN_BD:
5305     case EL_EDELSTEIN_GELB:
5306     case EL_EDELSTEIN_ROT:
5307     case EL_EDELSTEIN_LILA:
5308       RaiseScore(level.score[SC_EDELSTEIN]);
5309       break;
5310     case EL_DIAMANT:
5311       RaiseScore(level.score[SC_DIAMANT]);
5312       break;
5313     case EL_KAEFER:
5314     case EL_BUTTERFLY:
5315       RaiseScore(level.score[SC_KAEFER]);
5316       break;
5317     case EL_FLIEGER:
5318     case EL_FIREFLY:
5319       RaiseScore(level.score[SC_FLIEGER]);
5320       break;
5321     case EL_MAMPFER:
5322     case EL_MAMPFER2:
5323       RaiseScore(level.score[SC_MAMPFER]);
5324       break;
5325     case EL_ROBOT:
5326       RaiseScore(level.score[SC_ROBOT]);
5327       break;
5328     case EL_PACMAN:
5329       RaiseScore(level.score[SC_PACMAN]);
5330       break;
5331     case EL_KOKOSNUSS:
5332       RaiseScore(level.score[SC_KOKOSNUSS]);
5333       break;
5334     case EL_DYNAMITE_INACTIVE:
5335       RaiseScore(level.score[SC_DYNAMIT]);
5336       break;
5337     case EL_SCHLUESSEL:
5338       RaiseScore(level.score[SC_SCHLUESSEL]);
5339       break;
5340     default:
5341       break;
5342   }
5343 }
5344
5345 /* ---------- new game button stuff ---------------------------------------- */
5346
5347 /* graphic position values for game buttons */
5348 #define GAME_BUTTON_XSIZE       30
5349 #define GAME_BUTTON_YSIZE       30
5350 #define GAME_BUTTON_XPOS        5
5351 #define GAME_BUTTON_YPOS        215
5352 #define SOUND_BUTTON_XPOS       5
5353 #define SOUND_BUTTON_YPOS       (GAME_BUTTON_YPOS + GAME_BUTTON_YSIZE)
5354
5355 #define GAME_BUTTON_STOP_XPOS   (GAME_BUTTON_XPOS + 0 * GAME_BUTTON_XSIZE)
5356 #define GAME_BUTTON_PAUSE_XPOS  (GAME_BUTTON_XPOS + 1 * GAME_BUTTON_XSIZE)
5357 #define GAME_BUTTON_PLAY_XPOS   (GAME_BUTTON_XPOS + 2 * GAME_BUTTON_XSIZE)
5358 #define SOUND_BUTTON_MUSIC_XPOS (SOUND_BUTTON_XPOS + 0 * GAME_BUTTON_XSIZE)
5359 #define SOUND_BUTTON_LOOPS_XPOS (SOUND_BUTTON_XPOS + 1 * GAME_BUTTON_XSIZE)
5360 #define SOUND_BUTTON_SIMPLE_XPOS (SOUND_BUTTON_XPOS + 2 * GAME_BUTTON_XSIZE)
5361
5362 static struct
5363 {
5364   int x, y;
5365   int gadget_id;
5366   char *infotext;
5367 } gamebutton_info[NUM_GAME_BUTTONS] =
5368 {
5369   {
5370     GAME_BUTTON_STOP_XPOS,      GAME_BUTTON_YPOS,
5371     GAME_CTRL_ID_STOP,
5372     "stop game"
5373   },
5374   {
5375     GAME_BUTTON_PAUSE_XPOS,     GAME_BUTTON_YPOS,
5376     GAME_CTRL_ID_PAUSE,
5377     "pause game"
5378   },
5379   {
5380     GAME_BUTTON_PLAY_XPOS,      GAME_BUTTON_YPOS,
5381     GAME_CTRL_ID_PLAY,
5382     "play game"
5383   },
5384   {
5385     SOUND_BUTTON_MUSIC_XPOS,    SOUND_BUTTON_YPOS,
5386     SOUND_CTRL_ID_MUSIC,
5387     "background music on/off"
5388   },
5389   {
5390     SOUND_BUTTON_LOOPS_XPOS,    SOUND_BUTTON_YPOS,
5391     SOUND_CTRL_ID_LOOPS,
5392     "sound loops on/off"
5393   },
5394   {
5395     SOUND_BUTTON_SIMPLE_XPOS,   SOUND_BUTTON_YPOS,
5396     SOUND_CTRL_ID_SIMPLE,
5397     "normal sounds on/off"
5398   }
5399 };
5400
5401 void CreateGameButtons()
5402 {
5403   int i;
5404
5405   for (i=0; i<NUM_GAME_BUTTONS; i++)
5406   {
5407     Pixmap gd_pixmap = pix[PIX_DOOR];
5408     struct GadgetInfo *gi;
5409     int button_type;
5410     boolean checked;
5411     unsigned long event_mask;
5412     int gd_xoffset, gd_yoffset;
5413     int gd_x1, gd_x2, gd_y1, gd_y2;
5414     int id = i;
5415
5416     gd_xoffset = gamebutton_info[i].x;
5417     gd_yoffset = gamebutton_info[i].y;
5418     gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
5419     gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
5420
5421     if (id == GAME_CTRL_ID_STOP ||
5422         id == GAME_CTRL_ID_PAUSE ||
5423         id == GAME_CTRL_ID_PLAY)
5424     {
5425       button_type = GD_TYPE_NORMAL_BUTTON;
5426       checked = FALSE;
5427       event_mask = GD_EVENT_RELEASED;
5428       gd_y1  = DOOR_GFX_PAGEY1 + gd_yoffset - GAME_BUTTON_YSIZE;
5429       gd_y2  = DOOR_GFX_PAGEY1 + gd_yoffset - GAME_BUTTON_YSIZE;
5430     }
5431     else
5432     {
5433       button_type = GD_TYPE_CHECK_BUTTON;
5434       checked =
5435         ((id == SOUND_CTRL_ID_MUSIC && setup.sound_music) ||
5436          (id == SOUND_CTRL_ID_LOOPS && setup.sound_loops) ||
5437          (id == SOUND_CTRL_ID_SIMPLE && setup.sound_simple) ? TRUE : FALSE);
5438       event_mask = GD_EVENT_PRESSED;
5439       gd_y1  = DOOR_GFX_PAGEY1 + gd_yoffset;
5440       gd_y2  = DOOR_GFX_PAGEY1 + gd_yoffset - GAME_BUTTON_YSIZE;
5441     }
5442
5443     gi = CreateGadget(GDI_CUSTOM_ID, id,
5444                       GDI_INFO_TEXT, gamebutton_info[i].infotext,
5445                       GDI_X, DX + gd_xoffset,
5446                       GDI_Y, DY + gd_yoffset,
5447                       GDI_WIDTH, GAME_BUTTON_XSIZE,
5448                       GDI_HEIGHT, GAME_BUTTON_YSIZE,
5449                       GDI_TYPE, button_type,
5450                       GDI_STATE, GD_BUTTON_UNPRESSED,
5451                       GDI_CHECKED, checked,
5452                       GDI_DESIGN_UNPRESSED, gd_pixmap, gd_x1, gd_y1,
5453                       GDI_DESIGN_PRESSED, gd_pixmap, gd_x2, gd_y1,
5454                       GDI_ALT_DESIGN_UNPRESSED, gd_pixmap, gd_x1, gd_y2,
5455                       GDI_ALT_DESIGN_PRESSED, gd_pixmap, gd_x2, gd_y2,
5456                       GDI_EVENT_MASK, event_mask,
5457                       GDI_CALLBACK_ACTION, HandleGameButtons,
5458                       GDI_END);
5459
5460     if (gi == NULL)
5461       Error(ERR_EXIT, "cannot create gadget");
5462
5463     game_gadget[id] = gi;
5464   }
5465 }
5466
5467 static void MapGameButtons()
5468 {
5469   int i;
5470
5471   for (i=0; i<NUM_GAME_BUTTONS; i++)
5472     MapGadget(game_gadget[i]);
5473 }
5474
5475 void UnmapGameButtons()
5476 {
5477   int i;
5478
5479   for (i=0; i<NUM_GAME_BUTTONS; i++)
5480     UnmapGadget(game_gadget[i]);
5481 }
5482
5483 static void HandleGameButtons(struct GadgetInfo *gi)
5484 {
5485   int id = gi->custom_id;
5486
5487   if (game_status != PLAYING)
5488     return;
5489
5490   switch (id)
5491   {
5492     case GAME_CTRL_ID_STOP:
5493       if (AllPlayersGone)
5494       {
5495         CloseDoor(DOOR_CLOSE_1);
5496         game_status = MAINMENU;
5497         DrawMainMenu();
5498         break;
5499       }
5500
5501       if (level_editor_test_game ||
5502           Request("Do you really want to quit the game ?",
5503                   REQ_ASK | REQ_STAY_CLOSED))
5504       { 
5505 #ifndef MSDOS
5506         if (options.network)
5507           SendToServer_StopPlaying();
5508         else
5509 #endif
5510         {
5511           game_status = MAINMENU;
5512           DrawMainMenu();
5513         }
5514       }
5515       else
5516         OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
5517       break;
5518
5519     case GAME_CTRL_ID_PAUSE:
5520       if (options.network)
5521       {
5522 #ifndef MSDOS
5523         if (tape.pausing)
5524           SendToServer_ContinuePlaying();
5525         else
5526           SendToServer_PausePlaying();
5527 #endif
5528       }
5529       else
5530         TapeTogglePause();
5531       break;
5532
5533     case GAME_CTRL_ID_PLAY:
5534       if (tape.pausing)
5535       {
5536 #ifndef MSDOS
5537         if (options.network)
5538           SendToServer_ContinuePlaying();
5539         else
5540 #endif
5541         {
5542           tape.pausing = FALSE;
5543           DrawVideoDisplay(VIDEO_STATE_PAUSE_OFF,0);
5544         }
5545       }
5546       break;
5547
5548     case SOUND_CTRL_ID_MUSIC:
5549       if (setup.sound_music)
5550       { 
5551         setup.sound_music = FALSE;
5552         FadeSound(background_loop[level_nr % num_bg_loops]);
5553       }
5554       else if (sound_loops_allowed)
5555       { 
5556         setup.sound = setup.sound_music = TRUE;
5557         PlaySoundLoop(background_loop[level_nr % num_bg_loops]);
5558       }
5559       break;
5560
5561     case SOUND_CTRL_ID_LOOPS:
5562       if (setup.sound_loops)
5563         setup.sound_loops = FALSE;
5564       else if (sound_loops_allowed)
5565         setup.sound = setup.sound_loops = TRUE;
5566       break;
5567
5568     case SOUND_CTRL_ID_SIMPLE:
5569       if (setup.sound_simple)
5570         setup.sound_simple = FALSE;
5571       else if (sound_status==SOUND_AVAILABLE)
5572         setup.sound = setup.sound_simple = TRUE;
5573       break;
5574
5575     default:
5576       break;
5577   }
5578 }