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