rnd-19981012-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 (!standalone && 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     XCopyArea(display,pix[PIX_DOOR],pix[PIX_DB_DOOR],gc,
1356               DOOR_GFX_PAGEX4,OK_BUTTON_GFX_YPOS,
1357               DXSIZE,OK_BUTTON_YSIZE,
1358               DOOR_GFX_PAGEX1,OK_BUTTON_YPOS);
1359   else if (req_state & REQ_CONFIRM)
1360     XCopyArea(display,pix[PIX_DOOR],pix[PIX_DB_DOOR],gc,
1361               DOOR_GFX_PAGEX4,CONFIRM_BUTTON_GFX_YPOS,
1362               DXSIZE,CONFIRM_BUTTON_YSIZE,
1363               DOOR_GFX_PAGEX1,CONFIRM_BUTTON_YPOS);
1364   else if (req_state & REQ_PLAYER)
1365   {
1366     DrawPlayerButton(BUTTON_PLAYER_1, DB_INIT);
1367     DrawPlayerButton(BUTTON_PLAYER_2, DB_INIT);
1368     DrawPlayerButton(BUTTON_PLAYER_3, DB_INIT);
1369     DrawPlayerButton(BUTTON_PLAYER_4, DB_INIT);
1370
1371     /*
1372     XCopyArea(display,pix[PIX_DOOR],pix[PIX_DB_DOOR],gc,
1373               DOOR_GFX_PAGEX4 + PLAYER_BUTTON_GFX_XPOS, PLAYER_BUTTON_GFX_YPOS,
1374               PLAYER_BUTTON_XSIZE,PLAYER_BUTTON_YSIZE,
1375               DOOR_GFX_PAGEX1 + PLAYER_BUTTON_1_XPOS, PLAYER_BUTTON_1_YPOS);
1376     XCopyArea(display,pix[PIX_DOOR],pix[PIX_DB_DOOR],gc,
1377               DOOR_GFX_PAGEX4 + PLAYER_BUTTON_GFX_XPOS, PLAYER_BUTTON_GFX_YPOS,
1378               PLAYER_BUTTON_XSIZE,PLAYER_BUTTON_YSIZE,
1379               DOOR_GFX_PAGEX1 + PLAYER_BUTTON_1_XPOS, PLAYER_BUTTON_1_YPOS);
1380     XCopyArea(display,pix[PIX_DOOR],pix[PIX_DB_DOOR],gc,
1381               DOOR_GFX_PAGEX4 + PLAYER_BUTTON_GFX_XPOS, PLAYER_BUTTON_GFX_YPOS,
1382               PLAYER_BUTTON_XSIZE,PLAYER_BUTTON_YSIZE,
1383               DOOR_GFX_PAGEX1 + PLAYER_BUTTON_2_XPOS, PLAYER_BUTTON_2_YPOS);
1384     XCopyArea(display,pix[PIX_DOOR],pix[PIX_DB_DOOR],gc,
1385               DOOR_GFX_PAGEX4 + PLAYER_BUTTON_GFX_XPOS, PLAYER_BUTTON_GFX_YPOS,
1386               PLAYER_BUTTON_XSIZE,PLAYER_BUTTON_YSIZE,
1387               DOOR_GFX_PAGEX1 + PLAYER_BUTTON_3_XPOS, PLAYER_BUTTON_3_YPOS);
1388     XCopyArea(display,pix[PIX_DOOR],pix[PIX_DB_DOOR],gc,
1389               DOOR_GFX_PAGEX4 + PLAYER_BUTTON_GFX_XPOS, PLAYER_BUTTON_GFX_YPOS,
1390               PLAYER_BUTTON_XSIZE,PLAYER_BUTTON_YSIZE,
1391               DOOR_GFX_PAGEX1 + PLAYER_BUTTON_4_XPOS, PLAYER_BUTTON_4_YPOS);
1392     */
1393   }
1394
1395   OpenDoor(DOOR_OPEN_1);
1396   ClearEventQueue();
1397
1398   if (!(req_state & REQUEST_WAIT_FOR))
1399     return(FALSE);
1400
1401   if (game_status != MAINMENU)
1402     InitAnimation();
1403
1404   button_status = MB_RELEASED;
1405
1406   while(result<0)
1407   {
1408     DoAnimation();
1409     Delay(10);
1410
1411     if (XPending(display))
1412     {
1413       XEvent event;
1414
1415       XNextEvent(display, &event);
1416       switch(event.type)
1417       {
1418         case Expose:
1419           HandleExposeEvent((XExposeEvent *) &event);
1420           break;
1421         case UnmapNotify:
1422           SleepWhileUnmapped();
1423           break;
1424         case ButtonPress:
1425         case ButtonRelease:
1426         case MotionNotify:
1427         {
1428           int choice;
1429
1430           if (event.type == MotionNotify)
1431           {
1432             motion_status = TRUE;
1433             mx = ((XMotionEvent *) &event)->x;
1434             my = ((XMotionEvent *) &event)->y;
1435           }
1436           else
1437           {
1438             motion_status = FALSE;
1439             mx = ((XButtonEvent *) &event)->x;
1440             my = ((XButtonEvent *) &event)->y;
1441             if (event.type==ButtonPress)
1442               button_status = ((XButtonEvent *) &event)->button;
1443             else
1444               button_status = MB_RELEASED;
1445           }
1446
1447           if (req_state & REQ_ASK)
1448             choice = CheckYesNoButtons(mx,my,button_status);
1449           else if (req_state & REQ_CONFIRM)
1450             choice = CheckConfirmButton(mx,my,button_status);
1451           else
1452             choice = CheckPlayerButtons(mx,my,button_status);
1453
1454           switch(choice)
1455           {
1456             case BUTTON_OK:
1457               result = TRUE;
1458               break;
1459             case BUTTON_NO:
1460               result = FALSE;
1461               break;
1462             case BUTTON_CONFIRM:
1463               result = TRUE | FALSE;
1464               break;
1465             case BUTTON_PLAYER_1:
1466               result = 1;
1467               break;
1468             case BUTTON_PLAYER_2:
1469               result = 2;
1470               break;
1471             case BUTTON_PLAYER_3:
1472               result = 3;
1473               break;
1474             case BUTTON_PLAYER_4:
1475               result = 4;
1476               break;
1477             default:
1478               break;
1479           }
1480           break;
1481         }
1482         case KeyPress:
1483           switch(XLookupKeysym((XKeyEvent *)&event,
1484                                ((XKeyEvent *)&event)->state))
1485           {
1486             case XK_Return:
1487               result = 1;
1488               break;
1489             case XK_Escape:
1490               result = 0;
1491               break;
1492           }
1493           if (req_state & REQ_PLAYER)
1494             result = 0;
1495           break;
1496         case KeyRelease:
1497           key_joystick_mapping = 0;
1498           break;
1499         case FocusIn:
1500         case FocusOut:
1501           HandleFocusEvent((XFocusChangeEvent *) &event);
1502           break;
1503         case ClientMessage:
1504           HandleClientMessageEvent((XClientMessageEvent *) &event);
1505           break;
1506         default:
1507           break;
1508       }
1509     }
1510     else if (JoystickButton() == JOY_BUTTON_NEW_PRESSED)
1511     {
1512       int joy=Joystick();
1513
1514       if (joy & JOY_BUTTON_1)
1515         result = 1;
1516       else if (joy & JOY_BUTTON_2)
1517         result = 0;
1518     }
1519   }
1520
1521   if (game_status != MAINMENU)
1522     StopAnimation();
1523
1524   if (!(req_state & REQ_STAY_OPEN))
1525   {
1526     CloseDoor(DOOR_CLOSE_1);
1527
1528     if (!(req_state & REQ_STAY_CLOSED) && (old_door_state & DOOR_OPEN_1))
1529     {
1530       XCopyArea(display,pix[PIX_DB_DOOR],pix[PIX_DB_DOOR],gc,
1531                 DOOR_GFX_PAGEX2,DOOR_GFX_PAGEY1, DXSIZE,DYSIZE,
1532                 DOOR_GFX_PAGEX1,DOOR_GFX_PAGEY1);
1533       OpenDoor(DOOR_OPEN_1);
1534     }
1535   }
1536
1537   /* continue network game after request */
1538   if (!standalone && game_status == PLAYING && req_state & REQUEST_WAIT_FOR)
1539     SendToServer_ContinuePlaying();
1540
1541   return(result);
1542 }
1543
1544 unsigned int OpenDoor(unsigned int door_state)
1545 {
1546   unsigned int new_door_state;
1547
1548   if (door_state & DOOR_COPY_BACK)
1549   {
1550     XCopyArea(display,pix[PIX_DB_DOOR],pix[PIX_DB_DOOR],gc,
1551               DOOR_GFX_PAGEX2,DOOR_GFX_PAGEY1, DXSIZE,DYSIZE+VYSIZE,
1552               DOOR_GFX_PAGEX1,DOOR_GFX_PAGEY1);
1553     door_state &= ~DOOR_COPY_BACK;
1554   }
1555
1556   new_door_state = MoveDoor(door_state);
1557
1558   return(new_door_state);
1559 }
1560
1561 unsigned int CloseDoor(unsigned int door_state)
1562 {
1563   unsigned int new_door_state;
1564
1565   XCopyArea(display,backbuffer,pix[PIX_DB_DOOR],gc,
1566             DX,DY, DXSIZE,DYSIZE, DOOR_GFX_PAGEX1,DOOR_GFX_PAGEY1);
1567   XCopyArea(display,backbuffer,pix[PIX_DB_DOOR],gc,
1568             VX,VY, VXSIZE,VYSIZE, DOOR_GFX_PAGEX1,DOOR_GFX_PAGEY2);
1569
1570   new_door_state = MoveDoor(door_state);
1571
1572   return(new_door_state);
1573 }
1574
1575 unsigned int GetDoorState()
1576 {
1577   return(MoveDoor(DOOR_GET_STATE));
1578 }
1579
1580 unsigned int MoveDoor(unsigned int door_state)
1581 {
1582   static unsigned int door1 = DOOR_OPEN_1;
1583   static unsigned int door2 = DOOR_CLOSE_2;
1584   static long door_delay = 0;
1585   int x, start, stepsize = 2;
1586   long door_delay_value = stepsize * 5;
1587
1588   if (door_state == DOOR_GET_STATE)
1589     return(door1 | door2);
1590
1591   if (door1==DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
1592     door_state &= ~DOOR_OPEN_1;
1593   else if (door1==DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
1594     door_state &= ~DOOR_CLOSE_1;
1595   if (door2==DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
1596     door_state &= ~DOOR_OPEN_2;
1597   else if (door2==DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
1598     door_state &= ~DOOR_CLOSE_2;
1599
1600   if (quick_doors)
1601   {
1602     stepsize = 20;
1603     door_delay_value = 0;
1604     StopSound(SND_OEFFNEN);
1605   }
1606
1607   if (door_state & DOOR_ACTION)
1608   {
1609     if (!(door_state & DOOR_NO_DELAY))
1610       PlaySoundStereo(SND_OEFFNEN,PSND_MAX_RIGHT);
1611
1612     start = ((door_state & DOOR_NO_DELAY) ? DXSIZE : 0);
1613
1614     for(x=start; x<=DXSIZE; x+=stepsize)
1615     {
1616       WaitUntilDelayReached(&door_delay, door_delay_value);
1617
1618       if (door_state & DOOR_ACTION_1)
1619       {
1620         int i = (door_state & DOOR_OPEN_1 ? DXSIZE-x : x);
1621         int j = (DXSIZE - i)/3;
1622
1623         XCopyArea(display,pix[PIX_DB_DOOR],drawto,gc,
1624                   DOOR_GFX_PAGEX1,DOOR_GFX_PAGEY1+i/2,
1625                   DXSIZE,DYSIZE-i/2, DX,DY);
1626
1627         XFillRectangle(display,drawto,gc,DX,DY+DYSIZE-i/2,DXSIZE,i/2);
1628
1629         XSetClipOrigin(display,clip_gc[PIX_DOOR],
1630                        DX-i,(DY+j)-DOOR_GFX_PAGEY1);
1631         XCopyArea(display,pix[PIX_DOOR],drawto,clip_gc[PIX_DOOR],
1632                   DXSIZE,DOOR_GFX_PAGEY1, i,77, DX+DXSIZE-i,DY+j);
1633         XCopyArea(display,pix[PIX_DOOR],drawto,clip_gc[PIX_DOOR],
1634                   DXSIZE,DOOR_GFX_PAGEY1+140, i,63, DX+DXSIZE-i,DY+140+j);
1635         XSetClipOrigin(display,clip_gc[PIX_DOOR],
1636                        DX-DXSIZE+i,DY-(DOOR_GFX_PAGEY1+j));
1637         XCopyArea(display,pix[PIX_DOOR],drawto,clip_gc[PIX_DOOR],
1638                   DXSIZE-i,DOOR_GFX_PAGEY1+j, i,77-j, DX,DY);
1639         XCopyArea(display,pix[PIX_DOOR],drawto,clip_gc[PIX_DOOR],
1640                   DXSIZE-i,DOOR_GFX_PAGEY1+140, i,63, DX,DY+140-j);
1641
1642         XCopyArea(display,pix[PIX_DOOR],drawto,clip_gc[PIX_DOOR],
1643                   DXSIZE-i,DOOR_GFX_PAGEY1+77, i,63,
1644                   DX,DY+77-j);
1645         XCopyArea(display,pix[PIX_DOOR],drawto,clip_gc[PIX_DOOR],
1646                   DXSIZE-i,DOOR_GFX_PAGEY1+203, i,77,
1647                   DX,DY+203-j);
1648         XSetClipOrigin(display,clip_gc[PIX_DOOR],
1649                        DX-i,(DY+j)-DOOR_GFX_PAGEY1);
1650         XCopyArea(display,pix[PIX_DOOR],drawto,clip_gc[PIX_DOOR],
1651                   DXSIZE,DOOR_GFX_PAGEY1+77, i,63,
1652                   DX+DXSIZE-i,DY+77+j);
1653         XCopyArea(display,pix[PIX_DOOR],drawto,clip_gc[PIX_DOOR],
1654                   DXSIZE,DOOR_GFX_PAGEY1+203, i,77-j,
1655                   DX+DXSIZE-i,DY+203+j);
1656
1657         redraw_mask |= REDRAW_DOOR_1;
1658       }
1659
1660       if (door_state & DOOR_ACTION_2)
1661       {
1662         int i = (door_state & DOOR_OPEN_2 ? VXSIZE-x : x);
1663         int j = (VXSIZE - i)/3;
1664
1665         XCopyArea(display,pix[PIX_DB_DOOR],drawto,gc,
1666                   DOOR_GFX_PAGEX1,DOOR_GFX_PAGEY2+i/2,
1667                   VXSIZE,VYSIZE-i/2, VX,VY);
1668
1669         XFillRectangle(display,drawto,gc,VX,VY+VYSIZE-i/2,VXSIZE,i/2);
1670
1671         XSetClipOrigin(display,clip_gc[PIX_DOOR],
1672                        VX-i,(VY+j)-DOOR_GFX_PAGEY2);
1673         XCopyArea(display,pix[PIX_DOOR],drawto,clip_gc[PIX_DOOR],
1674                   VXSIZE,DOOR_GFX_PAGEY2, i,VYSIZE/2, VX+VXSIZE-i,VY+j);
1675         XSetClipOrigin(display,clip_gc[PIX_DOOR],
1676                        VX-VXSIZE+i,VY-(DOOR_GFX_PAGEY2+j));
1677         XCopyArea(display,pix[PIX_DOOR],drawto,clip_gc[PIX_DOOR],
1678                   VXSIZE-i,DOOR_GFX_PAGEY2+j, i,VYSIZE/2-j, VX,VY);
1679
1680         XCopyArea(display,pix[PIX_DOOR],drawto,clip_gc[PIX_DOOR],
1681                   VXSIZE-i,DOOR_GFX_PAGEY2+VYSIZE/2, i,VYSIZE/2,
1682                   VX,VY+VYSIZE/2-j);
1683         XSetClipOrigin(display,clip_gc[PIX_DOOR],
1684                        VX-i,(VY+j)-DOOR_GFX_PAGEY2);
1685         XCopyArea(display,pix[PIX_DOOR],drawto,clip_gc[PIX_DOOR],
1686                   VXSIZE,DOOR_GFX_PAGEY2+VYSIZE/2, i,VYSIZE/2-j,
1687                   VX+VXSIZE-i,VY+VYSIZE/2+j);
1688
1689         redraw_mask |= REDRAW_DOOR_2;
1690       }
1691
1692       BackToFront();
1693
1694       if (game_status == MAINMENU)
1695         DoAnimation();
1696     }
1697   }
1698
1699   if (door_state & DOOR_ACTION_1)
1700     door1 = door_state & DOOR_ACTION_1;
1701   if (door_state & DOOR_ACTION_2)
1702     door2 = door_state & DOOR_ACTION_2;
1703
1704   return(door1 | door2);
1705 }
1706
1707 int ReadPixel(Drawable d, int x, int y)
1708 {
1709   static XImage *pixelimage;
1710
1711   pixelimage = XGetImage(display, d, x,y, 1,1, AllPlanes, ZPixmap);
1712   return(XGetPixel(pixelimage,0,0));
1713 }
1714
1715 int el2gfx(int element)
1716 {
1717   switch(element)
1718   {
1719     case EL_LEERRAUM:           return(-1);
1720     case EL_ERDREICH:           return(GFX_ERDREICH);
1721     case EL_MAUERWERK:          return(GFX_MAUERWERK);
1722     case EL_FELSBODEN:          return(GFX_FELSBODEN);
1723     case EL_FELSBROCKEN:        return(GFX_FELSBROCKEN);
1724     case EL_SCHLUESSEL:         return(GFX_SCHLUESSEL);
1725     case EL_EDELSTEIN:          return(GFX_EDELSTEIN);
1726     case EL_AUSGANG_ZU:         return(GFX_AUSGANG_ZU);
1727     case EL_AUSGANG_ACT:        return(GFX_AUSGANG_ACT);
1728     case EL_AUSGANG_AUF:        return(GFX_AUSGANG_AUF);
1729     case EL_SPIELFIGUR:         return(GFX_SPIELFIGUR);
1730     case EL_SPIELER1:           return(GFX_SPIELER1);
1731     case EL_SPIELER2:           return(GFX_SPIELER2);
1732     case EL_SPIELER3:           return(GFX_SPIELER3);
1733     case EL_SPIELER4:           return(GFX_SPIELER4);
1734     case EL_KAEFER:             return(GFX_KAEFER);
1735     case EL_KAEFER_R:           return(GFX_KAEFER_R);
1736     case EL_KAEFER_O:           return(GFX_KAEFER_O);
1737     case EL_KAEFER_L:           return(GFX_KAEFER_L);
1738     case EL_KAEFER_U:           return(GFX_KAEFER_U);
1739     case EL_FLIEGER:            return(GFX_FLIEGER);
1740     case EL_FLIEGER_R:          return(GFX_FLIEGER_R);
1741     case EL_FLIEGER_O:          return(GFX_FLIEGER_O);
1742     case EL_FLIEGER_L:          return(GFX_FLIEGER_L);
1743     case EL_FLIEGER_U:          return(GFX_FLIEGER_U);
1744     case EL_BUTTERFLY:          return(GFX_BUTTERFLY);
1745     case EL_BUTTERFLY_R:        return(GFX_BUTTERFLY_R);
1746     case EL_BUTTERFLY_O:        return(GFX_BUTTERFLY_O);
1747     case EL_BUTTERFLY_L:        return(GFX_BUTTERFLY_L);
1748     case EL_BUTTERFLY_U:        return(GFX_BUTTERFLY_U);
1749     case EL_FIREFLY:            return(GFX_FIREFLY);
1750     case EL_FIREFLY_R:          return(GFX_FIREFLY_R);
1751     case EL_FIREFLY_O:          return(GFX_FIREFLY_O);
1752     case EL_FIREFLY_L:          return(GFX_FIREFLY_L);
1753     case EL_FIREFLY_U:          return(GFX_FIREFLY_U);
1754     case EL_MAMPFER:            return(GFX_MAMPFER);
1755     case EL_ROBOT:              return(GFX_ROBOT);
1756     case EL_BETON:              return(GFX_BETON);
1757     case EL_DIAMANT:            return(GFX_DIAMANT);
1758     case EL_MORAST_LEER:        return(GFX_MORAST_LEER);
1759     case EL_MORAST_VOLL:        return(GFX_MORAST_VOLL);
1760     case EL_TROPFEN:            return(GFX_TROPFEN);
1761     case EL_BOMBE:              return(GFX_BOMBE);
1762     case EL_SIEB_LEER:          return(GFX_SIEB_LEER);
1763     case EL_SIEB_VOLL:          return(GFX_SIEB_VOLL);
1764     case EL_SIEB_TOT:           return(GFX_SIEB_TOT);
1765     case EL_SALZSAEURE:         return(GFX_SALZSAEURE);
1766     case EL_AMOEBE_TOT:         return(GFX_AMOEBE_TOT);
1767     case EL_AMOEBE_NASS:        return(GFX_AMOEBE_NASS);
1768     case EL_AMOEBE_NORM:        return(GFX_AMOEBE_NORM);
1769     case EL_AMOEBE_VOLL:        return(GFX_AMOEBE_VOLL);
1770     case EL_AMOEBE_BD:          return(GFX_AMOEBE_BD);
1771     case EL_AMOEBA2DIAM:        return(GFX_AMOEBA2DIAM);
1772     case EL_KOKOSNUSS:          return(GFX_KOKOSNUSS);
1773     case EL_LIFE:               return(GFX_LIFE);
1774     case EL_LIFE_ASYNC:         return(GFX_LIFE_ASYNC);
1775     case EL_DYNAMIT:            return(GFX_DYNAMIT);
1776     case EL_BADEWANNE:          return(GFX_BADEWANNE);
1777     case EL_BADEWANNE1:         return(GFX_BADEWANNE1);
1778     case EL_BADEWANNE2:         return(GFX_BADEWANNE2);
1779     case EL_BADEWANNE3:         return(GFX_BADEWANNE3);
1780     case EL_BADEWANNE4:         return(GFX_BADEWANNE4);
1781     case EL_BADEWANNE5:         return(GFX_BADEWANNE5);
1782     case EL_ABLENK_AUS:         return(GFX_ABLENK_AUS);
1783     case EL_ABLENK_EIN:         return(GFX_ABLENK_EIN);
1784     case EL_SCHLUESSEL1:        return(GFX_SCHLUESSEL1);
1785     case EL_SCHLUESSEL2:        return(GFX_SCHLUESSEL2);
1786     case EL_SCHLUESSEL3:        return(GFX_SCHLUESSEL3);
1787     case EL_SCHLUESSEL4:        return(GFX_SCHLUESSEL4);
1788     case EL_PFORTE1:            return(GFX_PFORTE1);
1789     case EL_PFORTE2:            return(GFX_PFORTE2);
1790     case EL_PFORTE3:            return(GFX_PFORTE3);
1791     case EL_PFORTE4:            return(GFX_PFORTE4);
1792     case EL_PFORTE1X:           return(GFX_PFORTE1X);
1793     case EL_PFORTE2X:           return(GFX_PFORTE2X);
1794     case EL_PFORTE3X:           return(GFX_PFORTE3X);
1795     case EL_PFORTE4X:           return(GFX_PFORTE4X);
1796     case EL_DYNAMIT_AUS:        return(GFX_DYNAMIT_AUS);
1797     case EL_PACMAN:             return(GFX_PACMAN);
1798     case EL_PACMAN_R:           return(GFX_PACMAN_R);
1799     case EL_PACMAN_O:           return(GFX_PACMAN_O);
1800     case EL_PACMAN_L:           return(GFX_PACMAN_L);
1801     case EL_PACMAN_U:           return(GFX_PACMAN_U);
1802     case EL_UNSICHTBAR:         return(GFX_UNSICHTBAR);
1803     case EL_ERZ_EDEL:           return(GFX_ERZ_EDEL);
1804     case EL_ERZ_DIAM:           return(GFX_ERZ_DIAM);
1805     case EL_BIRNE_AUS:          return(GFX_BIRNE_AUS);
1806     case EL_BIRNE_EIN:          return(GFX_BIRNE_EIN);
1807     case EL_ZEIT_VOLL:          return(GFX_ZEIT_VOLL);
1808     case EL_ZEIT_LEER:          return(GFX_ZEIT_LEER);
1809     case EL_MAUER_LEBT:         return(GFX_MAUER_LEBT);
1810     case EL_MAUER_X:            return(GFX_MAUER_X);
1811     case EL_MAUER_Y:            return(GFX_MAUER_Y);
1812     case EL_MAUER_XY:           return(GFX_MAUER_XY);
1813     case EL_EDELSTEIN_BD:       return(GFX_EDELSTEIN_BD);
1814     case EL_EDELSTEIN_GELB:     return(GFX_EDELSTEIN_GELB);
1815     case EL_EDELSTEIN_ROT:      return(GFX_EDELSTEIN_ROT);
1816     case EL_EDELSTEIN_LILA:     return(GFX_EDELSTEIN_LILA);
1817     case EL_ERZ_EDEL_BD:        return(GFX_ERZ_EDEL_BD);
1818     case EL_ERZ_EDEL_GELB:      return(GFX_ERZ_EDEL_GELB);
1819     case EL_ERZ_EDEL_ROT:       return(GFX_ERZ_EDEL_ROT);
1820     case EL_ERZ_EDEL_LILA:      return(GFX_ERZ_EDEL_LILA);
1821     case EL_MAMPFER2:           return(GFX_MAMPFER2);
1822     case EL_SIEB2_LEER:         return(GFX_SIEB2_LEER);
1823     case EL_SIEB2_VOLL:         return(GFX_SIEB2_VOLL);
1824     case EL_SIEB2_TOT:          return(GFX_SIEB2_TOT);
1825     case EL_DYNABOMB:           return(GFX_DYNABOMB);
1826     case EL_DYNABOMB_NR:        return(GFX_DYNABOMB_NR);
1827     case EL_DYNABOMB_SZ:        return(GFX_DYNABOMB_SZ);
1828     case EL_DYNABOMB_XL:        return(GFX_DYNABOMB_XL);
1829     case EL_SOKOBAN_OBJEKT:     return(GFX_SOKOBAN_OBJEKT);
1830     case EL_SOKOBAN_FELD_LEER:  return(GFX_SOKOBAN_FELD_LEER);
1831     case EL_SOKOBAN_FELD_VOLL:  return(GFX_SOKOBAN_FELD_VOLL);
1832     case EL_MAULWURF:           return(GFX_MAULWURF);
1833     case EL_PINGUIN:            return(GFX_PINGUIN);
1834     case EL_SCHWEIN:            return(GFX_SCHWEIN);
1835     case EL_DRACHE:             return(GFX_DRACHE);
1836     case EL_SONDE:              return(GFX_SONDE);
1837     case EL_PFEIL_L:            return(GFX_PFEIL_L);
1838     case EL_PFEIL_R:            return(GFX_PFEIL_R);
1839     case EL_PFEIL_O:            return(GFX_PFEIL_O);
1840     case EL_PFEIL_U:            return(GFX_PFEIL_U);
1841     default:
1842     {
1843       if (IS_CHAR(element))
1844         return(GFX_CHAR_START + (element-EL_CHAR_START));
1845       else
1846         return(-1);
1847     }
1848   }
1849 }