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