fixed code to compile with current gcc and 64-bit systems
[rocksndiamonds.git] / src / game.c
1 /***********************************************************
2 *  Rocks'n'Diamonds -- McDuffin Strikes Back!              *
3 *----------------------------------------------------------*
4 *  ©1995 Artsoft Development                               *
5 *        Holger Schemel                                    *
6 *        33659 Bielefeld-Senne                             *
7 *        Telefon: (0521) 493245                            *
8 *        eMail: aeglos@valinor.owl.de                      *
9 *               aeglos@uni-paderborn.de                    *
10 *               q99492@pbhrzx.uni-paderborn.de             *
11 *----------------------------------------------------------*
12 *  game.c                                                  *
13 *                                                          *
14 *  Letzte Aenderung: 15.06.1995                            *
15 ***********************************************************/
16
17 #include "game.h"
18 #include "misc.h"
19 #include "tools.h"
20 #include "screens.h"
21 #include "sound.h"
22 #include "init.h"
23
24 BOOL CreateNewScoreFile()
25 {
26   int i,j,k;
27   char filename[MAX_FILENAME];
28   char empty_alias[MAX_NAMELEN];
29   FILE *file;
30
31   sprintf(filename,"%s/%s/%s",
32           SCORE_PATH,leveldir[leveldir_nr].filename,SCORE_FILENAME);
33
34   if (!(file=fopen(filename,"w")))
35     return(FALSE);
36
37   for(i=0;i<MAX_NAMELEN;i++)
38     empty_alias[i] = 0;
39   strncpy(empty_alias,EMPTY_ALIAS,MAX_NAMELEN-1);
40
41   fputs(SCORE_COOKIE,file);             /* Formatkennung */
42   for(i=0;i<LEVELDIR_SIZE(leveldir[leveldir_nr]);i++)
43   {
44     for(j=0;j<MAX_SCORE_ENTRIES;j++)
45     {
46       for(k=0;k<MAX_NAMELEN;k++)
47         fputc(empty_alias[k],file);
48       fputc(0,file);
49       fputc(0,file);
50     }
51   }
52   fclose(file);
53
54   chmod(filename, SCORE_PERMS);
55   return(TRUE);
56 }
57
58 BOOL CreateNewNamesFile(int mode)
59 {
60   char filename[MAX_FILENAME];
61   FILE *file;
62
63   if (mode==PLAYER_LEVEL)
64     sprintf(filename,"%s/%s/%s",
65             NAMES_PATH,leveldir[leveldir_nr].filename,NAMES_FILENAME);
66   else
67     sprintf(filename,"%s/%s",CONFIG_PATH,NAMES_FILENAME);
68
69   if (!(file=fopen(filename,"w")))
70     return(FALSE);
71
72   fputs(NAMES_COOKIE,file);             /* Formatkennung */
73   fclose(file);
74
75   chmod(filename, NAMES_PERMS);
76   return(TRUE);
77 }
78
79 void LoadLevelInfo()
80 {
81   int i;
82   char filename[MAX_FILENAME];
83   char cookie[MAX_FILENAME];
84   FILE *file;
85   int ignored;
86
87   sprintf(filename,"%s/%s",LEVEL_PATH,LEVDIR_FILENAME);
88
89   if (!(file=fopen(filename,"r")))
90   {
91     fprintf(stderr,"%s: cannot load level info '%s'!\n",progname,filename);
92     CloseAll();
93   }
94
95   ignored = fscanf(file,"%s\n",cookie);
96   if (strcmp(cookie,LEVELDIR_COOKIE))   /* ungültiges Format? */
97   {
98     fprintf(stderr,"%s: wrong format of level info file!\n",progname);
99     fclose(file);
100     CloseAll();
101   }
102
103   num_leveldirs = 0;
104   leveldir_nr = 0;
105   for(i=0;i<MAX_LEVDIR_ENTRIES;i++)
106   {
107     ignored = fscanf(file,"%s",leveldir[i].filename);
108     ignored = fscanf(file,"%s",leveldir[i].name);
109     ignored = fscanf(file,"%d",&leveldir[i].num_ready);
110     ignored = fscanf(file,"%d",&leveldir[i].num_free);
111     if (feof(file))
112       break;
113
114     num_leveldirs++;
115   }
116
117   if (!num_leveldirs)
118   {
119     fprintf(stderr,"%s: empty level info '%s'!\n",progname,filename);
120     CloseAll();
121   }
122 }
123
124 void LoadLevel(int level_nr)
125 {
126   int i,x,y;
127   char filename[MAX_FILENAME];
128   char cookie[MAX_FILENAME];
129   FILE *file;
130   char *ignored;
131
132   sprintf(filename,"%s/%s/%d",
133           LEVEL_PATH,leveldir[leveldir_nr].filename,level_nr);
134
135   if (!(file=fopen(filename,"r")))
136   {
137 /*
138     fprintf(stderr,"%s: cannot load level '%s'!\n",progname,filename);
139 */
140   }
141   else
142   {
143     ignored = fgets(cookie,LEVEL_COOKIE_LEN,file);
144     fgetc(file);
145     if (strcmp(cookie,LEVEL_COOKIE))    /* ungültiges Format? */
146     {
147       fprintf(stderr,"%s: wrong format of level file '%s'!\n",
148               progname,filename);
149       fclose(file);
150       file = NULL;
151     }
152   }
153
154   if (file)
155   {
156     lev_fieldx = level.fieldx = fgetc(file);
157     lev_fieldy = level.fieldy = fgetc(file);
158
159     level.time          = (fgetc(file)<<8) | fgetc(file);
160     level.edelsteine    = (fgetc(file)<<8) | fgetc(file);
161     for(i=0;i<MAX_LEVNAMLEN;i++)
162       level.name[i]     = fgetc(file);
163     for(i=0;i<MAX_SC_ENTRIES;i++)
164       level.score[i]    = fgetc(file);
165     for(i=0;i<4;i++)
166       for(y=0;y<3;y++)
167         for(x=0;x<3;x++)
168           level.mampfer_inhalt[i][x][y] = fgetc(file);
169     level.tempo_amoebe  = fgetc(file);
170     level.dauer_sieb    = fgetc(file);
171     level.dauer_ablenk  = fgetc(file);
172
173     for(i=0;i<19;i++)   /* Rest reserviert / Headergröße 80 Bytes */
174       fgetc(file);
175
176     for(y=0;y<lev_fieldy;y++) 
177       for(x=0;x<lev_fieldx;x++) 
178         Feld[x][y] = Ur[x][y] = fgetc(file);
179
180     fclose(file);
181
182     if (level.time<=10) /* Mindestspieldauer */
183       level.time = 10;
184   }
185   else
186   {
187     lev_fieldx = level.fieldx = STD_LEV_FIELDX;
188     lev_fieldy = level.fieldy = STD_LEV_FIELDY;
189
190     level.time          = 100;
191     level.edelsteine    = 0;
192     strncpy(level.name,"Nameless Level",MAX_LEVNAMLEN-1);
193     for(i=0;i<MAX_SC_ENTRIES;i++)
194       level.score[i]    = 10;
195     for(i=0;i<4;i++)
196       for(y=0;y<3;y++)
197         for(x=0;x<3;x++)
198           level.mampfer_inhalt[i][x][y] = EL_FELSBROCKEN;
199     level.tempo_amoebe  = 10;
200     level.dauer_sieb    = 10;
201     level.dauer_ablenk  = 10;
202
203     for(y=0;y<STD_LEV_FIELDY;y++) 
204       for(x=0;x<STD_LEV_FIELDX;x++) 
205         Feld[x][y] = Ur[x][y] = EL_ERDREICH;
206     Feld[0][0] = Ur[0][0] = EL_SPIELFIGUR;
207     Feld[STD_LEV_FIELDX-1][STD_LEV_FIELDY-1] =
208       Ur[STD_LEV_FIELDX-1][STD_LEV_FIELDY-1] = EL_AUSGANG_ZU;
209   }
210 }
211
212 void LoadLevelTape(int level_nr)
213 {
214   int i;
215   char filename[MAX_FILENAME];
216   char cookie[MAX_FILENAME];
217   FILE *file;
218   char *ignored;
219
220   sprintf(filename,"%s/%s/%d.tape",
221           LEVEL_PATH,leveldir[leveldir_nr].filename,level_nr);
222
223   if ((file=fopen(filename,"r")))
224   {
225     ignored = fgets(cookie,LEVELREC_COOKIE_LEN,file);
226     fgetc(file);
227     if (strcmp(cookie,LEVELREC_COOKIE)) /* ungültiges Format? */
228     {
229       fprintf(stderr,"%s: wrong format of level recording file '%s'!\n",
230               progname,filename);
231       fclose(file);
232       file = NULL;
233     }
234   }
235
236   if (!file)
237     return;
238
239   tape.random_seed =
240     (fgetc(file)<<24) | (fgetc(file)<<16) | (fgetc(file)<<8) | fgetc(file);
241   tape.date =
242     (fgetc(file)<<24) | (fgetc(file)<<16) | (fgetc(file)<<8) | fgetc(file);
243   tape.length =
244     (fgetc(file)<<24) | (fgetc(file)<<16) | (fgetc(file)<<8) | fgetc(file);
245
246   tape.level_nr = level_nr;
247   tape.counter = 0;
248   tape.recording = FALSE;
249   tape.playing = FALSE;
250   tape.pausing = FALSE;
251
252   for(i=0;i<tape.length;i++)
253   {
254     if (i>=MAX_TAPELEN)
255       break;
256     tape.pos[i].joystickdata = fgetc(file);
257     tape.pos[i].delay        = fgetc(file);
258     if (feof(file))
259       break;
260   }
261
262   if (i != tape.length)
263     fprintf(stderr,"%s: level recording file '%s' corrupted!\n",
264             progname,filename);
265
266   fclose(file);
267
268   master_tape = tape;
269 }
270
271 void LoadScore(int level_nr)
272 {
273   int i,j;
274   char filename[MAX_FILENAME];
275   char cookie[MAX_FILENAME];
276   FILE *file;
277   char *ignored;
278
279   sprintf(filename,"%s/%s/%s",
280           SCORE_PATH,leveldir[leveldir_nr].filename,SCORE_FILENAME);
281
282   if (!(file=fopen(filename,"r")))
283   {
284     if (!CreateNewScoreFile())
285     {
286       fprintf(stderr,"%s: cannot create score file '%s'!\n",
287               progname,filename);
288     }
289     else if (!(file=fopen(filename,"r"))) 
290     {
291       fprintf(stderr,"%s: cannot load score for level %d!\n",
292               progname,level_nr);
293     }
294   }
295
296   if (file)
297   {
298     ignored = fgets(cookie,SCORE_COOKIE_LEN,file);
299     if (strcmp(cookie,SCORE_COOKIE))    /* ungültiges Format? */
300     {
301       fprintf(stderr,"%s: wrong format of score file!\n",progname);
302       fclose(file);
303       file = NULL;
304     }
305   }
306
307   if (file)
308   {
309     fseek(file,
310           SCORE_COOKIE_LEN-1+level_nr*(MAX_SCORE_ENTRIES*(MAX_NAMELEN+2)),
311           SEEK_SET);
312     for(i=0;i<MAX_SCORE_ENTRIES;i++)
313     {
314       for(j=0;j<MAX_NAMELEN;j++)
315         highscore[i].Name[j] = fgetc(file);
316       highscore[i].Score = (fgetc(file)<<8) | fgetc(file);
317     }
318     fclose(file);
319   }
320   else
321   {
322     for(i=0;i<MAX_SCORE_ENTRIES;i++)
323     {
324       strcpy(highscore[i].Name,EMPTY_ALIAS);
325       highscore[i].Score = 0;
326     }
327   }
328 }
329
330 void LoadPlayerInfo(int mode)
331 {
332   int i;
333   char filename[MAX_FILENAME];
334   char cookie[MAX_FILENAME];
335   FILE *file;
336   char *login_name = GetLoginName();
337   struct PlayerInfo default_player, new_player;
338   char *ignored;
339
340   if (mode==PLAYER_LEVEL)
341     sprintf(filename,"%s/%s/%s",
342             NAMES_PATH,leveldir[leveldir_nr].filename,NAMES_FILENAME);
343   else
344     sprintf(filename,"%s/%s",CONFIG_PATH,NAMES_FILENAME);
345
346   for(i=0;i<MAX_NAMELEN;i++)
347     default_player.login_name[i] = default_player.alias_name[i] = 0;
348   strncpy(default_player.login_name,login_name,MAX_NAMELEN-1);
349   strncpy(default_player.alias_name,login_name,MAX_NAMELEN-1);
350   default_player.handicap = 0;
351   default_player.setup = DEFAULT_SETUP;
352   default_player.leveldir_nr = 0;
353
354   new_player = default_player;
355
356   if (!(file=fopen(filename,"r")))
357   {
358     if (!CreateNewNamesFile(mode))
359     {
360       fprintf(stderr,"%s: cannot create names file '%s'!\n",
361               progname,filename);
362     }
363     else if (!(file=fopen(filename,"r"))) 
364     {
365       fprintf(stderr,"%s: cannot load player information '%s'!\n",
366               progname,filename);
367     }
368   }
369
370   if (file)
371   {
372     ignored = fgets(cookie,NAMES_COOKIE_LEN,file);
373     if (strcmp(cookie,NAMES_COOKIE))    /* ungültiges Format? */
374     {
375       fprintf(stderr,"%s: wrong format of names file '%s'!\n",
376               progname,filename);
377       fclose(file);
378       file = NULL;
379     }
380   }
381
382   if (!file)
383   {
384     player = default_player;
385     level_nr = default_player.handicap;
386     return;
387   }
388
389   while(1)
390   {
391     for(i=0;i<MAX_NAMELEN;i++)
392       new_player.login_name[i] = fgetc(file);
393     for(i=0;i<MAX_NAMELEN;i++)
394       new_player.alias_name[i] = fgetc(file);
395     new_player.handicap = fgetc(file);
396     new_player.setup = (fgetc(file)<<8) | fgetc(file);
397     new_player.leveldir_nr = fgetc(file);
398
399     if (feof(file))             /* Spieler noch nicht in Liste enthalten */
400     {
401       new_player = default_player;
402
403       fclose(file);
404       if (!(file=fopen(filename,"a")))
405       {
406         fprintf(stderr,"%s: cannot append new player to names file '%s'!\n",
407                 progname,filename);
408       }
409       else
410       {
411         for(i=0;i<MAX_NAMELEN;i++)
412           fputc(new_player.login_name[i],file);
413         for(i=0;i<MAX_NAMELEN;i++)
414           fputc(new_player.alias_name[i],file);
415         fputc(new_player.handicap,file);
416         fputc(new_player.setup / 256,file);
417         fputc(new_player.setup % 256,file);
418         fputc(new_player.leveldir_nr,file);
419       }
420       break;
421     }
422     else                        /* prüfen, ob Spieler in Liste enthalten */
423       if (!strncmp(new_player.login_name,login_name,MAX_NAMELEN-1))
424         break;
425   }
426
427   if (mode==PLAYER_SETUP)
428   {
429     player = new_player;
430     if (player.leveldir_nr < num_leveldirs)
431       leveldir_nr = player.leveldir_nr;
432     else
433       leveldir_nr = 0;
434   }
435   else
436     player.handicap = new_player.handicap;
437
438   level_nr = player.handicap;
439   fclose(file);
440 }
441
442 void SaveLevel(int level_nr)
443 {
444   int i,x,y;
445   char filename[MAX_FILENAME];
446   FILE *file;
447
448   sprintf(filename,"%s/%s/%d",
449           LEVEL_PATH,leveldir[leveldir_nr].filename,level_nr);
450
451   if (!(file=fopen(filename,"w")))
452   {
453     fprintf(stderr,"%s: cannot save level file '%s'!\n",progname,filename);
454     return;
455   }
456
457   fputs(LEVEL_COOKIE,file);             /* Formatkennung */
458   fputc(0x0a,file);
459
460   fputc(level.fieldx,file);
461   fputc(level.fieldy,file);
462   fputc(level.time / 256,file);
463   fputc(level.time % 256,file);
464   fputc(level.edelsteine / 256,file);
465   fputc(level.edelsteine % 256,file);
466
467   for(i=0;i<MAX_LEVNAMLEN;i++)
468     fputc(level.name[i],file);
469   for(i=0;i<MAX_SC_ENTRIES;i++)
470     fputc(level.score[i],file);
471   for(i=0;i<4;i++)
472     for(y=0;y<3;y++)
473       for(x=0;x<3;x++)
474         fputc(level.mampfer_inhalt[i][x][y],file);
475   fputc(level.tempo_amoebe,file);
476   fputc(level.dauer_sieb,file);
477   fputc(level.dauer_ablenk,file);
478
479   for(i=0;i<19;i++)     /* Rest reserviert / Headergröße 80 Bytes */
480     fputc(0,file);
481
482   for(y=0;y<lev_fieldy;y++) 
483     for(x=0;x<lev_fieldx;x++) 
484       fputc(Ur[x][y],file);
485
486   fclose(file);
487
488   chmod(filename, LEVEL_PERMS);
489 }
490
491 void SaveLevelTape(int level_nr)
492 {
493   int i;
494   char filename[MAX_FILENAME];
495   FILE *file;
496   BOOL new_tape = TRUE;
497
498   sprintf(filename,"%s/%s/%d.tape",
499           LEVEL_PATH,leveldir[leveldir_nr].filename,level_nr);
500
501   /* Testen, ob bereits eine Aufnahme existiert */
502   if ((file=fopen(filename,"r")))
503   {
504     new_tape = FALSE;
505     fclose(file);
506
507     if (!AreYouSure("Replace old tape ?",AYS_ASK))
508       return;
509   }
510
511   if (!(file=fopen(filename,"w")))
512   {
513     fprintf(stderr,"%s: cannot save level recording file '%s'!\n",
514             progname,filename);
515     return;
516   }
517
518   fputs(LEVELREC_COOKIE,file);          /* Formatkennung */
519   fputc(0x0a,file);
520
521   tape = master_tape;
522
523   fputc((tape.random_seed >> 24) & 0xff,file);
524   fputc((tape.random_seed >> 16) & 0xff,file);
525   fputc((tape.random_seed >>  8) & 0xff,file);
526   fputc((tape.random_seed >>  0) & 0xff,file);
527
528   fputc((tape.date >>  24) & 0xff,file);
529   fputc((tape.date >>  16) & 0xff,file);
530   fputc((tape.date >>   8) & 0xff,file);
531   fputc((tape.date >>   0) & 0xff,file);
532
533   fputc((tape.length >>  24) & 0xff,file);
534   fputc((tape.length >>  16) & 0xff,file);
535   fputc((tape.length >>   8) & 0xff,file);
536   fputc((tape.length >>   0) & 0xff,file);
537
538   for(i=0;i<tape.length;i++)
539   {
540     fputc(tape.pos[i].joystickdata,file);
541     fputc(tape.pos[i].delay,file);
542   }
543
544   fclose(file);
545
546   chmod(filename, LEVREC_PERMS);
547
548   if (new_tape)
549     AreYouSure("tape saved !",AYS_CONFIRM);
550 }
551
552 void SaveScore(int level_nr)
553 {
554   int i,j;
555   char filename[MAX_FILENAME];
556   FILE *file;
557
558   sprintf(filename,"%s/%s/%s",
559           SCORE_PATH,leveldir[leveldir_nr].filename,SCORE_FILENAME);
560
561   if (!(file=fopen(filename,"r+")))
562   {
563     fprintf(stderr,"%s: cannot save score for level %d!\n",
564             progname,level_nr);
565     return;
566   }
567
568   fseek(file,
569         SCORE_COOKIE_LEN-1+level_nr*(MAX_SCORE_ENTRIES*(MAX_NAMELEN+2)),
570         SEEK_SET);
571   for(i=0;i<MAX_SCORE_ENTRIES;i++)
572   {
573     for(j=0;j<MAX_NAMELEN;j++)
574       fputc(highscore[i].Name[j],file);
575     fputc(highscore[i].Score / 256,file);
576     fputc(highscore[i].Score % 256,file);
577   }
578   fclose(file);
579 }
580
581 void SavePlayerInfo(int mode)
582 {
583   int i;
584   char filename[MAX_FILENAME];
585   char cookie[MAX_FILENAME];
586   FILE *file;
587   struct PlayerInfo default_player;
588   char *ignored;
589
590   if (mode==PLAYER_LEVEL)
591     sprintf(filename,"%s/%s/%s",
592             NAMES_PATH,leveldir[leveldir_nr].filename,NAMES_FILENAME);
593   else
594     sprintf(filename,"%s/%s",CONFIG_PATH,NAMES_FILENAME);
595
596   if (!(file=fopen(filename,"r+")))
597   {
598     fprintf(stderr,"%s: cannot save player information '%s'!\n",
599             progname,filename);
600     return;
601   }
602
603   ignored = fgets(cookie,NAMES_COOKIE_LEN,file);
604   if (strcmp(cookie,NAMES_COOKIE))      /* ungültiges Format? */
605   {
606     fprintf(stderr,"%s: wrong format of names file '%s'!\n",
607             progname,filename);
608     fclose(file);
609     return;
610   }
611
612   while(1)
613   {
614     for(i=0;i<MAX_NAMELEN;i++)
615       default_player.login_name[i] = fgetc(file);
616     for(i=0;i<MAX_NAMELEN;i++)
617       default_player.alias_name[i] = fgetc(file);
618     default_player.handicap = fgetc(file);
619     default_player.setup = (fgetc(file)<<8) | fgetc(file);
620     default_player.leveldir_nr = fgetc(file);
621
622     if (feof(file))             /* Spieler noch nicht in Liste enthalten */
623       break;
624     else                        /* prüfen, ob Spieler in Liste enthalten */
625       if (!strncmp(default_player.login_name,player.login_name,MAX_NAMELEN-1))
626       {
627         fseek(file,-(2*MAX_NAMELEN+1+2+1),SEEK_CUR);
628         break;
629       }
630   }
631
632   for(i=0;i<MAX_NAMELEN;i++)
633     fputc(player.login_name[i],file);
634   for(i=0;i<MAX_NAMELEN;i++)
635     fputc(player.alias_name[i],file);
636   fputc(player.handicap,file);
637   fputc(player.setup / 256,file);
638   fputc(player.setup % 256,file);
639   fputc(player.leveldir_nr,file);
640
641   fclose(file);
642 }
643
644 void GetPlayerConfig()
645 {
646   int old_joystick_nr = joystick_nr;
647
648   if (sound_status==SOUND_OFF)
649     player.setup &= ~SETUP_SOUND;
650   if (!sound_loops_allowed)
651   {
652     player.setup &= ~SETUP_SOUND_LOOPS;
653     player.setup &= ~SETUP_SOUND_MUSIC;
654   }
655
656   sound_on = SETUP_SOUND_ON(player.setup);
657   sound_loops_on = SETUP_SOUND_LOOPS_ON(player.setup);
658   sound_music_on = SETUP_SOUND_MUSIC_ON(player.setup);
659   toons_on = SETUP_TOONS_ON(player.setup);
660   direct_draw_on = SETUP_DIRECT_DRAW_ON(player.setup);
661   fading_on = SETUP_FADING_ON(player.setup);
662   autorecord_on = SETUP_RECORD_EACH_GAME_ON(player.setup);
663   joystick_nr = SETUP_2ND_JOYSTICK_ON(player.setup);
664
665   if (joystick_nr != old_joystick_nr)
666   {
667     if (joystick_device)
668       close(joystick_device);
669     InitJoystick();
670   }
671 }
672
673 void InitGame()
674 {
675   int x,y;
676
677   Dynamite = Score = 0;
678   Gems = level.edelsteine;
679   Key[0] = Key[1] = Key[2] = Key[3] = FALSE;
680   MampferNr = 0;
681   TimeLeft = level.time;
682   CheckMoving = TRUE;
683   CheckExploding = FALSE;
684   LevelSolved = GameOver = SiebAktiv = FALSE;
685   JX = JY = 0;
686   ZX = ZY = -1;
687
688   if (tape.recording)
689     TapeStartRecording();
690   else if (tape.playing)
691     TapeStartPlaying();
692
693   DigField(0,0,DF_NO_PUSH);
694   SnapField(0,0);
695
696   for(y=0;y<lev_fieldy;y++) for(x=0;x<lev_fieldx;x++)
697   {
698     Feld[x][y]=Ur[x][y];
699     MovPos[x][y]=MovDir[x][y]=MovDelay[x][y]=0;
700     Store[x][y]=Store2[x][y]=Frame[x][y]=0;
701
702     switch(Feld[x][y])
703     {
704       case EL_SPIELFIGUR:
705       case EL_SPIELER1:
706         Feld[x][y] = EL_LEERRAUM;
707         JX = x;
708         JY = y;
709         break;
710       case EL_SPIELER2:
711         Feld[x][y] = EL_LEERRAUM;
712         break;
713       case EL_BADEWANNE:
714         if (x<lev_fieldx-1 && Feld[x+1][y]==EL_SALZSAEURE)
715           Feld[x][y] = EL_BADEWANNE1;
716         else if (x>0 && Feld[x-1][y]==EL_SALZSAEURE)
717           Feld[x][y] = EL_BADEWANNE2;
718         else if (y>0 && Feld[x][y-1]==EL_BADEWANNE1)
719           Feld[x][y] = EL_BADEWANNE3;
720         else if (y>0 && Feld[x][y-1]==EL_SALZSAEURE)
721           Feld[x][y] = EL_BADEWANNE4;
722         else if (y>0 && Feld[x][y-1]==EL_BADEWANNE2)
723           Feld[x][y] = EL_BADEWANNE5;
724         break;
725       case EL_KAEFER_R:
726       case EL_KAEFER_O:
727       case EL_KAEFER_L:
728       case EL_KAEFER_U:
729       case EL_KAEFER:
730       case EL_FLIEGER_R:
731       case EL_FLIEGER_O:
732       case EL_FLIEGER_L:
733       case EL_FLIEGER_U:
734       case EL_FLIEGER:
735       case EL_PACMAN_R:
736       case EL_PACMAN_O:
737       case EL_PACMAN_L:
738       case EL_PACMAN_U:
739       case EL_MAMPFER:
740       case EL_ZOMBIE:
741       case EL_PACMAN:
742         InitMovDir(x,y);
743         break;
744       default:
745         break;
746     }
747   }
748
749   scroll_x = scroll_y = -1;
750   if (JX>=MIDPOSX-1)
751     scroll_x =
752       (JX<=lev_fieldx-MIDPOSX ? JX-MIDPOSX : lev_fieldx-SCR_FIELDX+1);
753   if (JY>=MIDPOSY-1)
754     scroll_y =
755       (JY<=lev_fieldy-MIDPOSY ? JY-MIDPOSY : lev_fieldy-SCR_FIELDY+1);
756
757   DrawLevel();
758   DrawLevelElement(JX,JY,EL_SPIELFIGUR);
759   FadeToFront();
760
761   XCopyArea(display,pix[PIX_DOOR],pix[PIX_DB_DOOR],gc,
762             DOOR_GFX_PAGEX5,DOOR_GFX_PAGEY1, DXSIZE,DYSIZE,
763             DOOR_GFX_PAGEX1,DOOR_GFX_PAGEY1);
764   DrawTextExt(pix[PIX_DB_DOOR],gc,
765               DOOR_GFX_PAGEX1+XX_LEVEL,DOOR_GFX_PAGEY1+YY_LEVEL,
766               int2str(level_nr,2),FS_SMALL,FC_YELLOW);
767   DrawTextExt(pix[PIX_DB_DOOR],gc,
768               DOOR_GFX_PAGEX1+XX_EMERALDS,DOOR_GFX_PAGEY1+YY_EMERALDS,
769               int2str(Gems,3),FS_SMALL,FC_YELLOW);
770   DrawTextExt(pix[PIX_DB_DOOR],gc,
771               DOOR_GFX_PAGEX1+XX_DYNAMITE,DOOR_GFX_PAGEY1+YY_DYNAMITE,
772               int2str(Dynamite,3),FS_SMALL,FC_YELLOW);
773   DrawTextExt(pix[PIX_DB_DOOR],gc,
774               DOOR_GFX_PAGEX1+XX_SCORE,DOOR_GFX_PAGEY1+YY_SCORE,
775               int2str(Score,5),FS_SMALL,FC_YELLOW);
776   DrawTextExt(pix[PIX_DB_DOOR],gc,
777               DOOR_GFX_PAGEX1+XX_TIME,DOOR_GFX_PAGEY1+YY_TIME,
778               int2str(TimeLeft,3),FS_SMALL,FC_YELLOW);
779
780   DrawGameButton(BUTTON_GAME_STOP);
781   DrawGameButton(BUTTON_GAME_PAUSE);
782   DrawGameButton(BUTTON_GAME_PLAY);
783   DrawSoundDisplay(BUTTON_SOUND_MUSIC | (BUTTON_ON * sound_music_on));
784   DrawSoundDisplay(BUTTON_SOUND_LOOPS | (BUTTON_ON * sound_loops_on));
785   DrawSoundDisplay(BUTTON_SOUND_SOUND | (BUTTON_ON * sound_on));
786   XCopyArea(display,drawto,pix[PIX_DB_DOOR],gc,
787             DX+GAME_CONTROL_XPOS,DY+GAME_CONTROL_YPOS,
788             GAME_CONTROL_XSIZE,2*GAME_CONTROL_YSIZE,
789             DOOR_GFX_PAGEX1+GAME_CONTROL_XPOS,
790             DOOR_GFX_PAGEY1+GAME_CONTROL_YPOS);
791
792   OpenDoor(DOOR_OPEN_1);
793
794   if (sound_music_on)
795     PlaySoundLoop(background_loop[level_nr % num_bg_loops]);
796
797   XAutoRepeatOff(display);
798 }
799
800 void InitMovDir(int x, int y)
801 {
802   int i, element = Feld[x][y];
803   static int xy[4][2] =
804   {
805     0,+1,
806     +1,0,
807     0,-1,
808     -1,0
809   };
810   static int direction[2][4] =
811   {
812     MV_RIGHT, MV_UP,   MV_LEFT,  MV_DOWN,
813     MV_LEFT,  MV_DOWN, MV_RIGHT, MV_UP
814   };
815
816   switch(element)
817   {
818     case EL_KAEFER_R:
819     case EL_KAEFER_O:
820     case EL_KAEFER_L:
821     case EL_KAEFER_U:
822       Feld[x][y] = EL_KAEFER;
823       MovDir[x][y] = direction[0][element-EL_KAEFER_R];
824       break;
825     case EL_FLIEGER_R:
826     case EL_FLIEGER_O:
827     case EL_FLIEGER_L:
828     case EL_FLIEGER_U:
829       Feld[x][y] = EL_FLIEGER;
830       MovDir[x][y] = direction[0][element-EL_FLIEGER_R];
831       break;
832     case EL_PACMAN_R:
833     case EL_PACMAN_O:
834     case EL_PACMAN_L:
835     case EL_PACMAN_U:
836       Feld[x][y] = EL_PACMAN;
837       MovDir[x][y] = direction[0][element-EL_PACMAN_R];
838       break;
839     default:
840       MovDir[x][y] = 1<<RND(4);
841       if (element!=EL_KAEFER && element!=EL_FLIEGER)
842         break;
843
844       for(i=0;i<4;i++)
845       {
846         int x1,y1;
847
848         x1 = x+xy[i][0];
849         y1 = y+xy[i][1];
850
851         if (!IN_LEV_FIELD(x1,y1) || !IS_FREE(x1,y1))
852         {
853           if (element==EL_KAEFER)
854           {
855             MovDir[x][y] = direction[0][i];
856             break;
857           }
858           else if (element==EL_FLIEGER)
859           {
860             MovDir[x][y] = direction[1][i];
861             break;
862           }
863         }
864       }
865       break;
866   }
867 }
868
869 void GameWon()
870 {
871   int hi_pos;
872   int bumplevel = FALSE;
873
874   if (sound_loops_on)
875     PlaySoundExt(SND_SIRR,PSND_MAX_VOLUME,PSND_MAX_RIGHT,PSND_LOOP);
876
877   if (TimeLeft>0) 
878   {
879     for(;TimeLeft>=0;TimeLeft--)
880     {
881       if (!sound_loops_on)
882         PlaySoundStereo(SND_SIRR,PSND_MAX_RIGHT);
883       if (TimeLeft && !(TimeLeft % 10))
884         RaiseScore(level.score[SC_ZEITBONUS]);
885       DrawText(DX_TIME,DY_TIME,int2str(TimeLeft,3),FS_SMALL,FC_YELLOW);
886       BackToFront();
887       Delay(10000);
888     }
889   }
890
891   if (sound_loops_on)
892     StopSound(SND_SIRR);
893   FadeSounds();
894
895   if (tape.playing)
896     return;
897
898   CloseDoor(DOOR_CLOSE_1);
899
900   if (level_nr==player.handicap &&
901       level_nr<leveldir[leveldir_nr].num_ready) 
902   { 
903     player.handicap++; 
904     bumplevel = TRUE;
905     SavePlayerInfo(PLAYER_LEVEL);
906   }
907
908   if ((hi_pos=NewHiScore())>=0) 
909   {
910     game_status = HALLOFFAME;
911     DrawHallOfFame(hi_pos);
912     if (bumplevel && TAPE_IS_EMPTY(tape))
913       level_nr++;
914   }
915   else
916   {
917     game_status = MAINMENU;
918     if (bumplevel && TAPE_IS_EMPTY(tape))
919       level_nr++;
920     DrawMainMenu();
921   }
922   BackToFront();
923 }
924
925 BOOL NewHiScore()
926 {
927   int k,l;
928   int position = -1;
929
930   LoadScore(level_nr);
931
932   if (!strcmp(player.alias_name,EMPTY_ALIAS) ||
933       Score<highscore[MAX_SCORE_ENTRIES-1].Score) 
934     return(-1);
935
936   for(k=0;k<MAX_SCORE_ENTRIES;k++) 
937   {
938     if (Score>highscore[k].Score)       /* Spieler kommt in Highscore-Liste */
939     {
940       if (k<MAX_SCORE_ENTRIES-1)
941       {
942         int m = MAX_SCORE_ENTRIES-1;
943
944 #ifdef ONE_PER_NAME
945         for(l=k;l<MAX_SCORE_ENTRIES;l++)
946           if (!strcmp(player.alias_name,highscore[l].Name))
947             m = l;
948         if (m==k)       /* Spieler überschreibt seine alte Position */
949           goto put_into_list;
950 #endif
951
952         for(l=m;l>k;l--)
953         {
954           strcpy(highscore[l].Name,highscore[l-1].Name);
955           highscore[l].Score = highscore[l-1].Score;
956         }
957       }
958
959 #ifdef ONE_PER_NAME
960       put_into_list:
961 #endif
962       sprintf(highscore[k].Name,"%s",player.alias_name);
963       highscore[k].Score = Score; 
964       position = k;
965       break;
966     }
967   }
968
969 #ifdef ONE_PER_NAME
970   else if (!strcmp(player.alias_name,highscore[k].Name))
971     break;      /* Spieler schon mit besserer Punktzahl in der Liste */
972 #endif
973
974   if (position>=0) 
975     SaveScore(level_nr);
976
977   return(position);
978 }
979
980 void InitMovingField(int x, int y, int direction)
981 {
982   int newx = x + (direction==MV_LEFT ? -1 : direction==MV_RIGHT ? +1 : 0);
983   int newy = y + (direction==MV_UP   ? -1 : direction==MV_DOWN  ? +1 : 0);
984
985   CheckMoving = TRUE;
986   MovDir[x][y] = direction;
987   MovDir[newx][newy] = direction;
988   if (Feld[newx][newy]==EL_LEERRAUM)
989     Feld[newx][newy] = EL_BLOCKED;
990 }
991
992 void Moving2Blocked(int x, int y, int *goes_to_x, int *goes_to_y)
993 {
994   int direction = MovDir[x][y];
995   int newx = x + (direction==MV_LEFT ? -1 : direction==MV_RIGHT ? +1 : 0);
996   int newy = y + (direction==MV_UP   ? -1 : direction==MV_DOWN  ? +1 : 0);
997
998   *goes_to_x = newx;
999   *goes_to_y = newy;
1000 }
1001
1002 void Blocked2Moving(int x, int y, int *comes_from_x, int *comes_from_y)
1003 {
1004   int oldx = x, oldy = y;
1005   int direction = MovDir[x][y];
1006
1007   if (direction==MV_LEFT)
1008     oldx++;
1009   else if (direction==MV_RIGHT)
1010     oldx--;
1011   else if (direction==MV_UP)
1012     oldy++;
1013   else if (direction==MV_DOWN)
1014     oldy--;
1015
1016   *comes_from_x = oldx;
1017   *comes_from_y = oldy;
1018 }
1019
1020 int MovingOrBlocked2Element(int x, int y)
1021 {
1022   int element = Feld[x][y];
1023
1024   if (element==EL_BLOCKED)
1025   {
1026     int oldx,oldy;
1027
1028     Blocked2Moving(x,y,&oldx,&oldy);
1029     return(Feld[oldx][oldy]);
1030   }
1031   else
1032     return(element);
1033 }
1034
1035 void RemoveMovingField(int x, int y)
1036 {
1037   int oldx=x,oldy=y, newx=x,newy=y;
1038
1039   if (Feld[x][y]!=EL_BLOCKED && !IS_MOVING(x,y))
1040     return;
1041
1042   if (IS_MOVING(x,y))
1043   {
1044     Moving2Blocked(x,y,&newx,&newy);
1045     if (Feld[newx][newy]!=EL_BLOCKED)
1046       return;
1047   }
1048   else if (Feld[x][y]==EL_BLOCKED)
1049   {
1050     Blocked2Moving(x,y,&oldx,&oldy);
1051     if (!IS_MOVING(oldx,oldy))
1052       return;
1053   }
1054
1055   Feld[oldx][oldy] = EL_LEERRAUM;
1056   Feld[newx][newy] = EL_LEERRAUM;
1057   MovPos[oldx][oldy] = MovDir[oldx][oldy] = MovDelay[oldx][oldy] = 0;
1058   MovPos[newx][newy] = MovDir[newx][newy] = MovDelay[newx][newy] = 0;
1059   DrawLevelField(oldx,oldy);
1060   DrawLevelField(newx,newy);
1061 }
1062
1063 void DrawDynamite(int x, int y)
1064 {
1065   int phase = (48-MovDelay[x][y])/6;
1066
1067   if (!IN_SCR_FIELD(SCROLLX(x),SCROLLY(y)))
1068     return;
1069
1070   if (phase>6)
1071     phase = 6;
1072
1073   if (Store[x][y])
1074   {
1075     DrawGraphic(SCROLLX(x),SCROLLY(y),el2gfx(Store[x][y]));
1076     if (PLAYER(x,y))
1077       DrawGraphicThruMask(SCROLLX(JX),SCROLLY(JY),GFX_SPIELFIGUR);
1078   }
1079   else if (PLAYER(x,y))
1080     DrawGraphic(SCROLLX(JX),SCROLLY(JY),GFX_SPIELFIGUR);
1081
1082   if (Store[x][y] || PLAYER(x,y))
1083     DrawGraphicThruMask(SCROLLX(x),SCROLLY(y),GFX_DYNAMIT+phase);
1084   else
1085     DrawGraphic(SCROLLX(x),SCROLLY(y),GFX_DYNAMIT+phase);
1086 }
1087
1088 void CheckDynamite(int x, int y)
1089 {
1090   CheckExploding=TRUE;
1091
1092   if (MovDelay[x][y])           /* neues Dynamit / in Wartezustand */
1093   {
1094     MovDelay[x][y]--;
1095     if (MovDelay[x][y])
1096     {
1097       if (!(MovDelay[x][y] % 6))
1098       {
1099         DrawDynamite(x,y);
1100         PlaySoundLevel(x,y,SND_ZISCH);
1101       }
1102
1103       return;
1104     }
1105   }
1106
1107   StopSound(SND_ZISCH);
1108   Bang(x,y);
1109 }
1110
1111 void Explode(int ex, int ey, int phase)
1112 {
1113   int x,y;
1114   int num_phase = 9, delay = 1;
1115   int last_phase = num_phase*delay;
1116   int half_phase = (num_phase/2)*delay;
1117
1118   if (phase==0)                 /* Feld 'Store' initialisieren */
1119   {
1120     int center_element = Feld[ex][ey];
1121
1122     if (center_element==EL_BLOCKED)
1123       center_element = MovingOrBlocked2Element(ex,ey);
1124
1125     for(y=ey-1;y<ey+2;y++) for(x=ex-1;x<ex+2;x++)
1126     {
1127       int element = Feld[x][y];
1128
1129       if (!IN_LEV_FIELD(x,y) || IS_MASSIV(element))
1130         continue;
1131
1132       if (element==EL_EXPLODING)
1133         element = Store2[x][y];
1134
1135       if (PLAYER(ex,ey) || center_element==EL_KAEFER)
1136         Store[x][y] = ((x==ex && y==ey) ? EL_DIAMANT : EL_EDELSTEIN);
1137       else if (center_element==EL_MAMPFER)
1138         Store[x][y] = level.mampfer_inhalt[MampferNr][x-ex+1][y-ey+1];
1139       else if (Feld[x][y]==EL_ERZ_1)
1140         Store[x][y] = EL_EDELSTEIN;
1141       else if (Feld[x][y]==EL_ERZ_2)
1142         Store[x][y] = EL_DIAMANT;
1143       else if (!IS_PFORTE(Store[x][y]))
1144         Store[x][y] = EL_LEERRAUM;
1145
1146       if (x!=ex || y!=ey)
1147         Store2[x][y] = element;
1148
1149       RemoveMovingField(x,y);
1150       Feld[x][y] = EL_EXPLODING;
1151       MovDir[x][y] = MovPos[x][y] = 0;
1152       Frame[x][y] = 1;
1153       Stop[x][y] = TRUE;
1154     }
1155
1156     if (center_element==EL_MAMPFER)
1157       MampferNr = (MampferNr+1) % 4;
1158
1159     return;
1160   }
1161
1162   if (Stop[ex][ey])
1163     return;
1164
1165   x = ex;
1166   y = ey;
1167
1168   Frame[x][y] = (phase<last_phase ? phase+1 : 0);
1169
1170   if (phase==half_phase)
1171   {
1172     int element = Store2[x][y];
1173
1174     if (PLAYER(x,y))
1175       KillHero();
1176     else if (element==EL_BOMBE ||
1177              element==EL_DYNAMIT ||
1178              element==EL_DYNAMIT_AUS ||
1179              element==EL_KAEFER)
1180     {
1181       Feld[x][y] = Store2[x][y];
1182       Store2[x][y] = 0;
1183       Bang(x,y);
1184     }
1185   }
1186
1187   if (phase==last_phase)
1188   {
1189     int element;
1190
1191     element = Feld[x][y] = Store[x][y];
1192     Store[x][y] = Store2[x][y] = 0;
1193     MovDir[x][y] = MovPos[x][y] = MovDelay[x][y] = 0;
1194     if (CAN_MOVE(element) || COULD_MOVE(element))
1195       InitMovDir(x,y);
1196     DrawLevelField(x,y);
1197   }
1198   else if (!(phase%delay) && IN_SCR_FIELD(SCROLLX(x),SCROLLY(y)))
1199   {
1200     if (phase==delay)
1201       ErdreichAnbroeckeln(SCROLLX(x),SCROLLY(y));
1202
1203     DrawGraphic(SCROLLX(x),SCROLLY(y),GFX_EXPLOSION+(phase/delay-1));
1204   }
1205
1206   CheckExploding=TRUE;
1207 }
1208
1209 void Bang(int x, int y)
1210 {
1211   int element = Feld[x][y];
1212
1213   CheckExploding=TRUE;
1214   PlaySoundLevel(x,y,SND_ROAAAR);
1215
1216   switch(element)
1217   {
1218     case EL_KAEFER:
1219       RaiseScore(level.score[SC_KAEFER]);
1220       break;
1221     case EL_FLIEGER:
1222       RaiseScore(level.score[SC_FLIEGER]);
1223       break;
1224     case EL_MAMPFER:
1225       RaiseScore(level.score[SC_MAMPFER]);
1226       break;
1227     case EL_ZOMBIE:
1228       RaiseScore(level.score[SC_ZOMBIE]);
1229       break;
1230     case EL_PACMAN:
1231       RaiseScore(level.score[SC_PACMAN]);
1232       break;
1233     default:
1234       break;
1235   }
1236
1237   Explode(x,y,0);
1238 }
1239
1240 void Blurb(int x, int y)
1241 {
1242   int element = Feld[x][y];
1243
1244   if (element!=EL_BLURB_LEFT && element!=EL_BLURB_RIGHT) /* Anfang */
1245   {
1246     PlaySoundLevel(x,y,SND_BLURB);
1247     if (IN_LEV_FIELD(x-1,y) && IS_FREE(x-1,y) &&
1248         (!IN_LEV_FIELD(x-1,y-1) ||
1249          !CAN_FALL(MovingOrBlocked2Element(x-1,y-1))))
1250     {
1251       Feld[x-1][y] = EL_BLURB_LEFT;
1252     }
1253     if (IN_LEV_FIELD(x+1,y) && IS_FREE(x+1,y) &&
1254         (!IN_LEV_FIELD(x+1,y-1) ||
1255          !CAN_FALL(MovingOrBlocked2Element(x+1,y-1))))
1256     {
1257       Feld[x+1][y] = EL_BLURB_RIGHT;
1258     }
1259   }
1260   else                                                   /* Blubbern */
1261   {
1262     int graphic = (element==EL_BLURB_LEFT ? GFX_BLURB_LEFT : GFX_BLURB_RIGHT);
1263
1264     CheckExploding=TRUE;
1265
1266     if (!MovDelay[x][y])        /* neue Phase / noch nicht gewartet */
1267       MovDelay[x][y] = 5;
1268
1269     if (MovDelay[x][y])         /* neue Phase / in Wartezustand */
1270     {
1271       MovDelay[x][y]--;
1272       if (MovDelay[x][y] && IN_SCR_FIELD(SCROLLX(x),SCROLLY(y)))
1273         DrawGraphic(SCROLLX(x),SCROLLY(y),graphic+4-MovDelay[x][y]);
1274
1275       if (!MovDelay[x][y])
1276       {
1277         Feld[x][y] = EL_LEERRAUM;
1278         DrawLevelField(x,y);
1279       }
1280     }
1281   }
1282 }
1283
1284 void Impact(int x, int y)
1285 {
1286   BOOL lastline = (y==lev_fieldy-1);
1287   BOOL object_hit = FALSE;
1288   int element = Feld[x][y];
1289
1290   /* Element darunter berührt? */
1291   if (!lastline)
1292     object_hit = (!IS_FREE(x,y+1) && (!IS_MOVING(x,y+1) ||
1293                                       MovDir[x][y+1]!=MV_DOWN ||
1294                                       MovPos[x][y+1]<=TILEY/2));
1295
1296   /* Auftreffendes Element fällt in Salzsäure */
1297   if (!lastline && Feld[x][y+1]==EL_SALZSAEURE)
1298   {
1299     Blurb(x,y);
1300     return;
1301   }
1302
1303   /* Auftreffendes Element ist Bombe */
1304   if (element==EL_BOMBE && (lastline || object_hit))
1305   {
1306     Bang(x,y);
1307     return;
1308   }
1309
1310   /* Auftreffendes Element ist Säuretropfen */
1311   if (element==EL_TROPFEN && (lastline || object_hit))
1312   {
1313     if (object_hit && PLAYER(x,y+1))
1314       KillHero();
1315     else
1316       Feld[x][y] = EL_AMOEBING2;
1317     return;
1318   }
1319
1320   /* Welches Element kriegt was auf die Rübe? */
1321   if (!lastline && object_hit)
1322   {
1323     int smashed = Feld[x][y+1];
1324
1325     if (PLAYER(x,y+1))
1326     {
1327       KillHero();
1328       return;
1329     }
1330     else if (element==EL_FELSBROCKEN)
1331     {
1332       if (IS_ENEMY(MovingOrBlocked2Element(x,y+1)))
1333       {
1334         Bang(x,y+1);
1335         return;
1336       }
1337       else if (!IS_MOVING(x,y+1))
1338       {
1339         if (smashed==EL_BOMBE)
1340         {
1341           Bang(x,y+1);
1342           return;
1343         }
1344         else if (smashed==EL_KOKOSNUSS)
1345         {
1346           Feld[x][y+1] = EL_CRACKINGNUT;
1347           PlaySoundLevel(x,y,SND_KNACK);
1348           RaiseScore(level.score[SC_KOKOSNUSS]);
1349           return;
1350         }
1351         else if (smashed==EL_DIAMANT)
1352         {
1353           Feld[x][y+1] = EL_LEERRAUM;
1354           PlaySoundLevel(x,y,SND_QUIRK);
1355           return;
1356         }
1357       }
1358     }
1359   }
1360
1361   /* Kein Geräusch beim Durchqueren des Siebes */
1362   if (!lastline && Feld[x][y+1]==EL_SIEB_LEER)
1363     return;
1364
1365   /* Geräusch beim Auftreffen */
1366   if (lastline || object_hit)
1367   {
1368     int sound;
1369
1370     switch(element)
1371     {
1372       case EL_EDELSTEIN:
1373       case EL_DIAMANT:
1374         sound = SND_PLING;
1375         break;
1376       case EL_KOKOSNUSS:
1377         sound = SND_KLUMPF;
1378         break;
1379       case EL_FELSBROCKEN:
1380         sound = SND_KLOPF;
1381         break;
1382       case EL_SCHLUESSEL:
1383       case EL_SCHLUESSEL1:
1384       case EL_SCHLUESSEL2:
1385       case EL_SCHLUESSEL3:
1386       case EL_SCHLUESSEL4:
1387         sound = SND_KINK;
1388         break;
1389       default:
1390         sound = -1;
1391         break;
1392     }
1393
1394     if (sound>=0)
1395       PlaySoundLevel(x,y,sound);
1396   }
1397 }
1398
1399 void TurnRound(int x, int y)
1400 {
1401   int element = Feld[x][y];
1402   int direction = MovDir[x][y];
1403
1404   if (element==EL_KAEFER)
1405   {
1406     TestIfBadThingHitsOtherBadThing(x,y);
1407
1408     if (MovDir[x][y]==MV_LEFT)
1409     {
1410       if (IN_LEV_FIELD(x,y-1) && IS_FREE(x,y-1))
1411         MovDir[x][y]=MV_UP;
1412       else if (!IN_LEV_FIELD(x-1,y) || !IS_FREE(x-1,y))
1413         MovDir[x][y]=MV_DOWN;
1414     }
1415     else if (MovDir[x][y]==MV_RIGHT)
1416     {
1417       if (IN_LEV_FIELD(x,y+1) && IS_FREE(x,y+1))
1418         MovDir[x][y]=MV_DOWN;
1419       else if (!IN_LEV_FIELD(x+1,y) || !IS_FREE(x+1,y))
1420         MovDir[x][y]=MV_UP;
1421     }
1422     else if (MovDir[x][y]==MV_UP)
1423     {
1424       if (IN_LEV_FIELD(x+1,y) && IS_FREE(x+1,y))
1425         MovDir[x][y]=MV_RIGHT;
1426       else if (!IN_LEV_FIELD(x,y-1) || !IS_FREE(x,y-1))
1427         MovDir[x][y]=MV_LEFT;
1428     }
1429     else if (MovDir[x][y]==MV_DOWN)
1430     {
1431       if (IN_LEV_FIELD(x-1,y) && IS_FREE(x-1,y))
1432         MovDir[x][y]=MV_LEFT;
1433       else if (!IN_LEV_FIELD(x,y+1) || !IS_FREE(x,y+1))
1434         MovDir[x][y]=MV_RIGHT;
1435     }
1436
1437     if (direction!=MovDir[x][y])
1438       MovDelay[x][y]=5;
1439   }
1440   else if (element==EL_FLIEGER)
1441   {
1442     TestIfBadThingHitsOtherBadThing(x,y);
1443
1444     if (MovDir[x][y]==MV_LEFT)
1445     {
1446       if (IN_LEV_FIELD(x,y+1) && IS_FREE(x,y+1))
1447         MovDir[x][y]=MV_DOWN;
1448       else if (!IN_LEV_FIELD(x-1,y) || !IS_FREE(x-1,y))
1449         MovDir[x][y]=MV_UP;
1450     }
1451     else if (MovDir[x][y]==MV_RIGHT)
1452     {
1453       if (IN_LEV_FIELD(x,y-1) && IS_FREE(x,y-1))
1454         MovDir[x][y]=MV_UP;
1455       else if (!IN_LEV_FIELD(x+1,y) || !IS_FREE(x+1,y))
1456         MovDir[x][y]=MV_DOWN;
1457     }
1458     else if (MovDir[x][y]==MV_UP)
1459     {
1460       if (IN_LEV_FIELD(x-1,y) && IS_FREE(x-1,y))
1461         MovDir[x][y]=MV_LEFT;
1462       else if (!IN_LEV_FIELD(x,y-1) || !IS_FREE(x,y-1))
1463         MovDir[x][y]=MV_RIGHT;
1464     }
1465     else if (MovDir[x][y]==MV_DOWN)
1466     {
1467       if (IN_LEV_FIELD(x+1,y) && IS_FREE(x+1,y))
1468         MovDir[x][y]=MV_RIGHT;
1469       else if (!IN_LEV_FIELD(x,y+1) || !IS_FREE(x,y+1))
1470         MovDir[x][y]=MV_LEFT;
1471     }
1472
1473     if (direction!=MovDir[x][y])
1474       MovDelay[x][y]=5;
1475   }
1476   else if (element==EL_MAMPFER)
1477   {
1478     if (MovDir[x][y]==MV_LEFT || MovDir[x][y]==MV_RIGHT)
1479     {
1480       MovDir[x][y]=(MovDir[x][y]==MV_LEFT ? MV_RIGHT : MV_LEFT);
1481       if (IN_LEV_FIELD(x,y-1) &&
1482           (IS_FREE(x,y-1) || Feld[x][y-1]==EL_DIAMANT) &&
1483           RND(2))
1484         MovDir[x][y]=MV_UP;
1485       if (IN_LEV_FIELD(x,y+1) &&
1486           (IS_FREE(x,y+1) || Feld[x][y+1]==EL_DIAMANT) &&
1487           RND(2))
1488         MovDir[x][y]=MV_DOWN;
1489     }
1490     else if (MovDir[x][y]==MV_UP || MovDir[x][y]==MV_DOWN)
1491     {
1492       MovDir[x][y]=(MovDir[x][y]==MV_UP ? MV_DOWN : MV_UP);
1493       if (IN_LEV_FIELD(x-1,y) &&
1494           (IS_FREE(x-1,y) || Feld[x-1][y]==EL_DIAMANT) &&
1495           RND(2))
1496         MovDir[x][y]=MV_LEFT;
1497       if (IN_LEV_FIELD(x+1,y) &&
1498           (IS_FREE(x+1,y) || Feld[x+1][y]==EL_DIAMANT) &&
1499           RND(2))
1500         MovDir[x][y]=MV_RIGHT;
1501     }
1502
1503     MovDelay[x][y]=8+8*RND(3);
1504   }
1505   else if (element==EL_PACMAN)
1506   {
1507     if (MovDir[x][y]==MV_LEFT || MovDir[x][y]==MV_RIGHT)
1508     {
1509       MovDir[x][y]=(MovDir[x][y]==MV_LEFT ? MV_RIGHT : MV_LEFT);
1510       if (IN_LEV_FIELD(x,y-1) &&
1511           (IS_FREE(x,y-1) || IS_AMOEBOID(Feld[x][y-1])) &&
1512           RND(2))
1513         MovDir[x][y]=MV_UP;
1514       if (IN_LEV_FIELD(x,y+1) &&
1515           (IS_FREE(x,y+1) || IS_AMOEBOID(Feld[x][y+1])) &&
1516           RND(2))
1517         MovDir[x][y]=MV_DOWN;
1518     }
1519     else if (MovDir[x][y]==MV_UP || MovDir[x][y]==MV_DOWN)
1520     {
1521       MovDir[x][y]=(MovDir[x][y]==MV_UP ? MV_DOWN : MV_UP);
1522       if (IN_LEV_FIELD(x-1,y) &&
1523           (IS_FREE(x-1,y) || IS_AMOEBOID(Feld[x-1][y])) &&
1524           RND(2))
1525         MovDir[x][y]=MV_LEFT;
1526       if (IN_LEV_FIELD(x+1,y) &&
1527           (IS_FREE(x+1,y) || IS_AMOEBOID(Feld[x+1][y])) &&
1528           RND(2))
1529         MovDir[x][y]=MV_RIGHT;
1530     }
1531
1532     MovDelay[x][y]=3+RND(20);
1533   }
1534   else if (element==EL_ZOMBIE)
1535   {
1536     int attr_x = JX, attr_y = JY;
1537
1538     if (ZX>=0 && ZY>=0)
1539     {
1540       attr_x = ZX;
1541       attr_y = ZY;
1542     }
1543
1544     MovDir[x][y]=MV_NO_MOVING;
1545     if (attr_x<x)
1546       MovDir[x][y]|=MV_LEFT;
1547     else if (attr_x>x)
1548       MovDir[x][y]|=MV_RIGHT;
1549     if (attr_y<y)
1550       MovDir[x][y]|=MV_UP;
1551     else if (attr_y>y)
1552       MovDir[x][y]|=MV_DOWN;
1553     if ((MovDir[x][y]&(MV_LEFT|MV_RIGHT)) && (MovDir[x][y]&(MV_UP|MV_DOWN)))
1554       MovDir[x][y] &= (RND(2) ? (MV_LEFT|MV_RIGHT) : (MV_UP|MV_DOWN));
1555
1556     MovDelay[x][y] = 8+8*RND(2);
1557   }
1558 }
1559
1560 void StartMoving(int x, int y)
1561 {
1562   int element = Feld[x][y];
1563
1564   if (Stop[x][y])
1565     return;
1566
1567   if (CAN_FALL(element) && y<lev_fieldy-1)
1568   {
1569     if (element==EL_MORAST_VOLL)
1570     {
1571       if (IS_FREE(x,y+1))
1572       {
1573         InitMovingField(x,y,MV_DOWN);
1574         Feld[x][y] = EL_FELSBROCKEN;
1575         Store[x][y] = EL_MORAST_LEER;
1576       }
1577       else if (Feld[x][y+1]==EL_MORAST_LEER)
1578       {
1579         CheckMoving=TRUE;
1580
1581         if (!MovDelay[x][y])
1582           MovDelay[x][y] = 16;
1583
1584         if (MovDelay[x][y])
1585         {
1586           MovDelay[x][y]--;
1587           if (MovDelay[x][y])
1588             return;
1589         }
1590
1591         Feld[x][y] = EL_MORAST_LEER;
1592         Feld[x][y+1] = EL_MORAST_VOLL;
1593       }
1594     }
1595     else if (element==EL_FELSBROCKEN && Feld[x][y+1]==EL_MORAST_LEER)
1596     {
1597       InitMovingField(x,y,MV_DOWN);
1598       Store[x][y] = EL_MORAST_VOLL;
1599     }
1600     else if (element==EL_SIEB_VOLL)
1601     {
1602       if (IS_FREE(x,y+1))
1603       {
1604         InitMovingField(x,y,MV_DOWN);
1605         Feld[x][y] = EL_CHANGED(Store2[x][y]);
1606         Store[x][y] = EL_SIEB_LEER;
1607       }
1608     }
1609     else if (CAN_CHANGE(element) && Feld[x][y+1]==EL_SIEB_LEER)
1610     {
1611       InitMovingField(x,y,MV_DOWN);
1612       Store[x][y] = EL_SIEB_VOLL;
1613       Store2[x][y+1] = element;
1614       SiebAktiv = 330;
1615     }
1616     else if (CAN_SMASH(element) && Feld[x][y+1]==EL_SALZSAEURE)
1617     {
1618       Blurb(x,y);
1619       InitMovingField(x,y,MV_DOWN);
1620       Store[x][y] = EL_SALZSAEURE;
1621     }
1622     else if (CAN_SMASH(element) && Feld[x][y+1]==EL_BLOCKED)
1623     {
1624       Impact(x,y);
1625     }
1626     else if (IS_FREE(x,y+1))
1627     {
1628       InitMovingField(x,y,MV_DOWN);
1629     }
1630     else if (element==EL_TROPFEN)
1631     {
1632       Feld[x][y] = EL_AMOEBING2;
1633     }
1634     else if (SLIPPERY(Feld[x][y+1]) && !Store[x][y+1])
1635     {
1636       int left  = (x>0 && IS_FREE(x-1,y) &&
1637                    (IS_FREE(x-1,y+1) || Feld[x-1][y+1]==EL_SALZSAEURE));
1638       int right = (x<lev_fieldx-1 && IS_FREE(x+1,y) &&
1639                    (IS_FREE(x+1,y+1) || Feld[x+1][y+1]==EL_SALZSAEURE));
1640
1641       if (left || right)
1642       {
1643         if (left && right)
1644           left = !(right=RND(2));
1645         InitMovingField(x,y,left ? MV_LEFT : MV_RIGHT);
1646       }
1647     }
1648   }
1649   else if (CAN_MOVE(element))
1650   {
1651     int newx,newy;
1652
1653     CheckMoving = TRUE;
1654
1655     if (!MovDelay[x][y])        /* neuer Schritt / noch nicht gewartet */
1656     {
1657       if (element==EL_ZOMBIE || element==EL_KAEFER || element==EL_FLIEGER)
1658       {
1659         TurnRound(x,y);
1660         if (MovDelay[x][y] && (element==EL_KAEFER || element==EL_FLIEGER))
1661           DrawLevelField(x,y);
1662       }
1663     }
1664
1665     if (MovDelay[x][y])         /* neuer Schritt / in Wartezustand */
1666     {
1667       MovDelay[x][y]--;
1668
1669       if (element==EL_ZOMBIE || element==EL_MAMPFER)
1670       {
1671         int phase = MovDelay[x][y] % 8;
1672
1673         if (phase>3)
1674           phase = 7-phase;
1675
1676         if (IN_SCR_FIELD(SCROLLX(x),SCROLLY(y)))
1677           DrawGraphic(SCROLLX(x),SCROLLY(y),
1678                       el2gfx(element)+phase);
1679
1680         if (element==EL_MAMPFER && MovDelay[x][y]%4==3)
1681           PlaySoundLevel(x,y,SND_NJAM);
1682       }
1683
1684       if (MovDelay[x][y])
1685         return;
1686     }
1687
1688     if (element==EL_KAEFER)
1689     {
1690       PlaySoundLevel(x,y,SND_KLAPPER);
1691     }
1692     else if (element==EL_FLIEGER)
1693     {
1694       PlaySoundLevel(x,y,SND_ROEHR);
1695     }
1696
1697     /* neuer Schritt / Wartezustand beendet */
1698
1699     Moving2Blocked(x,y,&newx,&newy);    /* wohin soll's gehen? */
1700
1701     if (PLAYER(newx,newy))              /* Spieler erwischt */
1702     {
1703       MovDir[x][y] = 0;
1704       KillHero();
1705       return;
1706     }
1707     else if (element==EL_MAMPFER && IN_LEV_FIELD(newx,newy) &&
1708              Feld[newx][newy]==EL_DIAMANT)
1709     {
1710       Feld[newx][newy] = EL_LEERRAUM;
1711       DrawLevelField(newx,newy);
1712     }
1713     else if (element==EL_PACMAN && IN_LEV_FIELD(newx,newy) &&
1714              IS_AMOEBOID(Feld[newx][newy]))
1715     {
1716       Feld[newx][newy] = EL_LEERRAUM;
1717       DrawLevelField(newx,newy);
1718     }
1719     else if (element==EL_ZOMBIE && IN_LEV_FIELD(newx,newy) &&
1720              MovDir[x][y]==MV_DOWN && Feld[newx][newy]==EL_SALZSAEURE)
1721     {
1722       Blurb(x,y);
1723       Store[x][y] = EL_SALZSAEURE;
1724     }
1725     else if (!IN_LEV_FIELD(newx,newy) || !IS_FREE(newx,newy))
1726     {                                   /* gegen Wand gelaufen */
1727       TurnRound(x,y);
1728       DrawLevelField(x,y);
1729       return;
1730     }
1731
1732     InitMovingField(x,y,MovDir[x][y]);
1733   }
1734
1735   if (MovDir[x][y])
1736     ContinueMoving(x,y);
1737 }
1738
1739 void ContinueMoving(int x, int y)
1740 {
1741   int element = Feld[x][y];
1742   int direction = MovDir[x][y];
1743   int dx = (direction==MV_LEFT ? -1 : direction==MV_RIGHT ? +1 : 0);
1744   int dy = (direction==MV_UP   ? -1 : direction==MV_DOWN  ? +1 : 0);
1745   int horiz_move = (dx!=0);
1746   int newx = x + dx, newy = y + dy;
1747   int step = (horiz_move ? dx : dy)*TILEX/4;
1748
1749   if (CAN_FALL(element) && horiz_move)
1750     step*=2;
1751   else if (element==EL_TROPFEN)
1752     step/=2;
1753   else if (Store[x][y]==EL_MORAST_VOLL || Store[x][y]==EL_MORAST_LEER)
1754     step/=4;
1755
1756   MovPos[x][y] += step;
1757
1758   if (ABS(MovPos[x][y])>=TILEX)         /* Zielfeld erreicht */
1759   {
1760     Feld[x][y]=EL_LEERRAUM;
1761     Feld[newx][newy]=element;
1762
1763     if (Store[x][y]==EL_MORAST_VOLL)
1764     {
1765       Store[x][y] = 0;
1766       Feld[newx][newy] = EL_MORAST_VOLL;
1767       element = EL_MORAST_VOLL;
1768     }
1769     else if (Store[x][y]==EL_MORAST_LEER)
1770     {
1771       Store[x][y] = 0;
1772       Feld[x][y] = EL_MORAST_LEER;
1773     }
1774     else if (Store[x][y]==EL_SIEB_VOLL)
1775     {
1776       Store[x][y] = 0;
1777       Feld[newx][newy] = EL_SIEB_VOLL;
1778       element = EL_SIEB_VOLL;
1779     }
1780     else if (Store[x][y]==EL_SIEB_LEER)
1781     {
1782       Store[x][y] = Store2[x][y] = 0;
1783       Feld[x][y] = EL_SIEB_LEER;
1784     }
1785     else if (Store[x][y]==EL_SALZSAEURE)
1786     {
1787       Store[x][y] = 0;
1788       Feld[newx][newy] = EL_SALZSAEURE;
1789       element = EL_SALZSAEURE;
1790     }
1791     else if (Store[x][y]==EL_AMOEBE2)
1792     {
1793       Store[x][y] = 0;
1794       Feld[x][y] = EL_AMOEBE2;
1795     }
1796
1797     MovPos[x][y] = MovDir[x][y] = 0;
1798
1799     if (!CAN_MOVE(element))
1800       MovDir[newx][newy] = 0;
1801
1802     DrawLevelField(x,y);
1803     DrawLevelField(newx,newy);
1804
1805     Stop[newx][newy]=TRUE;
1806     CheckMoving=TRUE;
1807
1808     if (DONT_TOUCH(element))    /* Käfer oder Flieger */
1809     {
1810       TestIfBadThingHitsHero();
1811       TestIfBadThingHitsOtherBadThing(newx,newy);
1812     }
1813
1814     if (CAN_SMASH(element) && direction==MV_DOWN &&
1815         (newy==lev_fieldy-1 || !IS_FREE(x,newy+1)))
1816       Impact(x,newy);
1817   }
1818   else                          /* noch in Bewegung */
1819   {
1820     DrawLevelField(x,y);
1821     CheckMoving=TRUE;
1822   }
1823 }
1824
1825 void AmoebeWaechst(int x, int y)
1826 {
1827   static int sound_delay = 0;
1828   static int sound_delay_value = 0;
1829
1830   CheckExploding=TRUE;
1831
1832   if (!MovDelay[x][y])          /* neue Phase / noch nicht gewartet */
1833   {
1834     MovDelay[x][y] = 4;
1835
1836     if (DelayReached(&sound_delay,sound_delay_value))
1837     {
1838       PlaySoundLevel(x,y,SND_AMOEBE);
1839       sound_delay_value = 30;
1840     }
1841   }
1842
1843   if (MovDelay[x][y])           /* neue Phase / in Wartezustand */
1844   {
1845     MovDelay[x][y]--;
1846     if (MovDelay[x][y] && IN_SCR_FIELD(SCROLLX(x),SCROLLY(y)))
1847       DrawGraphic(SCROLLX(x),SCROLLY(y),GFX_AMOEBING+3-MovDelay[x][y]);
1848
1849     if (!MovDelay[x][y])
1850     {
1851       Feld[x][y] = (Feld[x][y]==EL_AMOEBING2 ? EL_AMOEBE2 : EL_AMOEBE3);
1852       DrawLevelField(x,y);
1853     }
1854   }
1855 }
1856
1857 void AmoebeAbleger(int ax, int ay)
1858 {
1859   int i,j,start;
1860   int newax = ax, neway = ay;
1861   BOOL waiting_for_player = FALSE;
1862   static int xy[4][2] =
1863   {
1864     0,-1,
1865     -1,0,
1866     +1,0,
1867     0,+1
1868   };
1869
1870   CheckExploding=TRUE;
1871
1872   if (!level.tempo_amoebe)
1873   {
1874     Feld[ax][ay] = EL_AMOEBE1;
1875     DrawLevelField(ax,ay);
1876     return;
1877   }
1878
1879   if (!MovDelay[ax][ay])        /* neue Amoebe / noch nicht gewartet */
1880     MovDelay[ax][ay] = RND(33*20/(1+level.tempo_amoebe));
1881
1882   if (MovDelay[ax][ay])         /* neue Amoebe / in Wartezustand */
1883   {
1884     MovDelay[ax][ay]--;
1885     if (MovDelay[ax][ay])
1886       return;
1887   }
1888
1889   if (Feld[ax][ay]==EL_AMOEBE3)
1890   {
1891     start = RND(4);
1892     for(i=0;i<4;i++)
1893     {
1894       int x,y;
1895
1896       j = (start+i)%4;
1897       x = ax+xy[j][0];
1898       y = ay+xy[j][1];
1899       if (!IN_LEV_FIELD(x,y))
1900         continue;
1901
1902       if (IS_FREE(x,y) ||
1903           Feld[x][y]==EL_ERDREICH || Feld[x][y]==EL_MORAST_LEER)
1904       {
1905         newax=x;
1906         neway=y;
1907         break;
1908       }
1909       else if (PLAYER(x,y))
1910         waiting_for_player = TRUE;
1911     }
1912
1913     if (newax==ax && neway==ay)
1914     {
1915       if (Feld[ax][ay]==EL_AMOEBE3 && i==4 && !waiting_for_player)
1916       {
1917         Feld[ax][ay] = EL_AMOEBE1;
1918         DrawLevelField(ax,ay);
1919       }
1920       return;
1921     }
1922   }
1923   else
1924   {
1925     int x,y;
1926
1927     start = RND(4);
1928     x = ax+xy[start][0];
1929     y = ay+xy[start][1];
1930     if (!IN_LEV_FIELD(x,y))
1931       return;
1932
1933     if (IS_FREE(x,y) ||
1934           Feld[x][y]==EL_ERDREICH || Feld[x][y]==EL_MORAST_LEER)
1935     {
1936       newax=x;
1937       neway=y;
1938     }
1939
1940     if (newax==ax && neway==ay)
1941       return;
1942   }
1943
1944   if (Feld[ax][ay]==EL_AMOEBE3)
1945     Feld[newax][neway] = EL_AMOEBING3;
1946   else if (neway==lev_fieldy-1)
1947     Feld[newax][neway] = EL_AMOEBING2;
1948   else if (neway<=ay || !IS_FREE(newax,neway))
1949     Feld[newax][neway] = EL_TROPFEN;
1950   else
1951   {
1952     InitMovingField(ax,ay,MV_DOWN);
1953     Feld[ax][ay]=EL_TROPFEN;
1954     Store[ax][ay]=EL_AMOEBE2;
1955     ContinueMoving(ax,ay);
1956     return;
1957   }
1958
1959   DrawLevelField(newax,neway);
1960 }
1961
1962 void Life(int ax, int ay)
1963 {
1964   int x1,y1,x2,y2;
1965   static int life[4] = { 2,3,3,3 };     /* "Life"-Parameter */
1966   int life_time = 20;
1967   int element = Feld[ax][ay];
1968
1969   CheckExploding=TRUE;
1970
1971   if (Stop[ax][ay])
1972     return;
1973
1974   if (!MovDelay[ax][ay])        /* neue Phase / noch nicht gewartet */
1975     MovDelay[ax][ay] = life_time;
1976
1977   if (MovDelay[ax][ay])         /* neue Phase / in Wartezustand */
1978   {
1979     MovDelay[ax][ay]--;
1980     if (MovDelay[ax][ay])
1981       return;
1982   }
1983
1984   for(y1=-1;y1<2;y1++) for(x1=-1;x1<2;x1++)
1985   {
1986     int xx = ax+x1, yy = ay+y1;
1987     int nachbarn = 0;
1988
1989     if (!IN_LEV_FIELD(xx,yy))
1990       continue;
1991
1992     for(y2=-1;y2<2;y2++) for(x2=-1;x2<2;x2++)
1993     {
1994       int x = xx+x2, y = yy+y2;
1995
1996       if (!IN_LEV_FIELD(x,y) || (x==xx && y==yy))
1997         continue;
1998
1999       if ((Feld[x][y]==element && !Stop[x][y]) ||
2000           (IS_FREE(x,y) && Stop[x][y]))
2001         nachbarn++;
2002     }
2003
2004     if (xx==ax && yy==ay)               /* mittleres Feld mit Amoebe */
2005     {
2006       if (nachbarn<life[0] || nachbarn>life[1])
2007       {
2008         Feld[xx][yy] = EL_LEERRAUM;
2009         if (!Stop[xx][yy])
2010           DrawLevelField(xx,yy);
2011         Stop[xx][yy] = TRUE;
2012       }
2013     }
2014     else if (IS_FREE(xx,yy) || Feld[xx][yy]==EL_ERDREICH)
2015     {                                   /* Randfeld ohne Amoebe */
2016       if (nachbarn>=life[2] && nachbarn<=life[3])
2017       {
2018         Feld[xx][yy] = element;
2019         MovDelay[xx][yy] = (element==EL_LIFE ? 0 : life_time-1);
2020         if (!Stop[xx][yy])
2021           DrawLevelField(xx,yy);
2022         Stop[xx][yy] = TRUE;
2023       }
2024     }
2025   }
2026 }
2027
2028 void Ablenk(int x, int y)
2029 {
2030   CheckExploding=TRUE;
2031
2032   if (!MovDelay[x][y])          /* neue Phase / noch nicht gewartet */
2033     MovDelay[x][y] = 33*(level.dauer_ablenk/10);
2034   if (MovDelay[x][y])           /* neue Phase / in Wartezustand */
2035   {
2036     MovDelay[x][y]--;
2037     if (MovDelay[x][y])
2038     {
2039       if (IN_SCR_FIELD(SCROLLX(x),SCROLLY(y)))
2040         DrawGraphic(SCROLLX(x),SCROLLY(y),GFX_ABLENK+MovDelay[x][y]%4);
2041       if (!(MovDelay[x][y]%4))
2042         PlaySoundLevel(x,y,SND_MIEP);
2043       return;
2044     }
2045   }
2046
2047   Feld[x][y]=EL_ABLENK_AUS;
2048   DrawLevelField(x,y);
2049   if (ZX==x && ZY==y)
2050     ZX=ZY=-1;
2051 }
2052
2053 void Birne(int x, int y)
2054 {
2055   CheckExploding=TRUE;
2056
2057   if (!MovDelay[x][y])          /* neue Phase / noch nicht gewartet */
2058     MovDelay[x][y] = 400;
2059
2060   if (MovDelay[x][y])           /* neue Phase / in Wartezustand */
2061   {
2062     MovDelay[x][y]--;
2063     if (MovDelay[x][y])
2064     {
2065       if (!(MovDelay[x][y]%5))
2066       {
2067         if (!(MovDelay[x][y]%10))
2068           Feld[x][y]=EL_ABLENK_EIN;
2069         else
2070           Feld[x][y]=EL_ABLENK_AUS;
2071         DrawLevelField(x,y);
2072         Feld[x][y]=EL_ABLENK_EIN;
2073       }
2074       return;
2075     }
2076   }
2077
2078   Feld[x][y]=EL_ABLENK_AUS;
2079   DrawLevelField(x,y);
2080   if (ZX==x && ZY==y)
2081     ZX=ZY=-1;
2082 }
2083
2084 void Blubber(int x, int y)
2085 {
2086   CheckExploding=TRUE;
2087
2088   if (!MovDelay[x][y])          /* neue Phase / noch nicht gewartet */
2089     MovDelay[x][y] = 20;
2090
2091   if (MovDelay[x][y])           /* neue Phase / in Wartezustand */
2092   {
2093     int blubber;
2094
2095     MovDelay[x][y]--;
2096     blubber = MovDelay[x][y]/5;
2097     if (!(MovDelay[x][y]%5) && IN_SCR_FIELD(SCROLLX(x),SCROLLY(y)))
2098       DrawGraphic(SCROLLX(x),SCROLLY(y),GFX_GEBLUBBER+3-blubber);
2099   }
2100 }
2101
2102 void NussKnacken(int x, int y)
2103 {
2104   CheckExploding=TRUE;
2105
2106   if (!MovDelay[x][y])          /* neue Phase / noch nicht gewartet */
2107     MovDelay[x][y] = 4;
2108
2109   if (MovDelay[x][y])           /* neue Phase / in Wartezustand */
2110   {
2111     MovDelay[x][y]--;
2112     if (MovDelay[x][y] && IN_SCR_FIELD(SCROLLX(x),SCROLLY(y)))
2113       DrawGraphic(SCROLLX(x),SCROLLY(y),GFX_CRACKINGNUT+3-MovDelay[x][y]);
2114
2115     if (!MovDelay[x][y])
2116     {
2117       Feld[x][y] = EL_EDELSTEIN;
2118       DrawLevelField(x,y);
2119     }
2120   }
2121 }
2122
2123 void SiebAktivieren(int x, int y)
2124 {
2125   CheckExploding=TRUE;
2126
2127   if (SiebAktiv>1)
2128   {
2129     if (SiebAktiv%2 && IN_SCR_FIELD(SCROLLX(x),SCROLLY(y)))
2130       DrawGraphic(SCROLLX(x),SCROLLY(y),GFX_SIEB_VOLL+3-(SiebAktiv%8)/2);
2131
2132 /*
2133     if (!(SiebAktiv%4))
2134       PlaySoundLevel(x,y,SND_MIEP);
2135 */
2136
2137   }
2138   else
2139   {
2140     Feld[x][y] = EL_SIEB_TOT;
2141     DrawLevelField(x,y);
2142   }
2143 }
2144
2145 void AusgangstuerPruefen(int x, int y)
2146 {
2147   CheckExploding=TRUE;
2148
2149   if (!Gems)
2150     Feld[x][y] = EL_AUSGANG_ACT;
2151 }
2152
2153 void AusgangstuerOeffnen(int x, int y)
2154 {
2155   CheckExploding=TRUE;
2156
2157   if (!MovDelay[x][y])          /* neue Phase / noch nicht gewartet */
2158     MovDelay[x][y] = 20;
2159
2160   if (MovDelay[x][y])           /* neue Phase / in Wartezustand */
2161   {
2162     int tuer;
2163
2164     MovDelay[x][y]--;
2165     tuer = MovDelay[x][y]/5;
2166     if (!(MovDelay[x][y]%5) && IN_SCR_FIELD(SCROLLX(x),SCROLLY(y)))
2167       DrawGraphic(SCROLLX(x),SCROLLY(y),GFX_AUSGANG_ZU+3-tuer);
2168
2169     if (!MovDelay[x][y])
2170     {
2171       Feld[x][y] = EL_AUSGANG_AUF;
2172       DrawLevelField(x,y);
2173     }
2174   }
2175 }
2176
2177 int GameActions(int mx, int my, int button)
2178 {
2179   static int time_delay=0, action_delay=0;
2180   int Action;
2181
2182   if (TimeLeft>0 && DelayReached(&time_delay,100) && !tape.pausing)
2183   {
2184     TimeLeft--;
2185
2186     if (tape.recording || tape.playing)
2187       DrawVideoDisplay(VIDEO_STATE_TIME_ON,level.time-TimeLeft);
2188
2189     if (TimeLeft<=10)
2190       PlaySoundStereo(SND_GONG,PSND_MAX_RIGHT);
2191
2192     DrawText(DX_TIME,DY_TIME,int2str(TimeLeft,3),FS_SMALL,FC_YELLOW);
2193     BackToFront();
2194   }
2195
2196   if (!TimeLeft)
2197     KillHero();
2198
2199   Action = (CheckMoving || CheckExploding || SiebAktiv);
2200
2201 /*
2202   if (Action && DelayReached(&action_delay,3))
2203 */
2204
2205   if (DelayReached(&action_delay,3))
2206   {
2207     int x,y,element;
2208
2209     if (tape.pausing || (tape.playing && !TapePlayDelay()))
2210       return(ACT_GO_ON);
2211     else if (tape.recording)
2212       TapeRecordDelay();
2213
2214     CheckMoving = CheckExploding = FALSE;
2215     for(y=0;y<lev_fieldy;y++) for(x=0;x<lev_fieldx;x++)
2216       Stop[x][y] = FALSE;
2217
2218     for(y=0;y<lev_fieldy;y++) for(x=0;x<lev_fieldx;x++)
2219     {
2220       element = Feld[x][y];
2221
2222       if (element==EL_LEERRAUM || element==EL_ERDREICH)
2223         continue;
2224
2225       if (!IS_MOVING(x,y) && (CAN_FALL(element) || CAN_MOVE(element)))
2226         StartMoving(x,y);
2227       else if (IS_MOVING(x,y))
2228         ContinueMoving(x,y);
2229       else if (element==EL_DYNAMIT)
2230         CheckDynamite(x,y);
2231       else if (element==EL_EXPLODING)
2232         Explode(x,y,Frame[x][y]);
2233       else if (element==EL_AMOEBING2 || element==EL_AMOEBING3)
2234         AmoebeWaechst(x,y);
2235       else if (element==EL_AMOEBE2 || element==EL_AMOEBE3)
2236         AmoebeAbleger(x,y);
2237       else if (element==EL_LIFE || element==EL_LIFE_ASYNC)
2238         Life(x,y);
2239       else if (element==EL_ABLENK_EIN)
2240         Ablenk(x,y);
2241       else if (element==EL_SALZSAEURE)
2242         Blubber(x,y);
2243       else if (element==EL_BLURB_LEFT || element==EL_BLURB_RIGHT)
2244         Blurb(x,y);
2245       else if (element==EL_CRACKINGNUT)
2246         NussKnacken(x,y);
2247       else if (element==EL_AUSGANG_ZU)
2248         AusgangstuerPruefen(x,y);
2249       else if (element==EL_AUSGANG_ACT)
2250         AusgangstuerOeffnen(x,y);
2251
2252       if (SiebAktiv && (element==EL_SIEB_LEER ||
2253                         element==EL_SIEB_VOLL ||
2254                         Store[x][y]==EL_SIEB_LEER))
2255         SiebAktivieren(x,y);
2256     }
2257
2258     if (SiebAktiv)
2259       SiebAktiv--;
2260
2261     if (CheckMoving || CheckExploding)
2262       BackToFront();
2263   }
2264
2265   return(ACT_GO_ON);
2266 }
2267
2268 void ScrollLevel(int dx, int dy)
2269 {
2270   int x,y;
2271
2272   XCopyArea(display,drawto_field,drawto_field,gc,
2273             SX+TILEX*(dx==-1),SY+TILEY*(dy==-1),
2274             SXSIZE-TILEX*(dx!=0),SYSIZE-TILEY*(dy!=0),
2275             SX+TILEX*(dx==1),SY+TILEY*(dy==1));
2276
2277   if (dx)
2278   {
2279     x = dx==1 ? 0 : SCR_FIELDX-1;
2280     for(y=0;y<SCR_FIELDY;y++)
2281       DrawScreenField(x,y);
2282   }
2283   if (dy)
2284   {
2285     y = dy==1 ? 0 : SCR_FIELDY-1;
2286     for(x=0;x<SCR_FIELDY;x++)
2287       DrawScreenField(x,y);
2288   }
2289
2290   redraw_mask|=REDRAW_FIELD;
2291 }
2292
2293 BOOL MoveFigureOneStep(int dx, int dy)
2294 {
2295   int oldJX,oldJY, newJX=JX+dx,newJY=JY+dy;
2296   int element;
2297   int can_move;
2298
2299   if (!dx && !dy)
2300     return(MF_NO_ACTION);
2301   if (!IN_LEV_FIELD(newJX,newJY))
2302     return(MF_NO_ACTION);
2303
2304   element = MovingOrBlocked2Element(newJX,newJY);
2305
2306   if (DONT_GO_TO(element))
2307   {
2308     if (element==EL_SALZSAEURE && dx==0 && dy==1)
2309     {
2310       Blurb(JX,JY);
2311       Feld[JX][JY] = EL_SPIELFIGUR;
2312       InitMovingField(JX,JY,MV_DOWN);
2313       Store[JX][JY] = EL_SALZSAEURE;
2314       ContinueMoving(JX,JY);
2315
2316       PlaySoundLevel(JX,JY,SND_AUTSCH);
2317       PlaySoundLevel(JX,JY,SND_LACHEN);
2318       GameOver=TRUE;
2319       JX=JY=-1;
2320     }
2321     else
2322       KillHero();
2323
2324     return(MF_MOVING);
2325   }
2326
2327   can_move = DigField(newJX,newJY,DF_DIG);
2328   if (can_move != MF_MOVING)
2329     return(can_move);
2330
2331   oldJX = JX;
2332   oldJY = JY;
2333   JX = newJX;
2334   JY = newJY;
2335
2336   if (Store[oldJX][oldJY])
2337   {
2338     DrawGraphic(SCROLLX(oldJX),SCROLLY(oldJY),el2gfx(Store[oldJX][oldJY]));
2339     DrawGraphicThruMask(SCROLLX(oldJX),SCROLLY(oldJY),
2340                         el2gfx(Feld[oldJX][oldJY]));
2341   }
2342   else if (Feld[oldJX][oldJY]==EL_DYNAMIT)
2343     DrawDynamite(oldJX,oldJY);
2344   else
2345     DrawLevelField(oldJX,oldJY);
2346
2347   return(MF_MOVING);
2348 }
2349
2350 BOOL MoveFigure(int dx, int dy)
2351 {
2352   static int move_delay = 0;
2353   int moved = MF_NO_ACTION;
2354
2355   if (GameOver || (!dx && !dy))
2356     return(FALSE);
2357
2358   if (!DelayReached(&move_delay,10) && !tape.playing)
2359     return(FALSE);
2360
2361   if (moved |= MoveFigureOneStep(dx,0))
2362     moved |= MoveFigureOneStep(0,dy);
2363   else
2364   {
2365     moved |= MoveFigureOneStep(0,dy);
2366     moved |= MoveFigureOneStep(dx,0);
2367   }
2368
2369   if (moved & MF_MOVING)
2370   {
2371     int old_scroll_x=scroll_x, old_scroll_y=scroll_y;
2372
2373     if (scroll_x!=JX-MIDPOSX && JX>=MIDPOSX-1 && JX<=lev_fieldx-MIDPOSX)
2374       scroll_x = JX-MIDPOSX;
2375     if (scroll_y!=JY-MIDPOSY && JY>=MIDPOSY-1 && JY<=lev_fieldy-MIDPOSY)
2376       scroll_y = JY-MIDPOSY;
2377
2378     if (scroll_x!=old_scroll_x || scroll_y!=old_scroll_y)
2379       ScrollLevel(old_scroll_x-scroll_x,old_scroll_y-scroll_y);
2380
2381     if (Feld[JX][JY]==EL_LEERRAUM)
2382       DrawLevelElement(JX,JY,EL_SPIELFIGUR);
2383     else
2384       DrawGraphicThruMask(SCROLLX(JX),SCROLLY(JY),GFX_SPIELFIGUR);
2385   }
2386
2387   TestIfHeroHitsBadThing();
2388
2389   BackToFront();
2390
2391   if (LevelSolved)
2392     GameWon();
2393
2394   return(moved);
2395 }
2396
2397 void TestIfHeroHitsBadThing()
2398 {
2399   int i, killx = JX,killy = JY;
2400   static int xy[4][2] =
2401   {
2402     0,-1,
2403     -1,0,
2404     +1,0,
2405     0,+1
2406   };
2407   static int harmless[4] =
2408   {
2409     MV_UP,
2410     MV_LEFT,
2411     MV_RIGHT,
2412     MV_DOWN
2413   };
2414
2415   for(i=0;i<4;i++)
2416   {
2417     int x,y,element;
2418
2419     x = JX+xy[i][0];
2420     y = JY+xy[i][1];
2421     if (!IN_LEV_FIELD(x,y))
2422       continue;
2423
2424     element = Feld[x][y];
2425
2426     if (DONT_TOUCH(element))
2427     {
2428       if (MovDir[x][y]==harmless[i])
2429         continue;
2430
2431       killx = x;
2432       killy = y;
2433       break;
2434     }
2435   }
2436
2437   if (killx!=JX || killy!=JY)
2438     KillHero();
2439 }
2440
2441 void TestIfBadThingHitsHero()
2442 {
2443   TestIfHeroHitsBadThing();
2444 }
2445
2446 void TestIfBadThingHitsOtherBadThing(int badx, int bady)
2447 {
2448   int i, killx=badx, killy=bady;
2449   static int xy[4][2] =
2450   {
2451     0,-1,
2452     -1,0,
2453     +1,0,
2454     0,+1
2455   };
2456
2457   for(i=0;i<4;i++)
2458   {
2459     int x,y,element;
2460
2461     x=badx+xy[i][0];
2462     y=bady+xy[i][1];
2463     if (!IN_LEV_FIELD(x,y))
2464       continue;
2465
2466     element=Feld[x][y];
2467     if (IS_AMOEBOID(element) || element==EL_LIFE ||
2468         element==EL_AMOEBING2 || element==EL_AMOEBING3 || element==EL_TROPFEN)
2469     {
2470       killx=x;
2471       killy=y;
2472       break;
2473     }
2474   }
2475
2476   if (killx!=badx || killy!=bady)
2477     Bang(badx,bady);
2478 }
2479
2480 void KillHero()
2481 {
2482   if (PLAYER(-1,-1))
2483     return;
2484
2485   if (IS_PFORTE(Feld[JX][JY]))
2486     Feld[JX][JY] = EL_LEERRAUM;
2487
2488   PlaySoundLevel(JX,JY,SND_AUTSCH);
2489   PlaySoundLevel(JX,JY,SND_LACHEN);
2490   Bang(JX,JY);
2491   GameOver = TRUE;
2492   JX = JY = -1;
2493 }
2494
2495 int DigField(int x, int y, int mode)
2496 {
2497   int dx=x-JX, dy=y-JY;
2498   int element;
2499   static int push_delay = 0;
2500   static int push_delay_value = 20;
2501
2502   if (mode==DF_NO_PUSH)
2503   {
2504     push_delay = 0;
2505     return(MF_NO_ACTION);
2506   }
2507
2508   if (IS_MOVING(x,y))
2509     return(MF_NO_ACTION);
2510
2511   element = Feld[x][y];
2512
2513   switch(element)
2514   {
2515     case EL_LEERRAUM:
2516       CheckMoving=TRUE;
2517       break;
2518     case EL_ERDREICH:
2519       Feld[x][y]=EL_LEERRAUM;
2520       CheckMoving=TRUE;
2521       break;
2522     case EL_EDELSTEIN:
2523       Feld[x][y]=EL_LEERRAUM;
2524       CheckMoving=TRUE;
2525       if (Gems>0)
2526         Gems--;
2527       RaiseScore(level.score[SC_EDELSTEIN]);
2528       DrawText(DX_EMERALDS,DY_EMERALDS,int2str(Gems,3),FS_SMALL,FC_YELLOW);
2529       PlaySoundLevel(x,y,SND_PONG);
2530       break;
2531     case EL_DIAMANT:
2532       Feld[x][y]=EL_LEERRAUM;
2533       CheckMoving=TRUE;
2534       Gems -= 3;
2535       if (Gems<0)
2536         Gems=0;
2537       RaiseScore(level.score[SC_DIAMANT]);
2538       DrawText(DX_EMERALDS,DY_EMERALDS,int2str(Gems,3),FS_SMALL,FC_YELLOW);
2539       PlaySoundLevel(x,y,SND_PONG);
2540       break;
2541     case EL_DYNAMIT_AUS:
2542       Feld[x][y]=EL_LEERRAUM;
2543       CheckMoving=TRUE;
2544       Dynamite++;
2545       RaiseScore(level.score[SC_DYNAMIT]);
2546       DrawText(DX_DYNAMITE,DY_DYNAMITE,int2str(Dynamite,3),FS_SMALL,FC_YELLOW);
2547       PlaySoundLevel(x,y,SND_PONG);
2548       break;
2549     case EL_SCHLUESSEL1:
2550     case EL_SCHLUESSEL2:
2551     case EL_SCHLUESSEL3:
2552     case EL_SCHLUESSEL4:
2553     {
2554       int key_nr = element-EL_SCHLUESSEL1;
2555
2556       Feld[x][y] = EL_LEERRAUM;
2557       CheckMoving = TRUE;
2558       Key[key_nr] = TRUE;
2559       RaiseScore(level.score[SC_SCHLUESSEL]);
2560       DrawMiniGraphicExtHiRes(drawto,gc,
2561                               DX_KEYS+key_nr*MINI_TILEX,DY_KEYS,
2562                               GFX_SCHLUESSEL1+key_nr);
2563       DrawMiniGraphicExtHiRes(window,gc,
2564                               DX_KEYS+key_nr*MINI_TILEX,DY_KEYS,
2565                               GFX_SCHLUESSEL1+key_nr);
2566       PlaySoundLevel(x,y,SND_PONG);
2567       break;
2568     }
2569     case EL_ABLENK_AUS:
2570       Feld[x][y]=EL_ABLENK_EIN;
2571       CheckExploding=TRUE;
2572       ZX=x;
2573       ZY=y;
2574       DrawLevelField(x,y);
2575 /*
2576       PlaySoundLevel(x,y,SND_DENG);
2577 */
2578       return(MF_ACTION);
2579       break;
2580     case EL_FELSBROCKEN:
2581     case EL_BOMBE:
2582     case EL_KOKOSNUSS:
2583       if (mode==DF_SNAP)
2584         return(MF_NO_ACTION);
2585       if (dy || !IN_LEV_FIELD(x+dx,y+dy) || Feld[x+dx][y+dy]!=EL_LEERRAUM)
2586         return(MF_NO_ACTION);
2587
2588       if (Counter() > push_delay+4*push_delay_value)
2589         push_delay = Counter();
2590       if (!DelayReached(&push_delay,push_delay_value) && !tape.playing)
2591         return(MF_NO_ACTION);
2592
2593       Feld[x][y] = EL_LEERRAUM;
2594       Feld[x+dx][y+dy] = element;
2595       push_delay_value = 10+RND(30);
2596       CheckMoving = TRUE;
2597       DrawLevelField(x+dx,y+dy);
2598       if (element==EL_FELSBROCKEN)
2599         PlaySoundLevel(x+dx,y+dy,SND_PUSCH);
2600       else if (element==EL_KOKOSNUSS)
2601         PlaySoundLevel(x+dx,y+dy,SND_KNURK);
2602       else
2603         PlaySoundLevel(x+dx,y+dy,SND_KLOPF);
2604       break;
2605     case EL_PFORTE1:
2606     case EL_PFORTE2:
2607     case EL_PFORTE3:
2608     case EL_PFORTE4:
2609       if (!Key[element-EL_PFORTE1])
2610         return(MF_NO_ACTION);
2611       break;
2612     case EL_PFORTE1X:
2613     case EL_PFORTE2X:
2614     case EL_PFORTE3X:
2615     case EL_PFORTE4X:
2616       if (!Key[element-EL_PFORTE1X])
2617         return(MF_NO_ACTION);
2618       break;
2619     case EL_AUSGANG_ZU:
2620     case EL_AUSGANG_ACT:
2621       /* Tür ist (noch) nicht offen! */
2622       return(MF_NO_ACTION);
2623       break;
2624     case EL_AUSGANG_AUF:
2625       if (mode==DF_SNAP || Gems>0)
2626         return(MF_NO_ACTION);
2627       LevelSolved = TRUE;
2628       PlaySoundLevel(x,y,SND_BUING);
2629       break;
2630     default:
2631       return(MF_NO_ACTION);
2632       break;
2633   }
2634   push_delay=0;
2635   return(MF_MOVING);
2636 }
2637
2638 BOOL SnapField(int dx, int dy)
2639 {
2640   int x = JX+dx, y = JY+dy;
2641   static int snapped = FALSE;
2642
2643   if (GameOver || !IN_LEV_FIELD(x,y))
2644     return(FALSE);
2645   if (dx && dy)
2646     return(FALSE);
2647   if (!dx && !dy)
2648   {
2649     snapped = FALSE;
2650     return(FALSE);
2651   }
2652   if (snapped)
2653     return(FALSE);
2654
2655   if (!DigField(x,y,DF_SNAP))
2656     return(FALSE);
2657
2658   snapped = TRUE;
2659   DrawLevelField(x,y);
2660   BackToFront();
2661
2662   return(TRUE);
2663 }
2664
2665 BOOL PlaceBomb(void)
2666 {
2667   if (Dynamite==0 || Feld[JX][JY]==EL_DYNAMIT)
2668     return(FALSE);
2669
2670   if (Feld[JX][JY]!=EL_LEERRAUM)
2671     Store[JX][JY] = Feld[JX][JY];
2672   Feld[JX][JY] = EL_DYNAMIT;
2673   MovDelay[JX][JY] = 48;
2674   Dynamite--;
2675   DrawText(DX_DYNAMITE,DY_DYNAMITE,int2str(Dynamite,3),FS_SMALL,FC_YELLOW);
2676   DrawGraphicThruMask(SCROLLX(JX),SCROLLY(JY),GFX_DYNAMIT);
2677   CheckExploding = TRUE;
2678   return(TRUE);
2679 }
2680
2681 void PlaySoundLevel(int x, int y, int sound_nr)
2682 {
2683   int sx = SCROLLX(x), sy = SCROLLY(y);
2684   int volume, stereo;
2685
2686   if (!sound_loops_on && IS_LOOP_SOUND(sound_nr))
2687     return;
2688
2689   if (!IN_LEV_FIELD(x,y))
2690     return;
2691
2692   volume = PSND_MAX_VOLUME;
2693   stereo = (sx-SCR_FIELDX/2)*12;
2694
2695   if (!IN_SCR_FIELD(sx,sy))
2696   {
2697     if (sx<0 || sx>=SCR_FIELDX)
2698       volume = PSND_MAX_VOLUME - 2*ABS(sx-SCR_FIELDX/2);
2699     else
2700       volume = PSND_MAX_VOLUME - 2*ABS(sy-SCR_FIELDY/2);
2701   }
2702
2703   PlaySoundExt(sound_nr, volume, stereo, PSND_NO_LOOP);
2704 }
2705
2706 void RaiseScore(int value)
2707 {
2708   Score += value;
2709   DrawText(DX_SCORE,DY_SCORE,int2str(Score,5),FS_SMALL,FC_YELLOW);
2710   BackToFront();
2711 }
2712
2713 void TapeInitRecording()
2714 {
2715   time_t zeit1 = time(NULL);
2716   struct tm *zeit2 = localtime(&zeit1);
2717
2718   if (tape.recording || tape.playing)
2719     return;
2720
2721   tape.level_nr = level_nr;
2722   tape.recording = TRUE;
2723   tape.pausing = TRUE;
2724   tape.date =
2725     10000*(zeit2->tm_year%100) + 100*zeit2->tm_mon + zeit2->tm_mday;
2726
2727   DrawVideoDisplay(VIDEO_STATE_REC_ON | VIDEO_STATE_PAUSE_ON,0);
2728   DrawVideoDisplay(VIDEO_STATE_DATE_ON,tape.date);
2729   DrawVideoDisplay(VIDEO_STATE_TIME_ON,0);
2730 }
2731
2732 void TapeStartRecording()
2733 {
2734   tape.length = 0;
2735   tape.counter = 0;
2736   tape.pos[tape.counter].delay = 0;
2737   tape.recording = TRUE;
2738   tape.playing = FALSE;
2739   tape.pausing = FALSE;
2740   tape.random_seed = InitRND(NEW_RANDOMIZE);
2741   DrawVideoDisplay(VIDEO_STATE_REC_ON | VIDEO_STATE_PAUSE_OFF,0);
2742 }
2743
2744 void TapeStopRecording()
2745 {
2746   if (!tape.recording)
2747     return;
2748
2749   tape.length = tape.counter;
2750   tape.recording = FALSE;
2751   tape.pausing = FALSE;
2752   DrawVideoDisplay(VIDEO_STATE_REC_OFF,0);
2753
2754   master_tape = tape;
2755 }
2756
2757 void TapeRecordAction(int joy)
2758 {
2759   if (!tape.recording || tape.pausing)
2760     return;
2761
2762   if (tape.counter>=MAX_TAPELEN-1)
2763   {
2764     TapeStopRecording();
2765     return;
2766   }
2767
2768   if (joy)
2769   {
2770     tape.pos[tape.counter].joystickdata = joy;
2771     tape.counter++;
2772     tape.pos[tape.counter].delay = 0;
2773   }
2774 }
2775
2776 void TapeRecordDelay()
2777 {
2778   if (!tape.recording || tape.pausing)
2779     return;
2780
2781   if (tape.counter>=MAX_TAPELEN)
2782   {
2783     TapeStopRecording();
2784     return;
2785   }
2786
2787   tape.pos[tape.counter].delay++;
2788
2789   if (tape.pos[tape.counter].delay>=255)
2790   {
2791     tape.pos[tape.counter].joystickdata = 0;
2792     tape.counter++;
2793     tape.pos[tape.counter].delay = 0;
2794   }
2795 }
2796
2797 void TapeTogglePause()
2798 {
2799   if (!tape.recording && !tape.playing)
2800     return;
2801
2802   if (tape.pausing)
2803   {
2804     tape.pausing = FALSE;
2805     DrawVideoDisplay(VIDEO_STATE_PAUSE_OFF,0);
2806     if (game_status==MAINMENU)
2807       HandleMainMenu(SX+16,SY+7*32+16,0,0,MB_MENU_CHOICE);
2808   }
2809   else
2810   {
2811     tape.pausing = TRUE;
2812     DrawVideoDisplay(VIDEO_STATE_PAUSE_ON,0);
2813   }
2814 }
2815
2816 void TapeInitPlaying()
2817 {
2818   if (tape.recording || tape.playing || TAPE_IS_EMPTY(tape))
2819     return;
2820
2821   tape.playing = TRUE;
2822   tape.pausing = TRUE;
2823   DrawVideoDisplay(VIDEO_STATE_PLAY_ON | VIDEO_STATE_PAUSE_ON,0);
2824   DrawVideoDisplay(VIDEO_STATE_DATE_ON,tape.date);
2825   DrawVideoDisplay(VIDEO_STATE_TIME_ON,0);
2826 }
2827
2828 void TapeStartPlaying()
2829 {
2830   tape = master_tape;
2831
2832   tape.counter = 0;
2833   tape.recording = FALSE;
2834   tape.playing = TRUE;
2835   tape.pausing = FALSE;
2836   InitRND(tape.random_seed);
2837   DrawVideoDisplay(VIDEO_STATE_PLAY_ON | VIDEO_STATE_PAUSE_OFF,0);
2838 }
2839
2840 void TapeStopPlaying()
2841 {
2842   if (!tape.playing)
2843     return;
2844
2845   tape.playing = FALSE;
2846   tape.pausing = FALSE;
2847   DrawVideoDisplay(VIDEO_STATE_PLAY_OFF,0);
2848 }
2849
2850 int TapePlayAction()
2851 {
2852   if (!tape.playing || tape.pausing)
2853     return(0);
2854
2855   if (tape.counter>=tape.length)
2856   {
2857     TapeStopPlaying();
2858     return(0);
2859   }
2860
2861   if (!tape.pos[tape.counter].delay)
2862   {
2863     tape.counter++;
2864     return(tape.pos[tape.counter-1].joystickdata);
2865   }
2866   else
2867     return(0);
2868 }
2869
2870 BOOL TapePlayDelay()
2871 {
2872   if (!tape.playing || tape.pausing)
2873     return(0);
2874
2875   if (tape.counter>=tape.length)
2876   {
2877     TapeStopPlaying();
2878     return(TRUE);
2879   }
2880
2881   if (tape.pos[tape.counter].delay)
2882   {
2883     tape.pos[tape.counter].delay--;
2884     return(TRUE);
2885   }
2886   else
2887     return(FALSE);
2888 }
2889
2890 void TapeStop()
2891 {
2892   TapeStopRecording();
2893   TapeStopPlaying();
2894   DrawVideoDisplay(VIDEO_ALL_OFF,0);
2895   if (tape.date && tape.length)
2896   {
2897     DrawVideoDisplay(VIDEO_STATE_DATE_ON,tape.date);
2898     DrawVideoDisplay(VIDEO_STATE_TIME_ON,0);
2899   }
2900 }
2901
2902 void TapeErase()
2903 {
2904   tape.length = 0;
2905 }
2906
2907 void DrawVideoDisplay(unsigned int state, unsigned int value)
2908 {
2909   int i;
2910   int part1 = 0, part2 = 1;
2911   int xpos = 0, ypos = 1, xsize = 2, ysize = 3;
2912   static char *monatsname[12] =
2913   {
2914     "JAN", "FEB", "MAR", "APR", "MAY", "JUN",
2915     "JUL", "AUG", "SEP", "OCT", "NOV", "DEC"
2916   };
2917   static int video_pos[10][2][4] =
2918   {
2919     VIDEO_PLAY_LABEL_XPOS, VIDEO_PLAY_LABEL_YPOS,
2920     VIDEO_PLAY_LABEL_XSIZE,VIDEO_PLAY_LABEL_YSIZE,
2921     VIDEO_PLAY_SYMBOL_XPOS, VIDEO_PLAY_SYMBOL_YPOS,
2922     VIDEO_PLAY_SYMBOL_XSIZE,VIDEO_PLAY_SYMBOL_YSIZE,
2923
2924     VIDEO_REC_LABEL_XPOS, VIDEO_REC_LABEL_YPOS,
2925     VIDEO_REC_LABEL_XSIZE,VIDEO_REC_LABEL_YSIZE,
2926     VIDEO_REC_SYMBOL_XPOS, VIDEO_REC_SYMBOL_YPOS,
2927     VIDEO_REC_SYMBOL_XSIZE,VIDEO_REC_SYMBOL_YSIZE,
2928
2929     VIDEO_PAUSE_LABEL_XPOS, VIDEO_PAUSE_LABEL_YPOS,
2930     VIDEO_PAUSE_LABEL_XSIZE,VIDEO_PAUSE_LABEL_YSIZE,
2931     VIDEO_PAUSE_SYMBOL_XPOS, VIDEO_PAUSE_SYMBOL_YPOS,
2932     VIDEO_PAUSE_SYMBOL_XSIZE,VIDEO_PAUSE_SYMBOL_YSIZE,
2933
2934     VIDEO_DATE_LABEL_XPOS, VIDEO_DATE_LABEL_YPOS,
2935     VIDEO_DATE_LABEL_XSIZE,VIDEO_DATE_LABEL_YSIZE,
2936     VIDEO_DATE_XPOS, VIDEO_DATE_YPOS,
2937     VIDEO_DATE_XSIZE,VIDEO_DATE_YSIZE,
2938
2939     0,0,
2940     0,0,
2941     VIDEO_TIME_XPOS, VIDEO_TIME_YPOS,
2942     VIDEO_TIME_XSIZE,VIDEO_TIME_YSIZE,
2943
2944     VIDEO_BUTTON_PLAY_XPOS, VIDEO_BUTTON_ANY_YPOS,
2945     VIDEO_BUTTON_XSIZE,VIDEO_BUTTON_YSIZE,
2946     0,0,
2947     0,0,
2948
2949     VIDEO_BUTTON_REC_XPOS, VIDEO_BUTTON_ANY_YPOS,
2950     VIDEO_BUTTON_XSIZE,VIDEO_BUTTON_YSIZE,
2951     0,0,
2952     0,0,
2953
2954     VIDEO_BUTTON_PAUSE_XPOS, VIDEO_BUTTON_ANY_YPOS,
2955     VIDEO_BUTTON_XSIZE,VIDEO_BUTTON_YSIZE,
2956     0,0,
2957     0,0,
2958
2959     VIDEO_BUTTON_STOP_XPOS, VIDEO_BUTTON_ANY_YPOS,
2960     VIDEO_BUTTON_XSIZE,VIDEO_BUTTON_YSIZE,
2961     0,0,
2962     0,0,
2963
2964     VIDEO_BUTTON_EJECT_XPOS, VIDEO_BUTTON_ANY_YPOS,
2965     VIDEO_BUTTON_XSIZE,VIDEO_BUTTON_YSIZE,
2966     0,0,
2967     0,0
2968   };
2969
2970   for(i=0;i<20;i++)
2971   {
2972     if (state & (1<<i))
2973     {
2974       int pos = i/2, cx, cy = DOOR_GFX_PAGEY2;
2975
2976       if (i%2)                  /* i ungerade => STATE_ON / PRESS_OFF */
2977         cx = DOOR_GFX_PAGEX4;
2978       else
2979         cx = DOOR_GFX_PAGEX3;   /* i gerade => STATE_OFF / PRESS_ON */
2980
2981       if (video_pos[pos][part1][0])
2982         XCopyArea(display,pix[PIX_DOOR],drawto,gc,
2983                   cx + video_pos[pos][part1][xpos],
2984                   cy + video_pos[pos][part1][ypos],
2985                   video_pos[pos][part1][xsize],
2986                   video_pos[pos][part1][ysize],
2987                   VX + video_pos[pos][part1][xpos],
2988                   VY + video_pos[pos][part1][ypos]);
2989       if (video_pos[pos][part2][0])
2990         XCopyArea(display,pix[PIX_DOOR],drawto,gc,
2991                   cx + video_pos[pos][part2][xpos],
2992                   cy + video_pos[pos][part2][ypos],
2993                   video_pos[pos][part2][xsize],
2994                   video_pos[pos][part2][ysize],
2995                   VX + video_pos[pos][part2][xpos],
2996                   VY + video_pos[pos][part2][ypos]);
2997     }
2998   }
2999
3000   if (state & VIDEO_STATE_DATE_ON)
3001   {
3002     int tag = value % 100;
3003     int monat = (value/100) % 100;
3004     int jahr = (value/10000);
3005
3006     DrawText(VX+VIDEO_DATE_XPOS,VY+VIDEO_DATE_YPOS,
3007              int2str(tag,2),FS_SMALL,FC_SPECIAL1);
3008     DrawText(VX+VIDEO_DATE_XPOS+27,VY+VIDEO_DATE_YPOS,
3009              monatsname[monat],FS_SMALL,FC_SPECIAL1);
3010     DrawText(VX+VIDEO_DATE_XPOS+64,VY+VIDEO_DATE_YPOS,
3011              int2str(jahr,2),FS_SMALL,FC_SPECIAL1);
3012   }
3013
3014   if (state & VIDEO_STATE_TIME_ON)
3015   {
3016     int min = value / 60;
3017     int sec = value % 60;
3018
3019     DrawText(VX+VIDEO_TIME_XPOS,VY+VIDEO_TIME_YPOS,
3020              int2str(min,2),FS_SMALL,FC_SPECIAL1);
3021     DrawText(VX+VIDEO_TIME_XPOS+27,VY+VIDEO_TIME_YPOS,
3022              int2str(sec,2),FS_SMALL,FC_SPECIAL1);
3023   }
3024
3025   if (state & VIDEO_STATE_DATE)
3026     redraw_mask |= REDRAW_VIDEO_1;
3027   if ((state & ~VIDEO_STATE_DATE) & VIDEO_STATE)
3028     redraw_mask |= REDRAW_VIDEO_2;
3029   if (state & VIDEO_PRESS)
3030     redraw_mask |= REDRAW_VIDEO_3;
3031 }
3032
3033 void DrawSoundDisplay(unsigned int state)
3034 {
3035   int pos, cx = DOOR_GFX_PAGEX4, cy = 0;
3036
3037   pos = (state & BUTTON_SOUND_MUSIC ? SOUND_BUTTON_MUSIC_XPOS :
3038          state & BUTTON_SOUND_LOOPS ? SOUND_BUTTON_LOOPS_XPOS :
3039          SOUND_BUTTON_SOUND_XPOS);
3040
3041   if (state & BUTTON_ON)
3042     cy -= SOUND_BUTTON_YSIZE;
3043
3044   if (state & BUTTON_PRESSED)
3045     cx = DOOR_GFX_PAGEX3;
3046
3047   XCopyArea(display,pix[PIX_DOOR],drawto,gc,
3048             cx + pos,cy + SOUND_BUTTON_ANY_YPOS,
3049             SOUND_BUTTON_XSIZE,SOUND_BUTTON_YSIZE,
3050             DX + pos,DY + SOUND_BUTTON_ANY_YPOS);
3051
3052   redraw_mask |= REDRAW_DOOR_1;
3053 }
3054
3055 void DrawGameButton(unsigned int state)
3056 {
3057   int pos, cx = DOOR_GFX_PAGEX4, cy = -GAME_BUTTON_YSIZE;
3058
3059   pos = (state & BUTTON_GAME_STOP ? GAME_BUTTON_STOP_XPOS :
3060          state & BUTTON_GAME_PAUSE ? GAME_BUTTON_PAUSE_XPOS :
3061          GAME_BUTTON_PLAY_XPOS);
3062
3063   if (state & BUTTON_PRESSED)
3064     cx = DOOR_GFX_PAGEX3;
3065
3066   XCopyArea(display,pix[PIX_DOOR],drawto,gc,
3067             cx + pos,cy + GAME_BUTTON_ANY_YPOS,
3068             GAME_BUTTON_XSIZE,GAME_BUTTON_YSIZE,
3069             DX + pos,DY + GAME_BUTTON_ANY_YPOS);
3070
3071   redraw_mask |= REDRAW_DOOR_1;
3072 }
3073
3074 void DrawChooseButton(unsigned int state)
3075 {
3076   int pos, cx = DOOR_GFX_PAGEX4, cy = 0;
3077
3078   pos = (state & BUTTON_OK ? OK_BUTTON_XPOS : NO_BUTTON_XPOS);
3079
3080   if (state & BUTTON_PRESSED)
3081     cx = DOOR_GFX_PAGEX3;
3082
3083   XCopyArea(display,pix[PIX_DOOR],drawto,gc,
3084             cx + pos,cy + OK_BUTTON_GFX_YPOS,
3085             OK_BUTTON_XSIZE,OK_BUTTON_YSIZE,
3086             DX + pos,DY + OK_BUTTON_YPOS);
3087
3088   redraw_mask |= REDRAW_DOOR_1;
3089 }
3090
3091 void DrawConfirmButton(unsigned int state)
3092 {
3093   int cx = DOOR_GFX_PAGEX4, cy = 0;
3094
3095   if (state & BUTTON_PRESSED)
3096     cx = DOOR_GFX_PAGEX3;
3097
3098   XCopyArea(display,pix[PIX_DOOR],drawto,gc,
3099             cx + CONFIRM_BUTTON_XPOS,cy + CONFIRM_BUTTON_GFX_YPOS,
3100             CONFIRM_BUTTON_XSIZE,CONFIRM_BUTTON_YSIZE,
3101             DX + CONFIRM_BUTTON_XPOS,DY + CONFIRM_BUTTON_YPOS);
3102
3103   redraw_mask |= REDRAW_DOOR_1;
3104 }