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