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