1327e4e58acc2a057f47c1e544e61cb41f72250b
[rocksndiamonds.git] / src / tools.c
1 /***********************************************************
2 *  Rocks'n'Diamonds -- McDuffin Strikes Back!              *
3 *----------------------------------------------------------*
4 *  (c) 1995-98 Artsoft Entertainment                       *
5 *              Holger Schemel                              *
6 *              Oststrasse 11a                              *
7 *              33604 Bielefeld                             *
8 *              phone: ++49 +521 290471                     *
9 *              email: aeglos@valinor.owl.de                *
10 *----------------------------------------------------------*
11 *  tools.c                                                 *
12 ***********************************************************/
13
14 #ifdef __FreeBSD__
15 #include <machine/joystick.h>
16 #endif
17
18 #include "tools.h"
19 #include "game.h"
20 #include "events.h"
21 #include "sound.h"
22 #include "misc.h"
23 #include "buttons.h"
24 #include "joystick.h"
25 #include "cartoons.h"
26
27 #include <math.h>
28
29 #ifdef MSDOS
30 extern BOOL wait_for_vsync;
31 #endif
32
33 void SetDrawtoField(int mode)
34 {
35   if (mode == DRAW_BUFFERED && soft_scrolling_on)
36   {
37     FX = TILEX;
38     FY = TILEY;
39     BX1 = -1;
40     BY1 = -1;
41     BX2 = SCR_FIELDX;
42     BY2 = SCR_FIELDY;
43     redraw_x1 = 1;
44     redraw_y1 = 1;
45
46     drawto_field = fieldbuffer;
47   }
48   else  /* DRAW_DIRECT, DRAW_BACKBUFFER */
49   {
50     FX = SX;
51     FY = SY;
52     BX1 = 0;
53     BY1 = 0;
54     BX2 = SCR_FIELDX - 1;
55     BY2 = SCR_FIELDY - 1;
56     redraw_x1 = 0;
57     redraw_y1 = 0;
58
59     drawto_field = (mode == DRAW_DIRECT ? window :  backbuffer);
60   }
61 }
62
63 void BackToFront()
64 {
65   int x,y;
66   Drawable buffer = (drawto_field != window ? drawto_field : backbuffer);
67
68   if (direct_draw_on && game_status == PLAYING)
69     redraw_mask &= ~REDRAW_MAIN;
70
71   if (redraw_mask & REDRAW_TILES && redraw_tiles > REDRAWTILES_THRESHOLD)
72     redraw_mask |= REDRAW_FIELD;
73
74   if (redraw_mask & REDRAW_FIELD || ScreenGfxPos)
75     redraw_mask &= ~REDRAW_TILES;
76
77   if (!redraw_mask)
78     return;
79
80   /* synchronize X11 graphics at this point; if we would synchronize the
81      display immediately after the buffer switching (after the XFlush),
82      this could mean that we have to wait for the graphics to complete,
83      although we could go on doing calculations for the next frame */
84
85   XSync(display,FALSE);
86
87 #ifdef MSDOS
88   wait_for_vsync = TRUE;
89 #endif
90
91   if (redraw_mask & REDRAW_ALL)
92   {
93     XCopyArea(display,backbuffer,window,gc,
94               0,0, WIN_XSIZE,WIN_YSIZE,
95               0,0);
96     redraw_mask = 0;
97   }
98
99   if (redraw_mask & REDRAW_FIELD)
100   {
101     if (game_status != PLAYING || redraw_mask & REDRAW_FROM_BACKBUFFER)
102       XCopyArea(display,backbuffer,window,gc,
103                 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
104                 REAL_SX,REAL_SY);
105     else
106     {
107       int fx = FX, fy = FY;
108
109       if (soft_scrolling_on)
110       {
111         fx += (ScreenMovDir & (MV_LEFT|MV_RIGHT) ? ScreenGfxPos : 0);
112         fy += (ScreenMovDir & (MV_UP|MV_DOWN)    ? ScreenGfxPos : 0);
113       }
114
115       XCopyArea(display,buffer,window,gc,
116                 fx,fy, SXSIZE,SYSIZE,
117                 SX,SY);
118     }
119     redraw_mask &= ~REDRAW_MAIN;
120   }
121
122   if (redraw_mask & REDRAW_DOORS)
123   {
124     if (redraw_mask & REDRAW_DOOR_1)
125       XCopyArea(display,backbuffer,window,gc,
126                 DX,DY, DXSIZE,DYSIZE,
127                 DX,DY);
128     if (redraw_mask & REDRAW_DOOR_2)
129     {
130       if ((redraw_mask & REDRAW_DOOR_2) == REDRAW_DOOR_2)
131         XCopyArea(display,backbuffer,window,gc,
132                   VX,VY, VXSIZE,VYSIZE,
133                   VX,VY);
134       else
135       {
136         if (redraw_mask & REDRAW_VIDEO_1)
137           XCopyArea(display,backbuffer,window,gc,
138                     VX+VIDEO_DISPLAY1_XPOS,VY+VIDEO_DISPLAY1_YPOS,
139                     VIDEO_DISPLAY_XSIZE,VIDEO_DISPLAY_YSIZE,
140                     VX+VIDEO_DISPLAY1_XPOS,VY+VIDEO_DISPLAY1_YPOS);
141         if (redraw_mask & REDRAW_VIDEO_2)
142           XCopyArea(display,backbuffer,window,gc,
143                     VX+VIDEO_DISPLAY2_XPOS,VY+VIDEO_DISPLAY2_YPOS,
144                     VIDEO_DISPLAY_XSIZE,VIDEO_DISPLAY_YSIZE,
145                     VX+VIDEO_DISPLAY2_XPOS,VY+VIDEO_DISPLAY2_YPOS);
146         if (redraw_mask & REDRAW_VIDEO_3)
147           XCopyArea(display,backbuffer,window,gc,
148                     VX+VIDEO_CONTROL_XPOS,VY+VIDEO_CONTROL_YPOS,
149                     VIDEO_CONTROL_XSIZE,VIDEO_CONTROL_YSIZE,
150                     VX+VIDEO_CONTROL_XPOS,VY+VIDEO_CONTROL_YPOS);
151       }
152     }
153     redraw_mask &= ~REDRAW_DOORS;
154   }
155
156   if (redraw_mask & REDRAW_MICROLEV)
157   {
158     XCopyArea(display,backbuffer,window,gc,
159               MICROLEV_XPOS,MICROLEV_YPOS, MICROLEV_XSIZE,MICROLEV_YSIZE,
160               MICROLEV_XPOS,MICROLEV_YPOS);
161     XCopyArea(display,backbuffer,window,gc,
162               SX,MICROLABEL_YPOS, SXSIZE,FONT4_YSIZE,
163               SX,MICROLABEL_YPOS);
164     redraw_mask &= ~REDRAW_MICROLEV;
165   }
166
167   if (redraw_mask & REDRAW_TILES)
168   {
169     for(x=0; x<SCR_FIELDX; x++)
170       for(y=0; y<SCR_FIELDY; y++)
171         if (redraw[redraw_x1 + x][redraw_y1 + y])
172           XCopyArea(display,buffer,window,gc,
173                     FX+x*TILEX,FX+y*TILEY, TILEX,TILEY,
174                     SX+x*TILEX,SY+y*TILEY);
175   }
176
177   XFlush(display);
178
179   for(x=0; x<MAX_BUF_XSIZE; x++)
180     for(y=0; y<MAX_BUF_YSIZE; y++)
181       redraw[x][y] = 0;
182   redraw_tiles = 0;
183   redraw_mask = 0;
184 }
185
186 void FadeToFront()
187 {
188 /*
189   long fading_delay = 300;
190
191   if (fading_on && (redraw_mask & REDRAW_FIELD))
192   {
193 */
194
195 /*
196     int x,y;
197
198     XFillRectangle(display,window,gc,
199                    REAL_SX,REAL_SY,FULL_SXSIZE,FULL_SYSIZE);
200     XFlush(display);
201
202     for(i=0;i<2*FULL_SYSIZE;i++)
203     {
204       for(y=0;y<FULL_SYSIZE;y++)
205       {
206         XCopyArea(display,backbuffer,window,gc,
207                   REAL_SX,REAL_SY+i, FULL_SXSIZE,1, REAL_SX,REAL_SY+i);
208       }
209       XFlush(display);
210       Delay(10);
211     }
212 */
213
214 /*
215     for(i=1;i<FULL_SYSIZE;i+=2)
216       XCopyArea(display,backbuffer,window,gc,
217                 REAL_SX,REAL_SY+i, FULL_SXSIZE,1, REAL_SX,REAL_SY+i);
218     XFlush(display);
219     Delay(fading_delay);
220 */
221
222 /*
223     XSetClipOrigin(display,clip_gc[PIX_FADEMASK],0,0);
224     XCopyArea(display,backbuffer,window,clip_gc[PIX_FADEMASK],
225               REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE, REAL_SX,REAL_SY);
226     XFlush(display);
227     Delay(fading_delay);
228
229     XSetClipOrigin(display,clip_gc[PIX_FADEMASK],-1,-1);
230     XCopyArea(display,backbuffer,window,clip_gc[PIX_FADEMASK],
231               REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE, REAL_SX,REAL_SY);
232     XFlush(display);
233     Delay(fading_delay);
234
235     XSetClipOrigin(display,clip_gc[PIX_FADEMASK],0,-1);
236     XCopyArea(display,backbuffer,window,clip_gc[PIX_FADEMASK],
237               REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE, REAL_SX,REAL_SY);
238     XFlush(display);
239     Delay(fading_delay);
240
241     XSetClipOrigin(display,clip_gc[PIX_FADEMASK],-1,0);
242     XCopyArea(display,backbuffer,window,clip_gc[PIX_FADEMASK],
243               REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE, REAL_SX,REAL_SY);
244     XFlush(display);
245     Delay(fading_delay);
246
247     redraw_mask &= ~REDRAW_MAIN;
248   }
249 */
250
251   BackToFront();
252 }
253
254 void ClearWindow()
255 {
256   XFillRectangle(display,backbuffer,gc,
257                  REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE);
258
259   if (soft_scrolling_on && game_status==PLAYING)
260   {
261     XFillRectangle(display,fieldbuffer,gc,
262                    0,0, FXSIZE,FYSIZE);
263     SetDrawtoField(DRAW_BUFFERED);
264   }
265   else
266     SetDrawtoField(DRAW_BACKBUFFER);
267
268   if (direct_draw_on && game_status==PLAYING)
269   {
270     XFillRectangle(display,window,gc,
271                    REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE);
272     SetDrawtoField(DRAW_DIRECT);
273   }
274
275   redraw_mask |= REDRAW_FIELD;
276 }
277
278 void DrawText(int x, int y, char *text, int font, int col)
279 {
280   DrawTextExt(drawto, gc, x, y, text, font, col);
281   if (x < DX)
282     redraw_mask |= REDRAW_FIELD;
283   else if (y < VY)
284     redraw_mask |= REDRAW_DOOR_1;
285 }
286
287 void DrawTextExt(Drawable d, GC gc, int x, int y,
288                  char *text, int font, int font_color)
289 {
290   int font_width, font_height, font_start;
291   int font_pixmap;
292
293   if (font!=FS_SMALL && font!=FS_BIG)
294     font = FS_SMALL;
295   if (font_color<FC_RED || font_color>FC_SPECIAL2)
296     font_color = FC_RED;
297
298   font_width =
299     (font==FS_BIG ? FONT1_XSIZE :
300      font_color<FC_SPECIAL1 ? FONT2_XSIZE :
301      font_color<FC_SPECIAL2 ? FONT3_XSIZE : FONT4_XSIZE);
302   font_height =
303     (font==FS_BIG ? FONT1_XSIZE :
304      font_color<FC_SPECIAL2 ? FONT2_XSIZE: FONT4_XSIZE);
305   font_pixmap = (font==FS_BIG ? PIX_BIGFONT : PIX_SMALLFONT);
306   font_start =
307     font_color*(font==FS_BIG ? FONT1_YSIZE : FONT2_YSIZE)*FONT_LINES_PER_FONT;
308
309   while(*text)
310   {
311     char c = *text++;
312
313     if (c>='a' && c<='z')
314       c = 'A' + (c - 'a');
315     else if (c=='ä' || c=='Ä')
316       c = 91;
317     else if (c=='ö' || c=='Ö')
318       c = 92;
319     else if (c=='ü' || c=='Ãœ')
320       c = 93;
321
322     if (c>=32 && c<=95)
323       XCopyArea(display,pix[font_pixmap],d,gc,
324                 ((c-32) % FONT_CHARS_PER_LINE)*font_width,
325                 ((c-32) / FONT_CHARS_PER_LINE)*font_height + font_start,
326                 font_width,font_height, x,y);
327
328     x += font_width;
329   }
330 }
331
332 void DrawAllPlayers()
333 {
334   int i;
335
336   for(i=0; i<MAX_PLAYERS; i++)
337     if (stored_player[i].active)
338       DrawPlayer(&stored_player[i]);
339 }
340
341 void DrawPlayerField(int x, int y)
342 {
343   if (!IS_PLAYER(x,y))
344     return;
345
346   DrawPlayer(PLAYERINFO(x,y));
347 }
348
349 void DrawPlayer(struct PlayerInfo *player)
350 {
351   int jx = player->jx, jy = player->jy;
352   int last_jx = player->last_jx, last_jy = player->last_jy;
353   int next_jx = jx + (jx - last_jx), next_jy = jy + (jy - last_jy);
354   int sx = SCREENX(jx), sy = SCREENY(jy);
355   int sxx = 0, syy = 0;
356   int element = Feld[jx][jy];
357   int graphic, phase;
358
359   /*
360   if (!player->active || player->gone || !IN_SCR_FIELD(sx,sy))
361     return;
362   */
363
364   if (!player->active || player->gone ||
365       !IN_SCR_FIELD(SCREENX(last_jx),SCREENY(last_jy)))
366     return;
367
368 #if DEBUG
369   if (!IN_LEV_FIELD(jx,jy))
370   {
371     printf("DrawPlayerField(): x = %d, y = %d\n",jx,jy);
372     printf("DrawPlayerField(): sx = %d, sy = %d\n",sx,sy);
373     printf("DrawPlayerField(): This should never happen!\n");
374     return;
375   }
376 #endif
377
378   if (element == EL_EXPLODING)
379     return;
380
381   /* draw things in the field the player is leaving, if needed */
382
383   if (last_jx != jx || last_jy != jy)
384   {
385     if (Store[last_jx][last_jy])
386     {
387       DrawLevelElement(last_jx,last_jy, Store[last_jx][last_jy]);
388       DrawLevelFieldThruMask(last_jx,last_jy);
389     }
390     else if (Feld[last_jx][last_jy] == EL_DYNAMIT)
391       DrawDynamite(last_jx,last_jy);
392     else
393       DrawLevelField(last_jx,last_jy);
394
395     if (player->Pushing && IN_SCR_FIELD(SCREENX(next_jx),SCREENY(next_jy)))
396     {
397       if (player->GfxPos)
398       {
399         if (Feld[next_jx][next_jy] == EL_SOKOBAN_FELD_VOLL)
400           DrawLevelElement(next_jx,next_jy, EL_SOKOBAN_FELD_LEER);
401         else
402           DrawLevelElement(next_jx,next_jy, EL_LEERRAUM);
403       }
404       else
405         DrawLevelField(next_jx,next_jy);
406     }
407   }
408
409   if (!IN_SCR_FIELD(sx,sy))
410     return;
411
412   if (direct_draw_on)
413     SetDrawtoField(DRAW_BUFFERED);
414
415   /* draw things behind the player, if needed */
416
417   if (Store[jx][jy])
418     DrawLevelElement(jx,jy, Store[jx][jy]);
419   else if (element != EL_DYNAMIT && element != EL_DYNABOMB)
420     DrawLevelField(jx,jy);
421
422   /* draw player himself */
423
424   if (player->MovDir==MV_LEFT)
425     graphic = (player->Pushing ? GFX_SPIELER1_PUSH_LEFT : GFX_SPIELER1_LEFT);
426   else if (player->MovDir==MV_RIGHT)
427     graphic = (player->Pushing ? GFX_SPIELER1_PUSH_RIGHT : GFX_SPIELER1_RIGHT);
428   else if (player->MovDir==MV_UP)
429     graphic = GFX_SPIELER1_UP;
430   else  /* MV_DOWN || MV_NO_MOVING */
431     graphic = GFX_SPIELER1_DOWN;
432
433   graphic += player->index_nr * 3*HEROES_PER_LINE;
434   graphic += player->Frame;
435
436   if (player->GfxPos)
437   {
438     if (player->MovDir == MV_LEFT || player->MovDir == MV_RIGHT)
439       sxx = player->GfxPos;
440     else
441       syy = player->GfxPos;
442   }
443
444   if (!soft_scrolling_on && ScreenMovPos)
445     sxx = syy = 0;
446
447   DrawGraphicShiftedThruMask(sx,sy, sxx,syy, graphic, NO_CUTTING);
448
449   if (player->Pushing && player->GfxPos)
450   {
451     int px = SCREENX(next_jx), py = SCREENY(next_jy);
452
453     if (Feld[jx][jy] == EL_SOKOBAN_FELD_LEER ||
454         Feld[next_jx][next_jy] == EL_SOKOBAN_FELD_VOLL)
455       DrawGraphicShiftedThruMask(px,py,sxx,syy, GFX_SOKOBAN_OBJEKT,NO_CUTTING);
456     else
457     {
458       int element = Feld[next_jx][next_jy];
459       int graphic = el2gfx(element);
460
461       if (element == EL_FELSBROCKEN && sxx)
462       {
463         int phase = (player->GfxPos / (TILEX/4));
464
465         if (player->MovDir == MV_LEFT)
466           graphic += phase;
467         else
468           graphic += (phase+4)%4;
469       }
470
471       DrawGraphicShifted(px,py, sxx,syy, graphic, NO_CUTTING, NO_MASKING);
472     }
473   }
474
475   /* draw things in front of player (EL_DYNAMIT || EL_DYNABOMB) */
476
477   if (element == EL_DYNAMIT || element == EL_DYNABOMB)
478   {
479     graphic = el2gfx(element);
480
481     if (element == EL_DYNAMIT)
482     {
483       if ((phase = (96-MovDelay[jx][jy])/12) > 6)
484         phase = 6;
485     }
486     else
487     {
488       if ((phase = ((96-MovDelay[jx][jy])/6) % 8) > 3)
489         phase = 7-phase;
490     }
491
492     DrawGraphicThruMask(sx,sy, graphic + phase);
493   }
494
495   if ((last_jx != jx || last_jy != jy) && Feld[last_jx][last_jy]==EL_EXPLODING)
496   {
497     int phase = Frame[last_jx][last_jy];
498     int delay = 2;
499
500     if (phase > 2)
501       DrawGraphicThruMask(SCREENX(last_jx),SCREENY(last_jy),
502                           GFX_EXPLOSION + ((phase-1)/delay-1));
503   }
504
505   if (direct_draw_on)
506   {
507     int dest_x = SX + SCREENX(MIN(jx,last_jx))*TILEX;
508     int dest_y = SY + SCREENY(MIN(jy,last_jy))*TILEY;
509     int x_size = TILEX * (1 + ABS(jx - last_jx));
510     int y_size = TILEY * (1 + ABS(jy - last_jy));
511
512     XCopyArea(display,drawto_field,window,gc,
513               dest_x,dest_y, x_size,y_size, dest_x,dest_y);
514     SetDrawtoField(DRAW_DIRECT);
515   }
516
517   MarkTileDirty(sx,sy);
518 }
519
520 static int getGraphicAnimationPhase(int frames, int delay, int mode)
521 {
522   int phase;
523
524   if (mode == ANIM_OSCILLATE)
525   {
526     int max_anim_frames = frames*2 - 2;
527     phase = (FrameCounter % (delay * max_anim_frames)) / delay;
528     phase = (phase < frames ? phase : max_anim_frames - phase);
529   }
530   else
531     phase = (FrameCounter % (delay * frames)) / delay;
532
533   if (mode == ANIM_REVERSE)
534     phase = -phase;
535
536   return(phase);
537 }
538
539 void DrawGraphicAnimationExt(int x, int y, int graphic,
540                              int frames, int delay, int mode, int mask_mode)
541 {
542   int phase = getGraphicAnimationPhase(frames, delay, mode);
543
544   if (!(FrameCounter % delay) && IN_SCR_FIELD(SCREENX(x),SCREENY(y)))
545   {
546     if (mask_mode == USE_MASKING)
547       DrawGraphicThruMask(SCREENX(x),SCREENY(y), graphic + phase);
548     else
549       DrawGraphic(SCREENX(x),SCREENY(y), graphic + phase);
550   }
551 }
552
553 void DrawGraphicAnimation(int x, int y, int graphic,
554                           int frames, int delay, int mode)
555 {
556   DrawGraphicAnimationExt(x,y, graphic, frames,delay,mode, NO_MASKING);
557 }
558
559 void DrawGraphicAnimationThruMask(int x, int y, int graphic,
560                                   int frames, int delay, int mode)
561 {
562   DrawGraphicAnimationExt(x,y, graphic, frames,delay,mode, USE_MASKING);
563 }
564
565 void DrawGraphic(int x, int y, int graphic)
566 {
567 #if DEBUG
568   if (!IN_SCR_FIELD(x,y))
569   {
570     printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
571     printf("DrawGraphic(): This should never happen!\n");
572     return;
573   }
574 #endif
575
576   DrawGraphicExt(drawto_field, gc, FX+x*TILEX, FY+y*TILEY, graphic);
577   MarkTileDirty(x,y);
578 }
579
580 void DrawGraphicExt(Drawable d, GC gc, int x, int y, int graphic)
581 {
582   if (graphic >= GFX_START_ROCKSSCREEN && graphic <= GFX_END_ROCKSSCREEN)
583   {
584     graphic -= GFX_START_ROCKSSCREEN;
585     XCopyArea(display,pix[PIX_BACK],d,gc,
586               SX + (graphic % GFX_PER_LINE) * TILEX,
587               SY + (graphic / GFX_PER_LINE) * TILEY,
588               TILEX,TILEY, x,y);
589   }
590   else if (graphic >= GFX_START_ROCKSHEROES && graphic <= GFX_END_ROCKSHEROES)
591   {
592     graphic -= GFX_START_ROCKSHEROES;
593     XCopyArea(display,pix[PIX_HEROES],d,gc,
594               (graphic % HEROES_PER_LINE) * TILEX,
595               (graphic / HEROES_PER_LINE) * TILEY,
596               TILEX,TILEY, x,y);
597   }
598   else if (graphic >= GFX_START_ROCKSFONT && graphic <= GFX_END_ROCKSFONT)
599   {
600     graphic -= GFX_START_ROCKSFONT;
601     XCopyArea(display,pix[PIX_BIGFONT],d,gc,
602               (graphic % FONT_CHARS_PER_LINE) * TILEX,
603               (graphic / FONT_CHARS_PER_LINE) * TILEY +
604               FC_SPECIAL1 * FONT_LINES_PER_FONT * TILEY,
605               TILEX,TILEY, x,y);
606   }
607   else
608     XFillRectangle(display,d,gc, x,y, TILEX,TILEY);
609 }
610
611 void DrawGraphicThruMask(int x, int y, int graphic)
612 {
613 #if DEBUG
614   if (!IN_SCR_FIELD(x,y))
615   {
616     printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
617     printf("DrawGraphicThruMask(): This should never happen!\n");
618     return;
619   }
620 #endif
621
622   DrawGraphicThruMaskExt(drawto_field, FX+x*TILEX, FY+y*TILEY, graphic);
623   MarkTileDirty(x,y);
624 }
625
626 void DrawGraphicThruMaskExt(Drawable d, int dest_x, int dest_y, int graphic)
627 {
628   int src_x, src_y;
629   int tile = graphic;
630   Pixmap src_pixmap;
631   GC drawing_gc;
632
633   if (graphic >= GFX_START_ROCKSSCREEN && graphic <= GFX_END_ROCKSSCREEN)
634   {
635     src_pixmap = pix[PIX_BACK];
636     drawing_gc = clip_gc[PIX_BACK];
637     graphic -= GFX_START_ROCKSSCREEN;
638     src_x  = SX+(graphic % GFX_PER_LINE)*TILEX;
639     src_y  = SY+(graphic / GFX_PER_LINE)*TILEY;
640   }
641   else if (graphic >= GFX_START_ROCKSHEROES && graphic <= GFX_END_ROCKSHEROES)
642   {
643     src_pixmap = pix[PIX_HEROES];
644     drawing_gc = clip_gc[PIX_HEROES];
645     graphic -= GFX_START_ROCKSHEROES;
646     src_x  = (graphic % HEROES_PER_LINE)*TILEX;
647     src_y  = (graphic / HEROES_PER_LINE)*TILEY;
648   }
649   else
650   {
651     DrawGraphicExt(d, gc, dest_x,dest_y, graphic);
652     return;
653   }
654
655   if (tile_clipmask[tile] != None)
656   {
657     XSetClipMask(display, tile_clip_gc, tile_clipmask[tile]);
658     XSetClipOrigin(display, tile_clip_gc, dest_x,dest_y);
659     XCopyArea(display, src_pixmap, drawto_field, tile_clip_gc,
660               src_x,src_y, TILEX,TILEY, dest_x,dest_y);
661   }
662   else
663   {
664 #if DEBUG
665     printf("DrawGraphicThruMask(): tile '%d' needs clipping!\n", tile);
666 #endif
667
668     XSetClipOrigin(display, drawing_gc, dest_x-src_x, dest_y-src_y);
669     XCopyArea(display, src_pixmap, drawto_field, drawing_gc,
670               src_x,src_y, TILEX,TILEY, dest_x,dest_y);
671   }
672 }
673
674 void DrawMiniGraphic(int x, int y, int graphic)
675 {
676   DrawMiniGraphicExt(drawto,gc, SX+x*MINI_TILEX,SY+y*MINI_TILEY, graphic);
677   MarkTileDirty(x/2, y/2);
678 }
679
680 void DrawMiniGraphicExt(Drawable d, GC gc, int x, int y, int graphic)
681 {
682   if (graphic >= GFX_START_ROCKSSCREEN && graphic <= GFX_END_ROCKSSCREEN)
683   {
684     graphic -= GFX_START_ROCKSSCREEN;
685     XCopyArea(display,pix[PIX_BACK],d,gc,
686               MINI_GFX_STARTX+(graphic % MINI_GFX_PER_LINE)*MINI_TILEX,
687               MINI_GFX_STARTY+(graphic / MINI_GFX_PER_LINE)*MINI_TILEY,
688               MINI_TILEX,MINI_TILEY, x,y);
689   }
690   else if (graphic >= GFX_START_ROCKSFONT && graphic <= GFX_END_ROCKSFONT)
691   {
692     graphic -= GFX_START_ROCKSFONT;
693     XCopyArea(display,pix[PIX_SMALLFONT],d,gc,
694               (graphic % FONT_CHARS_PER_LINE)*FONT4_XSIZE,
695               (graphic / FONT_CHARS_PER_LINE)*FONT4_YSIZE +
696               FC_SPECIAL2*FONT2_YSIZE*FONT_LINES_PER_FONT,
697               MINI_TILEX,MINI_TILEY, x,y);
698   }
699   else
700     XFillRectangle(display,d,gc, x,y, MINI_TILEX,MINI_TILEY);
701 }
702
703 void DrawGraphicShifted(int x,int y, int dx,int dy, int graphic,
704                         int cut_mode, int mask_mode)
705 {
706   int width = TILEX, height = TILEY;
707   int cx = 0, cy = 0;
708   int src_x,src_y, dest_x,dest_y;
709   int tile = graphic;
710   Pixmap src_pixmap;
711   GC drawing_gc;
712
713   if (graphic < 0)
714   {
715     DrawGraphic(x,y,graphic);
716     return;
717   }
718
719   if (dx || dy)                 /* Verschiebung der Grafik? */
720   {
721     if (x < BX1)                /* Element kommt von links ins Bild */
722     {
723       x = BX1;
724       width = dx;
725       cx = TILEX - dx;
726       dx = 0;
727     }
728     else if (x > BX2)           /* Element kommt von rechts ins Bild */
729     {
730       x = BX2;
731       width = -dx;
732       dx = TILEX + dx;
733     }
734     else if (x==BX1 && dx<0)    /* Element verläßt links das Bild */
735     {
736       width += dx;
737       cx = -dx;
738       dx = 0;
739     }
740     else if (x==BX2 && dx>0)    /* Element verläßt rechts das Bild */
741       width -= dx;
742     else if (dx)                /* allg. Bewegung in x-Richtung */
743       MarkTileDirty(x + SIGN(dx), y);
744
745     if (y < BY1)                /* Element kommt von oben ins Bild */
746     {
747       if (cut_mode==CUT_BELOW)  /* Element oberhalb des Bildes */
748         return;
749
750       y = BY1;
751       height = dy;
752       cy = TILEY - dy;
753       dy = 0;
754     }
755     else if (y > BY2)           /* Element kommt von unten ins Bild */
756     {
757       y = BY2;
758       height = -dy;
759       dy = TILEY + dy;
760     }
761     else if (y==BY1 && dy<0)    /* Element verläßt oben das Bild */
762     {
763       height += dy;
764       cy = -dy;
765       dy = 0;
766     }
767     else if (dy > 0 && cut_mode==CUT_ABOVE)
768     {
769       if (y == BY2)             /* Element unterhalb des Bildes */
770         return;
771
772       height = dy;
773       cy = TILEY-dy;
774       dy = TILEY;
775       MarkTileDirty(x, y + 1);
776     }                           /* Element verläßt unten das Bild */
777     else if (dy > 0 && (y == BY2 || cut_mode==CUT_BELOW))
778       height -= dy;
779     else if (dy)                /* allg. Bewegung in y-Richtung */
780       MarkTileDirty(x, y + SIGN(dy));
781   }
782
783   if (graphic >= GFX_START_ROCKSSCREEN && graphic <= GFX_END_ROCKSSCREEN)
784   {
785     src_pixmap = pix[PIX_BACK];
786     drawing_gc = clip_gc[PIX_BACK];
787     graphic -= GFX_START_ROCKSSCREEN;
788     src_x  = SX+(graphic % GFX_PER_LINE)*TILEX+cx;
789     src_y  = SY+(graphic / GFX_PER_LINE)*TILEY+cy;
790   }
791   else if (graphic >= GFX_START_ROCKSHEROES && graphic <= GFX_END_ROCKSHEROES)
792   {
793     src_pixmap = pix[PIX_HEROES];
794     drawing_gc = clip_gc[PIX_HEROES];
795     graphic -= GFX_START_ROCKSHEROES;
796     src_x  = (graphic % HEROES_PER_LINE)*TILEX+cx;
797     src_y  = (graphic / HEROES_PER_LINE)*TILEY+cy;
798   }
799
800   dest_x = FX + x*TILEX + dx;
801   dest_y = FY + y*TILEY + dy;
802
803 #if DEBUG
804   if (!IN_SCR_FIELD(x,y))
805   {
806     printf("DrawGraphicShifted(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
807     printf("DrawGraphicShifted(): This should never happen!\n");
808     return;
809   }
810 #endif
811
812   if (mask_mode == USE_MASKING)
813   {
814     if (tile_clipmask[tile] != None)
815     {
816       XSetClipMask(display, tile_clip_gc, tile_clipmask[tile]);
817       XSetClipOrigin(display, tile_clip_gc, dest_x,dest_y);
818       XCopyArea(display, src_pixmap, drawto_field, tile_clip_gc,
819                 src_x,src_y, TILEX,TILEY, dest_x,dest_y);
820     }
821     else
822     {
823 #if DEBUG
824       printf("DrawGraphicShifted(): tile '%d' needs clipping!\n", tile);
825 #endif
826
827       XSetClipOrigin(display, drawing_gc, dest_x-src_x, dest_y-src_y);
828       XCopyArea(display, src_pixmap, drawto_field, drawing_gc,
829                 src_x,src_y, width,height, dest_x,dest_y);
830     }
831   }
832   else
833     XCopyArea(display, src_pixmap, drawto_field, gc,
834               src_x,src_y, width,height, dest_x,dest_y);
835
836   MarkTileDirty(x,y);
837 }
838
839 void DrawGraphicShiftedThruMask(int x,int y, int dx,int dy, int graphic,
840                                 int cut_mode)
841 {
842   DrawGraphicShifted(x,y, dx,dy, graphic, cut_mode, USE_MASKING);
843 }
844
845 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
846                           int cut_mode, int mask_mode)
847 {
848   int ux = LEVELX(x), uy = LEVELY(y);
849   int graphic = el2gfx(element);
850   int phase4 = ABS(MovPos[ux][uy])/(TILEX/4);
851   int phase  = phase4 / 2;
852   int dir = MovDir[ux][uy];
853
854   if (element==EL_PACMAN || element==EL_KAEFER || element==EL_FLIEGER)
855   {
856     graphic += 4*!phase;
857
858     if (dir == MV_UP)
859       graphic += 1;
860     else if (dir == MV_LEFT)
861       graphic += 2;
862     else if (dir == MV_DOWN)
863       graphic += 3;
864   }
865   else if (element==EL_MAULWURF || element==EL_PINGUIN ||
866            element==EL_SCHWEIN || element==EL_DRACHE)
867   {
868     if (dir==MV_LEFT)
869       graphic = (element==EL_MAULWURF ? GFX_MAULWURF_LEFT :
870                  element==EL_PINGUIN ? GFX_PINGUIN_LEFT :
871                  element==EL_SCHWEIN ? GFX_SCHWEIN_LEFT : GFX_DRACHE_LEFT);
872     else if (dir==MV_RIGHT)
873       graphic = (element==EL_MAULWURF ? GFX_MAULWURF_RIGHT :
874                  element==EL_PINGUIN ? GFX_PINGUIN_RIGHT :
875                  element==EL_SCHWEIN ? GFX_SCHWEIN_RIGHT : GFX_DRACHE_RIGHT);
876     else if (dir==MV_UP)
877       graphic = (element==EL_MAULWURF ? GFX_MAULWURF_UP :
878                  element==EL_PINGUIN ? GFX_PINGUIN_UP :
879                  element==EL_SCHWEIN ? GFX_SCHWEIN_UP : GFX_DRACHE_UP);
880     else
881       graphic = (element==EL_MAULWURF ? GFX_MAULWURF_DOWN :
882                  element==EL_PINGUIN ? GFX_PINGUIN_DOWN :
883                  element==EL_SCHWEIN ? GFX_SCHWEIN_DOWN : GFX_DRACHE_DOWN);
884
885     graphic += phase4;
886   }
887   else if (element==EL_SONDE)
888   {
889     graphic = GFX_SONDE_START + getGraphicAnimationPhase(8, 2, ANIM_NORMAL);
890   }
891   else if (element==EL_SALZSAEURE)
892   {
893     graphic = GFX_GEBLUBBER + getGraphicAnimationPhase(4, 10, ANIM_NORMAL);
894   }
895   else if (element==EL_BUTTERFLY || element==EL_FIREFLY)
896   {
897     graphic += !phase;
898   }
899   else if ((element==EL_FELSBROCKEN || IS_GEM(element)) && !cut_mode)
900   {
901     graphic += phase * (element==EL_FELSBROCKEN ? 2 : 1);
902   }
903   else if ((element==EL_SIEB_LEER || element==EL_SIEB2_LEER ||
904             element==EL_SIEB_VOLL || element==EL_SIEB2_VOLL) && SiebAktiv)
905   {
906     graphic += 3-(SiebAktiv%8)/2;
907   }
908   else if (IS_AMOEBOID(element))
909   {
910     graphic = (element==EL_AMOEBE_TOT ? GFX_AMOEBE_TOT : GFX_AMOEBE_LEBT);
911     graphic += (x+2*y) % 4;
912   }
913   else if (element==EL_MAUER_LEBT)
914   {
915     BOOL links_massiv = FALSE, rechts_massiv = FALSE;
916
917     if (!IN_LEV_FIELD(ux-1,uy) || IS_MAUER(Feld[ux-1][uy]))
918       links_massiv = TRUE;
919     if (!IN_LEV_FIELD(ux+1,uy) || IS_MAUER(Feld[ux+1][uy]))
920       rechts_massiv = TRUE;
921
922     if (links_massiv && rechts_massiv)
923       graphic = GFX_MAUERWERK;
924     else if (links_massiv)
925       graphic = GFX_MAUER_R;
926     else if (rechts_massiv)
927       graphic = GFX_MAUER_L;
928   }
929
930   if (dx || dy)
931     DrawGraphicShifted(x,y, dx,dy, graphic, cut_mode, mask_mode);
932   else if (mask_mode == USE_MASKING)
933     DrawGraphicThruMask(x,y, graphic);
934   else
935     DrawGraphic(x,y, graphic);
936 }
937
938 void DrawLevelElementExt(int x, int y, int dx, int dy, int element,
939                          int cut_mode, int mask_mode)
940 {
941   if (IN_LEV_FIELD(x,y) && IN_SCR_FIELD(SCREENX(x),SCREENY(y)))
942     DrawScreenElementExt(SCREENX(x),SCREENY(y), dx,dy, element,
943                          cut_mode, mask_mode);
944 }
945
946 void DrawScreenElementShifted(int x, int y, int dx, int dy, int element,
947                               int cut_mode)
948 {
949   DrawScreenElementExt(x,y, dx,dy, element, cut_mode, NO_MASKING);
950 }
951
952 void DrawLevelElementShifted(int x, int y, int dx, int dy, int element,
953                              int cut_mode)
954 {
955   DrawLevelElementExt(x,y, dx,dy, element, cut_mode, NO_MASKING);
956 }
957
958 void DrawScreenElementThruMask(int x, int y, int element)
959 {
960   DrawScreenElementExt(x,y, 0,0, element, NO_CUTTING, USE_MASKING);
961 }
962
963 void DrawLevelElementThruMask(int x, int y, int element)
964 {
965   DrawLevelElementExt(x,y, 0,0, element, NO_CUTTING, USE_MASKING);
966 }
967
968 void DrawLevelFieldThruMask(int x, int y)
969 {
970   DrawLevelElementExt(x,y, 0,0, Feld[x][y], NO_CUTTING, USE_MASKING);
971 }
972
973 void ErdreichAnbroeckeln(int x, int y)
974 {
975   int i, width, height, cx,cy;
976   int ux = LEVELX(x), uy = LEVELY(y);
977   int element, graphic;
978   int snip = 4;
979   static int xy[4][2] =
980   {
981     { 0,-1 },
982     { -1,0 },
983     { +1,0 },
984     { 0,+1 }
985   };
986
987   if (!IN_LEV_FIELD(ux,uy))
988     return;
989
990   element = Feld[ux][uy];
991
992   if (element==EL_ERDREICH)
993   {
994     if (!IN_SCR_FIELD(x,y))
995       return;
996
997     graphic = GFX_ERDENRAND;
998
999     for(i=0;i<4;i++)
1000     {
1001       int uxx,uyy;
1002
1003       uxx = ux+xy[i][0];
1004       uyy = uy+xy[i][1];
1005       if (!IN_LEV_FIELD(uxx,uyy))
1006         element = EL_BETON;
1007       else
1008         element = Feld[uxx][uyy];
1009
1010       if (element==EL_ERDREICH)
1011         continue;
1012
1013       if (i==1 || i==2)
1014       {
1015         width = snip;
1016         height = TILEY;
1017         cx = (i==2 ? TILEX-snip : 0);
1018         cy = 0;
1019       }
1020       else
1021       {
1022         width = TILEX;
1023         height = snip;
1024         cx = 0;
1025         cy = (i==3 ? TILEY-snip : 0);
1026       }
1027
1028       XCopyArea(display,pix[PIX_BACK],drawto_field,gc,
1029                 SX+(graphic % GFX_PER_LINE)*TILEX+cx,
1030                 SY+(graphic / GFX_PER_LINE)*TILEY+cy,
1031                 width,height, FX+x*TILEX+cx,FY+y*TILEY+cy);
1032     }
1033
1034     MarkTileDirty(x,y);
1035   }
1036   else
1037   {
1038     graphic = GFX_ERDENRAND;
1039
1040     for(i=0;i<4;i++)
1041     {
1042       int xx,yy,uxx,uyy;
1043
1044       xx = x+xy[i][0];
1045       yy = y+xy[i][1];
1046       uxx = ux+xy[i][0];
1047       uyy = uy+xy[i][1];
1048
1049       if (!IN_LEV_FIELD(uxx,uyy) || Feld[uxx][uyy]!=EL_ERDREICH ||
1050           !IN_SCR_FIELD(xx,yy))
1051         continue;
1052
1053       if (i==1 || i==2)
1054       {
1055         width = snip;
1056         height = TILEY;
1057         cx = (i==1 ? TILEX-snip : 0);
1058         cy = 0;
1059       }
1060       else
1061       {
1062         width = TILEX;
1063         height = snip;
1064         cx = 0;
1065         cy = (i==0 ? TILEY-snip : 0);
1066       }
1067
1068       XCopyArea(display,pix[PIX_BACK],drawto_field,gc,
1069                 SX+(graphic % GFX_PER_LINE)*TILEX+cx,
1070                 SY+(graphic / GFX_PER_LINE)*TILEY+cy,
1071                 width,height, FX+xx*TILEX+cx,FY+yy*TILEY+cy);
1072
1073       MarkTileDirty(xx,yy);
1074     }
1075   }
1076 }
1077
1078 void DrawScreenElement(int x, int y, int element)
1079 {
1080   DrawScreenElementExt(x,y, 0,0, element, NO_CUTTING, NO_MASKING);
1081   ErdreichAnbroeckeln(x,y);
1082 }
1083
1084 void DrawLevelElement(int x, int y, int element)
1085 {
1086   if (IN_LEV_FIELD(x,y) && IN_SCR_FIELD(SCREENX(x),SCREENY(y)))
1087     DrawScreenElement(SCREENX(x),SCREENY(y),element);
1088 }
1089
1090 void DrawScreenField(int x, int y)
1091 {
1092   int ux = LEVELX(x), uy = LEVELY(y);
1093   int element;
1094
1095   if (!IN_LEV_FIELD(ux,uy))
1096   {
1097     DrawScreenElement(x,y,EL_BETON);
1098     return;
1099   }
1100
1101   element = Feld[ux][uy];
1102
1103   if (IS_MOVING(ux,uy))
1104   {
1105     int horiz_move = (MovDir[ux][uy]==MV_LEFT || MovDir[ux][uy]==MV_RIGHT);
1106     BOOL cut_mode = NO_CUTTING;
1107
1108     if (Store[ux][uy]==EL_MORAST_LEER ||
1109         Store[ux][uy]==EL_SIEB_LEER ||
1110         Store[ux][uy]==EL_SIEB2_LEER ||
1111         Store[ux][uy]==EL_AMOEBE_NASS)
1112       cut_mode = CUT_ABOVE;
1113     else if (Store[ux][uy]==EL_MORAST_VOLL ||
1114              Store[ux][uy]==EL_SIEB_VOLL ||
1115              Store[ux][uy]==EL_SIEB2_VOLL)
1116       cut_mode = CUT_BELOW;
1117
1118     if (cut_mode==CUT_ABOVE)
1119       DrawScreenElementShifted(x,y, 0,0, Store[ux][uy], NO_CUTTING);
1120     else
1121       DrawScreenElement(x,y,EL_LEERRAUM);
1122
1123     if (horiz_move)
1124       DrawScreenElementShifted(x,y, MovPos[ux][uy],0, element, NO_CUTTING);
1125     else
1126       DrawScreenElementShifted(x,y, 0,MovPos[ux][uy], element, cut_mode);
1127
1128     if (Store[ux][uy] == EL_SALZSAEURE)
1129       DrawLevelElementThruMask(ux,uy+1, EL_SALZSAEURE);
1130   }
1131   else if (IS_BLOCKED(ux,uy))
1132   {
1133     int oldx,oldy;
1134     int sx, sy;
1135     int horiz_move;
1136     BOOL cut_mode = NO_CUTTING;
1137
1138     Blocked2Moving(ux,uy,&oldx,&oldy);
1139     sx = SCREENX(oldx);
1140     sy = SCREENY(oldy);
1141     horiz_move = (MovDir[oldx][oldy]==MV_LEFT || MovDir[oldx][oldy]==MV_RIGHT);
1142
1143     if (Store[oldx][oldy]==EL_MORAST_LEER ||
1144         Store[oldx][oldy]==EL_SIEB_LEER ||
1145         Store[oldx][oldy]==EL_SIEB2_LEER ||
1146         Store[oldx][oldy]==EL_AMOEBE_NASS)
1147       cut_mode = CUT_ABOVE;
1148
1149     DrawScreenElement(x,y,EL_LEERRAUM);
1150     element = Feld[oldx][oldy];
1151
1152     if (horiz_move)
1153       DrawScreenElementShifted(sx,sy, MovPos[oldx][oldy],0,element,NO_CUTTING);
1154     else
1155       DrawScreenElementShifted(sx,sy, 0,MovPos[oldx][oldy],element,cut_mode);
1156   }
1157   else if (IS_DRAWABLE(element))
1158     DrawScreenElement(x,y,element);
1159   else
1160     DrawScreenElement(x,y,EL_LEERRAUM);
1161 }
1162
1163 void DrawLevelField(int x, int y)
1164 {
1165   if (IN_SCR_FIELD(SCREENX(x),SCREENY(y)))
1166     DrawScreenField(SCREENX(x),SCREENY(y));
1167   else if (IS_MOVING(x,y))
1168   {
1169     int newx,newy;
1170
1171     Moving2Blocked(x,y,&newx,&newy);
1172     if (IN_SCR_FIELD(SCREENX(newx),SCREENY(newy)))
1173       DrawScreenField(SCREENX(newx),SCREENY(newy));
1174   }
1175   else if (IS_BLOCKED(x,y))
1176   {
1177     int oldx,oldy;
1178
1179     Blocked2Moving(x,y,&oldx,&oldy);
1180     if (IN_SCR_FIELD(SCREENX(oldx),SCREENY(oldy)))
1181       DrawScreenField(SCREENX(oldx),SCREENY(oldy));
1182   }
1183 }
1184
1185 void DrawMiniElement(int x, int y, int element)
1186 {
1187   int graphic;
1188
1189   if (!element)
1190   {
1191     DrawMiniGraphic(x,y,-1);
1192     return;
1193   }
1194
1195   graphic = el2gfx(element);
1196   DrawMiniGraphic(x,y,graphic);
1197 }
1198
1199 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
1200 {
1201   int x = sx + scroll_x, y = sy + scroll_y;
1202
1203   if (x<-1 || x>lev_fieldx || y<-1 || y>lev_fieldy)
1204     DrawMiniElement(sx,sy,EL_LEERRAUM);
1205   else if (x==-1 || x==lev_fieldx || y==-1 || y==lev_fieldy)
1206     DrawMiniElement(sx,sy,EL_BETON);
1207   else
1208     DrawMiniElement(sx,sy,Feld[x][y]);
1209 }
1210
1211 void DrawMicroElement(int xpos, int ypos, int element)
1212 {
1213   int graphic;
1214
1215   if (element==EL_LEERRAUM)
1216     return;
1217
1218   graphic = el2gfx(element);
1219
1220   XCopyArea(display,pix[PIX_BACK],drawto,gc,
1221             MICRO_GFX_STARTX+(graphic % MICRO_GFX_PER_LINE)*MICRO_TILEX,
1222             MICRO_GFX_STARTY+(graphic / MICRO_GFX_PER_LINE)*MICRO_TILEY,
1223             MICRO_TILEX,MICRO_TILEY, xpos,ypos);
1224 }
1225
1226 void DrawLevel()
1227 {
1228   int x,y;
1229
1230   ClearWindow();
1231
1232   for(x=BX1; x<=BX2; x++)
1233     for(y=BY1; y<=BY2; y++)
1234       DrawScreenField(x,y);
1235
1236   if (soft_scrolling_on)
1237     XCopyArea(display,fieldbuffer,backbuffer,gc,
1238               FX,FY, SXSIZE,SYSIZE,
1239               SX,SY);
1240
1241   redraw_mask |= (REDRAW_FIELD | REDRAW_FROM_BACKBUFFER);
1242 }
1243
1244 void DrawMiniLevel(int scroll_x, int scroll_y)
1245 {
1246   int x,y;
1247
1248   ClearWindow();
1249
1250   for(x=0;x<2*SCR_FIELDX;x++)
1251     for(y=0;y<2*SCR_FIELDY;y++)
1252       DrawMiniElementOrWall(x,y,scroll_x,scroll_y);
1253
1254   redraw_mask |= REDRAW_FIELD;
1255 }
1256
1257 void DrawMicroLevel(int xpos, int ypos)
1258 {
1259   int x,y;
1260
1261   XFillRectangle(display,drawto,gc,
1262                  xpos-MICRO_TILEX,ypos-MICRO_TILEY,
1263                  MICRO_TILEX*(STD_LEV_FIELDX+2),
1264                  MICRO_TILEY*(STD_LEV_FIELDY+2));
1265   if (lev_fieldx < STD_LEV_FIELDX)
1266     xpos += (STD_LEV_FIELDX - lev_fieldx)/2 * MICRO_TILEX;
1267   if (lev_fieldy < STD_LEV_FIELDY)
1268     ypos += (STD_LEV_FIELDY - lev_fieldy)/2 * MICRO_TILEY;
1269
1270   for(x=-1;x<=STD_LEV_FIELDX;x++)
1271     for(y=-1;y<=STD_LEV_FIELDY;y++)
1272       if (x>=0 && x<lev_fieldx && y>=0 && y<lev_fieldy)
1273         DrawMicroElement(xpos+MICRO_TILEX*x,ypos+MICRO_TILEY*y,
1274                          Feld[x][y]=Ur[x][y]);
1275       else if (x>=-1 && x<lev_fieldx+1 && y>=-1 && y<lev_fieldy+1)
1276         DrawMicroElement(xpos+MICRO_TILEX*x,ypos+MICRO_TILEY*y,
1277                          EL_BETON);
1278
1279   XFillRectangle(display,drawto,gc, SX,MICROLABEL_YPOS, SXSIZE,FONT4_YSIZE);
1280
1281   if (level.name)
1282   {
1283     int len = strlen(level.name);
1284     int lxpos = SX+(SXSIZE-len*FONT4_XSIZE)/2;
1285     int lypos = MICROLABEL_YPOS;
1286
1287     DrawText(lxpos,lypos,level.name,FS_SMALL,FC_SPECIAL2);
1288   }
1289
1290   redraw_mask |= REDRAW_MICROLEV;
1291 }
1292
1293 int REQ_in_range(int x, int y)
1294 {
1295   if (y>DY+249 && y<DY+278)
1296   {
1297     if (x>DX+1 && x<DX+48)
1298       return(1);
1299     else if (x>DX+51 && x<DX+98) 
1300       return(2);
1301   }
1302   return(0);
1303 }
1304
1305 BOOL Request(char *text, unsigned int req_state)
1306 {
1307   int mx,my, ty, result = -1;
1308   unsigned int old_door_state;
1309
1310   old_door_state = GetDoorState();
1311
1312   CloseDoor(DOOR_CLOSE_1);
1313
1314   /* Alten Türinhalt sichern */
1315   XCopyArea(display,pix[PIX_DB_DOOR],pix[PIX_DB_DOOR],gc,
1316             DOOR_GFX_PAGEX1,DOOR_GFX_PAGEY1, DXSIZE,DYSIZE,
1317             DOOR_GFX_PAGEX2,DOOR_GFX_PAGEY1);
1318
1319   /* Fragetext schreiben */
1320   XFillRectangle(display,pix[PIX_DB_DOOR],gc,
1321                  DOOR_GFX_PAGEX1,DOOR_GFX_PAGEY1,DXSIZE,DYSIZE);
1322
1323   for(ty=0;ty<13;ty++)
1324   {
1325     int tx,tl,tc;
1326     char txt[256];
1327
1328     if (!(*text))
1329       break;
1330     for(tl=0,tx=0;tx<7;tl++,tx++)
1331     {
1332       tc=*(text+tx);
1333       if (!tc || tc==32)
1334         break;
1335     }
1336     if (!tl)
1337     { 
1338       text++; 
1339       ty--; 
1340       continue; 
1341     }
1342     sprintf(txt,text); 
1343     txt[tl]=0;
1344     DrawTextExt(pix[PIX_DB_DOOR],gc,
1345                 DOOR_GFX_PAGEX1+51-(tl*14)/2,SY+ty*16,txt,FS_SMALL,FC_YELLOW);
1346     text+=(tl+(tc==32));
1347   }
1348
1349   if (req_state & REQ_ASK)
1350     XCopyArea(display,pix[PIX_DOOR],pix[PIX_DB_DOOR],gc,
1351               DOOR_GFX_PAGEX4,OK_BUTTON_GFX_YPOS,
1352               DXSIZE,OK_BUTTON_YSIZE,
1353               DOOR_GFX_PAGEX1,OK_BUTTON_YPOS);
1354   else if (req_state & REQ_CONFIRM)
1355     XCopyArea(display,pix[PIX_DOOR],pix[PIX_DB_DOOR],gc,
1356               DOOR_GFX_PAGEX4,CONFIRM_BUTTON_GFX_YPOS,
1357               DXSIZE,CONFIRM_BUTTON_YSIZE,
1358               DOOR_GFX_PAGEX1,CONFIRM_BUTTON_YPOS);
1359   else if (req_state & REQ_PLAYER)
1360   {
1361     DrawPlayerButton(BUTTON_PLAYER_1, DB_INIT);
1362     DrawPlayerButton(BUTTON_PLAYER_2, DB_INIT);
1363     DrawPlayerButton(BUTTON_PLAYER_3, DB_INIT);
1364     DrawPlayerButton(BUTTON_PLAYER_4, DB_INIT);
1365
1366     /*
1367     XCopyArea(display,pix[PIX_DOOR],pix[PIX_DB_DOOR],gc,
1368               DOOR_GFX_PAGEX4 + PLAYER_BUTTON_GFX_XPOS, PLAYER_BUTTON_GFX_YPOS,
1369               PLAYER_BUTTON_XSIZE,PLAYER_BUTTON_YSIZE,
1370               DOOR_GFX_PAGEX1 + PLAYER_BUTTON_1_XPOS, PLAYER_BUTTON_1_YPOS);
1371     XCopyArea(display,pix[PIX_DOOR],pix[PIX_DB_DOOR],gc,
1372               DOOR_GFX_PAGEX4 + PLAYER_BUTTON_GFX_XPOS, PLAYER_BUTTON_GFX_YPOS,
1373               PLAYER_BUTTON_XSIZE,PLAYER_BUTTON_YSIZE,
1374               DOOR_GFX_PAGEX1 + PLAYER_BUTTON_1_XPOS, PLAYER_BUTTON_1_YPOS);
1375     XCopyArea(display,pix[PIX_DOOR],pix[PIX_DB_DOOR],gc,
1376               DOOR_GFX_PAGEX4 + PLAYER_BUTTON_GFX_XPOS, PLAYER_BUTTON_GFX_YPOS,
1377               PLAYER_BUTTON_XSIZE,PLAYER_BUTTON_YSIZE,
1378               DOOR_GFX_PAGEX1 + PLAYER_BUTTON_2_XPOS, PLAYER_BUTTON_2_YPOS);
1379     XCopyArea(display,pix[PIX_DOOR],pix[PIX_DB_DOOR],gc,
1380               DOOR_GFX_PAGEX4 + PLAYER_BUTTON_GFX_XPOS, PLAYER_BUTTON_GFX_YPOS,
1381               PLAYER_BUTTON_XSIZE,PLAYER_BUTTON_YSIZE,
1382               DOOR_GFX_PAGEX1 + PLAYER_BUTTON_3_XPOS, PLAYER_BUTTON_3_YPOS);
1383     XCopyArea(display,pix[PIX_DOOR],pix[PIX_DB_DOOR],gc,
1384               DOOR_GFX_PAGEX4 + PLAYER_BUTTON_GFX_XPOS, PLAYER_BUTTON_GFX_YPOS,
1385               PLAYER_BUTTON_XSIZE,PLAYER_BUTTON_YSIZE,
1386               DOOR_GFX_PAGEX1 + PLAYER_BUTTON_4_XPOS, PLAYER_BUTTON_4_YPOS);
1387     */
1388   }
1389
1390   OpenDoor(DOOR_OPEN_1);
1391   ClearEventQueue();
1392
1393   if (!(req_state & REQ_ASK) &&
1394       !(req_state & REQ_CONFIRM) &&
1395       !(req_state & REQ_PLAYER))
1396     return(FALSE);
1397
1398   if (game_status != MAINMENU)
1399     InitAnimation();
1400
1401   button_status = MB_RELEASED;
1402
1403   while(result<0)
1404   {
1405     DoAnimation();
1406     Delay(10);
1407
1408     if (XPending(display))
1409     {
1410       XEvent event;
1411
1412       XNextEvent(display, &event);
1413       switch(event.type)
1414       {
1415         case Expose:
1416           HandleExposeEvent((XExposeEvent *) &event);
1417           break;
1418         case UnmapNotify:
1419           SleepWhileUnmapped();
1420           break;
1421         case ButtonPress:
1422         case ButtonRelease:
1423         case MotionNotify:
1424         {
1425           int choice;
1426
1427           if (event.type == MotionNotify)
1428           {
1429             motion_status = TRUE;
1430             mx = ((XMotionEvent *) &event)->x;
1431             my = ((XMotionEvent *) &event)->y;
1432           }
1433           else
1434           {
1435             motion_status = FALSE;
1436             mx = ((XButtonEvent *) &event)->x;
1437             my = ((XButtonEvent *) &event)->y;
1438             if (event.type==ButtonPress)
1439               button_status = ((XButtonEvent *) &event)->button;
1440             else
1441               button_status = MB_RELEASED;
1442           }
1443
1444           if (req_state & REQ_ASK)
1445             choice = CheckYesNoButtons(mx,my,button_status);
1446           else if (req_state & REQ_CONFIRM)
1447             choice = CheckConfirmButton(mx,my,button_status);
1448           else
1449             choice = CheckPlayerButtons(mx,my,button_status);
1450
1451           switch(choice)
1452           {
1453             case BUTTON_OK:
1454               result = TRUE;
1455               break;
1456             case BUTTON_NO:
1457               result = FALSE;
1458               break;
1459             case BUTTON_CONFIRM:
1460               result = TRUE | FALSE;
1461               break;
1462             case BUTTON_PLAYER_1:
1463               result = 1;
1464               break;
1465             case BUTTON_PLAYER_2:
1466               result = 2;
1467               break;
1468             case BUTTON_PLAYER_3:
1469               result = 3;
1470               break;
1471             case BUTTON_PLAYER_4:
1472               result = 4;
1473               break;
1474             default:
1475               break;
1476           }
1477           break;
1478         }
1479         case KeyPress:
1480           switch(XLookupKeysym((XKeyEvent *)&event,
1481                                ((XKeyEvent *)&event)->state))
1482           {
1483             case XK_Return:
1484               result = 1;
1485               break;
1486             case XK_Escape:
1487               result = 0;
1488               break;
1489           }
1490           if (req_state & REQ_PLAYER)
1491             result = 0;
1492           break;
1493         case KeyRelease:
1494           key_joystick_mapping = 0;
1495           break;
1496         case FocusIn:
1497         case FocusOut:
1498           HandleFocusEvent((XFocusChangeEvent *) &event);
1499           break;
1500         case ClientMessage:
1501           HandleClientMessageEvent((XClientMessageEvent *) &event);
1502           break;
1503         default:
1504           break;
1505       }
1506     }
1507     else if (JoystickButton() == JOY_BUTTON_NEW_PRESSED)
1508     {
1509       int joy=Joystick();
1510
1511       if (joy & JOY_BUTTON_1)
1512         result = 1;
1513       else if (joy & JOY_BUTTON_2)
1514         result = 0;
1515     }
1516   }
1517
1518   if (game_status != MAINMENU)
1519     StopAnimation();
1520
1521   if (!(req_state & REQ_STAY_OPEN))
1522   {
1523     CloseDoor(DOOR_CLOSE_1);
1524
1525     if (!(req_state & REQ_STAY_CLOSED) && (old_door_state & DOOR_OPEN_1))
1526     {
1527       XCopyArea(display,pix[PIX_DB_DOOR],pix[PIX_DB_DOOR],gc,
1528                 DOOR_GFX_PAGEX2,DOOR_GFX_PAGEY1, DXSIZE,DYSIZE,
1529                 DOOR_GFX_PAGEX1,DOOR_GFX_PAGEY1);
1530       OpenDoor(DOOR_OPEN_1);
1531     }
1532   }
1533
1534   return(result);
1535 }
1536
1537 unsigned int OpenDoor(unsigned int door_state)
1538 {
1539   unsigned int new_door_state;
1540
1541   if (door_state & DOOR_COPY_BACK)
1542   {
1543     XCopyArea(display,pix[PIX_DB_DOOR],pix[PIX_DB_DOOR],gc,
1544               DOOR_GFX_PAGEX2,DOOR_GFX_PAGEY1, DXSIZE,DYSIZE+VYSIZE,
1545               DOOR_GFX_PAGEX1,DOOR_GFX_PAGEY1);
1546     door_state &= ~DOOR_COPY_BACK;
1547   }
1548
1549   new_door_state = MoveDoor(door_state);
1550
1551   return(new_door_state);
1552 }
1553
1554 unsigned int CloseDoor(unsigned int door_state)
1555 {
1556   unsigned int new_door_state;
1557
1558   XCopyArea(display,backbuffer,pix[PIX_DB_DOOR],gc,
1559             DX,DY, DXSIZE,DYSIZE, DOOR_GFX_PAGEX1,DOOR_GFX_PAGEY1);
1560   XCopyArea(display,backbuffer,pix[PIX_DB_DOOR],gc,
1561             VX,VY, VXSIZE,VYSIZE, DOOR_GFX_PAGEX1,DOOR_GFX_PAGEY2);
1562
1563   new_door_state = MoveDoor(door_state);
1564
1565   return(new_door_state);
1566 }
1567
1568 unsigned int GetDoorState()
1569 {
1570   return(MoveDoor(DOOR_GET_STATE));
1571 }
1572
1573 unsigned int MoveDoor(unsigned int door_state)
1574 {
1575   static unsigned int door1 = DOOR_OPEN_1;
1576   static unsigned int door2 = DOOR_CLOSE_2;
1577   static long door_delay = 0;
1578   int x, start, stepsize = 2;
1579   long door_delay_value = stepsize * 5;
1580
1581   if (door_state == DOOR_GET_STATE)
1582     return(door1 | door2);
1583
1584   if (door1==DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
1585     door_state &= ~DOOR_OPEN_1;
1586   else if (door1==DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
1587     door_state &= ~DOOR_CLOSE_1;
1588   if (door2==DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
1589     door_state &= ~DOOR_OPEN_2;
1590   else if (door2==DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
1591     door_state &= ~DOOR_CLOSE_2;
1592
1593   if (quick_doors)
1594   {
1595     stepsize = 20;
1596     door_delay_value = 0;
1597     StopSound(SND_OEFFNEN);
1598   }
1599
1600   if (door_state & DOOR_ACTION)
1601   {
1602     if (!(door_state & DOOR_NO_DELAY))
1603       PlaySoundStereo(SND_OEFFNEN,PSND_MAX_RIGHT);
1604
1605     start = ((door_state & DOOR_NO_DELAY) ? DXSIZE : 0);
1606
1607     for(x=start; x<=DXSIZE; x+=stepsize)
1608     {
1609       WaitUntilDelayReached(&door_delay, door_delay_value);
1610
1611       if (door_state & DOOR_ACTION_1)
1612       {
1613         int i = (door_state & DOOR_OPEN_1 ? DXSIZE-x : x);
1614         int j = (DXSIZE - i)/3;
1615
1616         XCopyArea(display,pix[PIX_DB_DOOR],drawto,gc,
1617                   DOOR_GFX_PAGEX1,DOOR_GFX_PAGEY1+i/2,
1618                   DXSIZE,DYSIZE-i/2, DX,DY);
1619
1620         XFillRectangle(display,drawto,gc,DX,DY+DYSIZE-i/2,DXSIZE,i/2);
1621
1622         XSetClipOrigin(display,clip_gc[PIX_DOOR],
1623                        DX-i,(DY+j)-DOOR_GFX_PAGEY1);
1624         XCopyArea(display,pix[PIX_DOOR],drawto,clip_gc[PIX_DOOR],
1625                   DXSIZE,DOOR_GFX_PAGEY1, i,77, DX+DXSIZE-i,DY+j);
1626         XCopyArea(display,pix[PIX_DOOR],drawto,clip_gc[PIX_DOOR],
1627                   DXSIZE,DOOR_GFX_PAGEY1+140, i,63, DX+DXSIZE-i,DY+140+j);
1628         XSetClipOrigin(display,clip_gc[PIX_DOOR],
1629                        DX-DXSIZE+i,DY-(DOOR_GFX_PAGEY1+j));
1630         XCopyArea(display,pix[PIX_DOOR],drawto,clip_gc[PIX_DOOR],
1631                   DXSIZE-i,DOOR_GFX_PAGEY1+j, i,77-j, DX,DY);
1632         XCopyArea(display,pix[PIX_DOOR],drawto,clip_gc[PIX_DOOR],
1633                   DXSIZE-i,DOOR_GFX_PAGEY1+140, i,63, DX,DY+140-j);
1634
1635         XCopyArea(display,pix[PIX_DOOR],drawto,clip_gc[PIX_DOOR],
1636                   DXSIZE-i,DOOR_GFX_PAGEY1+77, i,63,
1637                   DX,DY+77-j);
1638         XCopyArea(display,pix[PIX_DOOR],drawto,clip_gc[PIX_DOOR],
1639                   DXSIZE-i,DOOR_GFX_PAGEY1+203, i,77,
1640                   DX,DY+203-j);
1641         XSetClipOrigin(display,clip_gc[PIX_DOOR],
1642                        DX-i,(DY+j)-DOOR_GFX_PAGEY1);
1643         XCopyArea(display,pix[PIX_DOOR],drawto,clip_gc[PIX_DOOR],
1644                   DXSIZE,DOOR_GFX_PAGEY1+77, i,63,
1645                   DX+DXSIZE-i,DY+77+j);
1646         XCopyArea(display,pix[PIX_DOOR],drawto,clip_gc[PIX_DOOR],
1647                   DXSIZE,DOOR_GFX_PAGEY1+203, i,77-j,
1648                   DX+DXSIZE-i,DY+203+j);
1649
1650         redraw_mask |= REDRAW_DOOR_1;
1651       }
1652
1653       if (door_state & DOOR_ACTION_2)
1654       {
1655         int i = (door_state & DOOR_OPEN_2 ? VXSIZE-x : x);
1656         int j = (VXSIZE - i)/3;
1657
1658         XCopyArea(display,pix[PIX_DB_DOOR],drawto,gc,
1659                   DOOR_GFX_PAGEX1,DOOR_GFX_PAGEY2+i/2,
1660                   VXSIZE,VYSIZE-i/2, VX,VY);
1661
1662         XFillRectangle(display,drawto,gc,VX,VY+VYSIZE-i/2,VXSIZE,i/2);
1663
1664         XSetClipOrigin(display,clip_gc[PIX_DOOR],
1665                        VX-i,(VY+j)-DOOR_GFX_PAGEY2);
1666         XCopyArea(display,pix[PIX_DOOR],drawto,clip_gc[PIX_DOOR],
1667                   VXSIZE,DOOR_GFX_PAGEY2, i,VYSIZE/2, VX+VXSIZE-i,VY+j);
1668         XSetClipOrigin(display,clip_gc[PIX_DOOR],
1669                        VX-VXSIZE+i,VY-(DOOR_GFX_PAGEY2+j));
1670         XCopyArea(display,pix[PIX_DOOR],drawto,clip_gc[PIX_DOOR],
1671                   VXSIZE-i,DOOR_GFX_PAGEY2+j, i,VYSIZE/2-j, VX,VY);
1672
1673         XCopyArea(display,pix[PIX_DOOR],drawto,clip_gc[PIX_DOOR],
1674                   VXSIZE-i,DOOR_GFX_PAGEY2+VYSIZE/2, i,VYSIZE/2,
1675                   VX,VY+VYSIZE/2-j);
1676         XSetClipOrigin(display,clip_gc[PIX_DOOR],
1677                        VX-i,(VY+j)-DOOR_GFX_PAGEY2);
1678         XCopyArea(display,pix[PIX_DOOR],drawto,clip_gc[PIX_DOOR],
1679                   VXSIZE,DOOR_GFX_PAGEY2+VYSIZE/2, i,VYSIZE/2-j,
1680                   VX+VXSIZE-i,VY+VYSIZE/2+j);
1681
1682         redraw_mask |= REDRAW_DOOR_2;
1683       }
1684
1685       BackToFront();
1686
1687       if (game_status == MAINMENU)
1688         DoAnimation();
1689     }
1690   }
1691
1692   if (door_state & DOOR_ACTION_1)
1693     door1 = door_state & DOOR_ACTION_1;
1694   if (door_state & DOOR_ACTION_2)
1695     door2 = door_state & DOOR_ACTION_2;
1696
1697   return(door1 | door2);
1698 }
1699
1700 int ReadPixel(Drawable d, int x, int y)
1701 {
1702   static XImage *pixelimage;
1703
1704   pixelimage = XGetImage(display, d, x,y, 1,1, AllPlanes, ZPixmap);
1705   return(XGetPixel(pixelimage,0,0));
1706 }
1707
1708 int el2gfx(int element)
1709 {
1710   switch(element)
1711   {
1712     case EL_LEERRAUM:           return(-1);
1713     case EL_ERDREICH:           return(GFX_ERDREICH);
1714     case EL_MAUERWERK:          return(GFX_MAUERWERK);
1715     case EL_FELSBODEN:          return(GFX_FELSBODEN);
1716     case EL_FELSBROCKEN:        return(GFX_FELSBROCKEN);
1717     case EL_SCHLUESSEL:         return(GFX_SCHLUESSEL);
1718     case EL_EDELSTEIN:          return(GFX_EDELSTEIN);
1719     case EL_AUSGANG_ZU:         return(GFX_AUSGANG_ZU);
1720     case EL_AUSGANG_ACT:        return(GFX_AUSGANG_ACT);
1721     case EL_AUSGANG_AUF:        return(GFX_AUSGANG_AUF);
1722     case EL_SPIELFIGUR:         return(GFX_SPIELFIGUR);
1723     case EL_SPIELER1:           return(GFX_SPIELER1);
1724     case EL_SPIELER2:           return(GFX_SPIELER2);
1725     case EL_SPIELER3:           return(GFX_SPIELER3);
1726     case EL_SPIELER4:           return(GFX_SPIELER4);
1727     case EL_KAEFER:             return(GFX_KAEFER);
1728     case EL_KAEFER_R:           return(GFX_KAEFER_R);
1729     case EL_KAEFER_O:           return(GFX_KAEFER_O);
1730     case EL_KAEFER_L:           return(GFX_KAEFER_L);
1731     case EL_KAEFER_U:           return(GFX_KAEFER_U);
1732     case EL_FLIEGER:            return(GFX_FLIEGER);
1733     case EL_FLIEGER_R:          return(GFX_FLIEGER_R);
1734     case EL_FLIEGER_O:          return(GFX_FLIEGER_O);
1735     case EL_FLIEGER_L:          return(GFX_FLIEGER_L);
1736     case EL_FLIEGER_U:          return(GFX_FLIEGER_U);
1737     case EL_BUTTERFLY:          return(GFX_BUTTERFLY);
1738     case EL_BUTTERFLY_R:        return(GFX_BUTTERFLY_R);
1739     case EL_BUTTERFLY_O:        return(GFX_BUTTERFLY_O);
1740     case EL_BUTTERFLY_L:        return(GFX_BUTTERFLY_L);
1741     case EL_BUTTERFLY_U:        return(GFX_BUTTERFLY_U);
1742     case EL_FIREFLY:            return(GFX_FIREFLY);
1743     case EL_FIREFLY_R:          return(GFX_FIREFLY_R);
1744     case EL_FIREFLY_O:          return(GFX_FIREFLY_O);
1745     case EL_FIREFLY_L:          return(GFX_FIREFLY_L);
1746     case EL_FIREFLY_U:          return(GFX_FIREFLY_U);
1747     case EL_MAMPFER:            return(GFX_MAMPFER);
1748     case EL_ROBOT:              return(GFX_ROBOT);
1749     case EL_BETON:              return(GFX_BETON);
1750     case EL_DIAMANT:            return(GFX_DIAMANT);
1751     case EL_MORAST_LEER:        return(GFX_MORAST_LEER);
1752     case EL_MORAST_VOLL:        return(GFX_MORAST_VOLL);
1753     case EL_TROPFEN:            return(GFX_TROPFEN);
1754     case EL_BOMBE:              return(GFX_BOMBE);
1755     case EL_SIEB_LEER:          return(GFX_SIEB_LEER);
1756     case EL_SIEB_VOLL:          return(GFX_SIEB_VOLL);
1757     case EL_SIEB_TOT:           return(GFX_SIEB_TOT);
1758     case EL_SALZSAEURE:         return(GFX_SALZSAEURE);
1759     case EL_AMOEBE_TOT:         return(GFX_AMOEBE_TOT);
1760     case EL_AMOEBE_NASS:        return(GFX_AMOEBE_NASS);
1761     case EL_AMOEBE_NORM:        return(GFX_AMOEBE_NORM);
1762     case EL_AMOEBE_VOLL:        return(GFX_AMOEBE_VOLL);
1763     case EL_AMOEBE_BD:          return(GFX_AMOEBE_BD);
1764     case EL_AMOEBA2DIAM:        return(GFX_AMOEBA2DIAM);
1765     case EL_KOKOSNUSS:          return(GFX_KOKOSNUSS);
1766     case EL_LIFE:               return(GFX_LIFE);
1767     case EL_LIFE_ASYNC:         return(GFX_LIFE_ASYNC);
1768     case EL_DYNAMIT:            return(GFX_DYNAMIT);
1769     case EL_BADEWANNE:          return(GFX_BADEWANNE);
1770     case EL_BADEWANNE1:         return(GFX_BADEWANNE1);
1771     case EL_BADEWANNE2:         return(GFX_BADEWANNE2);
1772     case EL_BADEWANNE3:         return(GFX_BADEWANNE3);
1773     case EL_BADEWANNE4:         return(GFX_BADEWANNE4);
1774     case EL_BADEWANNE5:         return(GFX_BADEWANNE5);
1775     case EL_ABLENK_AUS:         return(GFX_ABLENK_AUS);
1776     case EL_ABLENK_EIN:         return(GFX_ABLENK_EIN);
1777     case EL_SCHLUESSEL1:        return(GFX_SCHLUESSEL1);
1778     case EL_SCHLUESSEL2:        return(GFX_SCHLUESSEL2);
1779     case EL_SCHLUESSEL3:        return(GFX_SCHLUESSEL3);
1780     case EL_SCHLUESSEL4:        return(GFX_SCHLUESSEL4);
1781     case EL_PFORTE1:            return(GFX_PFORTE1);
1782     case EL_PFORTE2:            return(GFX_PFORTE2);
1783     case EL_PFORTE3:            return(GFX_PFORTE3);
1784     case EL_PFORTE4:            return(GFX_PFORTE4);
1785     case EL_PFORTE1X:           return(GFX_PFORTE1X);
1786     case EL_PFORTE2X:           return(GFX_PFORTE2X);
1787     case EL_PFORTE3X:           return(GFX_PFORTE3X);
1788     case EL_PFORTE4X:           return(GFX_PFORTE4X);
1789     case EL_DYNAMIT_AUS:        return(GFX_DYNAMIT_AUS);
1790     case EL_PACMAN:             return(GFX_PACMAN);
1791     case EL_PACMAN_R:           return(GFX_PACMAN_R);
1792     case EL_PACMAN_O:           return(GFX_PACMAN_O);
1793     case EL_PACMAN_L:           return(GFX_PACMAN_L);
1794     case EL_PACMAN_U:           return(GFX_PACMAN_U);
1795     case EL_UNSICHTBAR:         return(GFX_UNSICHTBAR);
1796     case EL_ERZ_EDEL:           return(GFX_ERZ_EDEL);
1797     case EL_ERZ_DIAM:           return(GFX_ERZ_DIAM);
1798     case EL_BIRNE_AUS:          return(GFX_BIRNE_AUS);
1799     case EL_BIRNE_EIN:          return(GFX_BIRNE_EIN);
1800     case EL_ZEIT_VOLL:          return(GFX_ZEIT_VOLL);
1801     case EL_ZEIT_LEER:          return(GFX_ZEIT_LEER);
1802     case EL_MAUER_LEBT:         return(GFX_MAUER_LEBT);
1803     case EL_MAUER_X:            return(GFX_MAUER_X);
1804     case EL_MAUER_Y:            return(GFX_MAUER_Y);
1805     case EL_MAUER_XY:           return(GFX_MAUER_XY);
1806     case EL_EDELSTEIN_BD:       return(GFX_EDELSTEIN_BD);
1807     case EL_EDELSTEIN_GELB:     return(GFX_EDELSTEIN_GELB);
1808     case EL_EDELSTEIN_ROT:      return(GFX_EDELSTEIN_ROT);
1809     case EL_EDELSTEIN_LILA:     return(GFX_EDELSTEIN_LILA);
1810     case EL_ERZ_EDEL_BD:        return(GFX_ERZ_EDEL_BD);
1811     case EL_ERZ_EDEL_GELB:      return(GFX_ERZ_EDEL_GELB);
1812     case EL_ERZ_EDEL_ROT:       return(GFX_ERZ_EDEL_ROT);
1813     case EL_ERZ_EDEL_LILA:      return(GFX_ERZ_EDEL_LILA);
1814     case EL_MAMPFER2:           return(GFX_MAMPFER2);
1815     case EL_SIEB2_LEER:         return(GFX_SIEB2_LEER);
1816     case EL_SIEB2_VOLL:         return(GFX_SIEB2_VOLL);
1817     case EL_SIEB2_TOT:          return(GFX_SIEB2_TOT);
1818     case EL_DYNABOMB:           return(GFX_DYNABOMB);
1819     case EL_DYNABOMB_NR:        return(GFX_DYNABOMB_NR);
1820     case EL_DYNABOMB_SZ:        return(GFX_DYNABOMB_SZ);
1821     case EL_DYNABOMB_XL:        return(GFX_DYNABOMB_XL);
1822     case EL_SOKOBAN_OBJEKT:     return(GFX_SOKOBAN_OBJEKT);
1823     case EL_SOKOBAN_FELD_LEER:  return(GFX_SOKOBAN_FELD_LEER);
1824     case EL_SOKOBAN_FELD_VOLL:  return(GFX_SOKOBAN_FELD_VOLL);
1825     case EL_MAULWURF:           return(GFX_MAULWURF);
1826     case EL_PINGUIN:            return(GFX_PINGUIN);
1827     case EL_SCHWEIN:            return(GFX_SCHWEIN);
1828     case EL_DRACHE:             return(GFX_DRACHE);
1829     case EL_SONDE:              return(GFX_SONDE);
1830     case EL_PFEIL_L:            return(GFX_PFEIL_L);
1831     case EL_PFEIL_R:            return(GFX_PFEIL_R);
1832     case EL_PFEIL_O:            return(GFX_PFEIL_O);
1833     case EL_PFEIL_U:            return(GFX_PFEIL_U);
1834     default:
1835     {
1836       if (IS_CHAR(element))
1837         return(GFX_CHAR_START + (element-EL_CHAR_START));
1838       else
1839         return(-1);
1840     }
1841   }
1842 }