rnd-19990314-1-src
[rocksndiamonds.git] / src / tools.c
1 /***********************************************************
2 *  Rocks'n'Diamonds -- McDuffin Strikes Back!              *
3 *----------------------------------------------------------*
4 *  (c) 1995-98 Artsoft Entertainment                       *
5 *              Holger Schemel                              *
6 *              Oststrasse 11a                              *
7 *              33604 Bielefeld                             *
8 *              phone: ++49 +521 290471                     *
9 *              email: aeglos@valinor.owl.de                *
10 *----------------------------------------------------------*
11 *  tools.c                                                 *
12 ***********************************************************/
13
14 #include <stdarg.h>
15
16 #ifdef __FreeBSD__
17 #include <machine/joystick.h>
18 #endif
19
20 #include "tools.h"
21 #include "game.h"
22 #include "events.h"
23 #include "sound.h"
24 #include "misc.h"
25 #include "buttons.h"
26 #include "joystick.h"
27 #include "cartoons.h"
28 #include "network.h"
29
30 #ifdef MSDOS
31 extern boolean wait_for_vsync;
32 #endif
33
34 /* tool button identifiers */
35 #define TOOL_CTRL_ID_YES        0
36 #define TOOL_CTRL_ID_NO         1
37 #define TOOL_CTRL_ID_CONFIRM    2
38 #define TOOL_CTRL_ID_PLAYER_1   3
39 #define TOOL_CTRL_ID_PLAYER_2   4
40 #define TOOL_CTRL_ID_PLAYER_3   5
41 #define TOOL_CTRL_ID_PLAYER_4   6
42
43 #define NUM_TOOL_BUTTONS        7
44
45 /* forward declaration for internal use */
46 static int getGraphicAnimationPhase(int, int, int);
47 static void UnmapToolButtons();
48 static void HandleToolButtons(struct GadgetInfo *);
49
50 static struct GadgetInfo *tool_gadget[NUM_TOOL_BUTTONS];
51 static int request_gadget_id = -1;
52
53 void SetDrawtoField(int mode)
54 {
55   if (mode == DRAW_BUFFERED && setup.soft_scrolling)
56   {
57     FX = TILEX;
58     FY = TILEY;
59     BX1 = -1;
60     BY1 = -1;
61     BX2 = SCR_FIELDX;
62     BY2 = SCR_FIELDY;
63     redraw_x1 = 1;
64     redraw_y1 = 1;
65
66     drawto_field = fieldbuffer;
67   }
68   else  /* DRAW_DIRECT, DRAW_BACKBUFFER */
69   {
70     FX = SX;
71     FY = SY;
72     BX1 = 0;
73     BY1 = 0;
74     BX2 = SCR_FIELDX - 1;
75     BY2 = SCR_FIELDY - 1;
76     redraw_x1 = 0;
77     redraw_y1 = 0;
78
79     drawto_field = (mode == DRAW_DIRECT ? window :  backbuffer);
80   }
81 }
82
83 void BackToFront()
84 {
85   int x,y;
86   Drawable buffer = (drawto_field == window ? backbuffer : drawto_field);
87
88   if (setup.direct_draw && game_status == PLAYING)
89     redraw_mask &= ~REDRAW_MAIN;
90
91   if (redraw_mask & REDRAW_TILES && redraw_tiles > REDRAWTILES_THRESHOLD)
92     redraw_mask |= REDRAW_FIELD;
93
94   if (redraw_mask & REDRAW_FIELD)
95     redraw_mask &= ~REDRAW_TILES;
96
97   if (!redraw_mask)
98     return;
99
100   /* synchronize X11 graphics at this point; if we would synchronize the
101      display immediately after the buffer switching (after the XFlush),
102      this could mean that we have to wait for the graphics to complete,
103      although we could go on doing calculations for the next frame */
104
105   XSync(display, FALSE);
106
107   if (redraw_mask & REDRAW_ALL)
108   {
109     XCopyArea(display, backbuffer, window, gc,
110               0, 0, WIN_XSIZE, WIN_YSIZE,
111               0, 0);
112     redraw_mask = 0;
113   }
114
115   if (redraw_mask & REDRAW_FIELD)
116   {
117     if (game_status != PLAYING || redraw_mask & REDRAW_FROM_BACKBUFFER)
118     {
119       XCopyArea(display, backbuffer, window, gc,
120                 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
121                 REAL_SX, REAL_SY);
122     }
123     else
124     {
125       int fx = FX, fy = FY;
126
127       if (setup.soft_scrolling)
128       {
129         fx += (ScreenMovDir & (MV_LEFT | MV_RIGHT) ? ScreenGfxPos : 0);
130         fy += (ScreenMovDir & (MV_UP | MV_DOWN)    ? ScreenGfxPos : 0);
131       }
132
133       if (setup.soft_scrolling ||
134           ABS(ScreenMovPos) + ScrollStepSize == TILEX ||
135           ABS(ScreenMovPos) == ScrollStepSize ||
136           redraw_tiles > REDRAWTILES_THRESHOLD)
137       {
138         XCopyArea(display, buffer, window, gc, fx, fy, SXSIZE, SYSIZE, SX, SY);
139
140 #ifdef DEBUG
141 #if 0
142         printf("redrawing all (ScreenGfxPos == %d) because %s\n",
143                ScreenGfxPos,
144                (setup.soft_scrolling ?
145                 "setup.soft_scrolling" :
146                 ABS(ScreenGfxPos) + ScrollStepSize == TILEX ?
147                 "ABS(ScreenGfxPos) + ScrollStepSize == TILEX" :
148                 ABS(ScreenGfxPos) == ScrollStepSize ?
149                 "ABS(ScreenGfxPos) == ScrollStepSize" :
150                 "redraw_tiles > REDRAWTILES_THRESHOLD"));
151 #endif
152 #endif
153       }
154     }
155     redraw_mask &= ~REDRAW_MAIN;
156   }
157
158   if (redraw_mask & REDRAW_DOORS)
159   {
160     if (redraw_mask & REDRAW_DOOR_1)
161       XCopyArea(display, backbuffer, window, gc,
162                 DX, DY, DXSIZE, DYSIZE,
163                 DX, DY);
164     if (redraw_mask & REDRAW_DOOR_2)
165     {
166       if ((redraw_mask & REDRAW_DOOR_2) == REDRAW_DOOR_2)
167         XCopyArea(display,backbuffer,window,gc,
168                   VX,VY, VXSIZE,VYSIZE,
169                   VX,VY);
170       else
171       {
172         if (redraw_mask & REDRAW_VIDEO_1)
173           XCopyArea(display,backbuffer,window,gc,
174                     VX+VIDEO_DISPLAY1_XPOS,VY+VIDEO_DISPLAY1_YPOS,
175                     VIDEO_DISPLAY_XSIZE,VIDEO_DISPLAY_YSIZE,
176                     VX+VIDEO_DISPLAY1_XPOS,VY+VIDEO_DISPLAY1_YPOS);
177         if (redraw_mask & REDRAW_VIDEO_2)
178           XCopyArea(display,backbuffer,window,gc,
179                     VX+VIDEO_DISPLAY2_XPOS,VY+VIDEO_DISPLAY2_YPOS,
180                     VIDEO_DISPLAY_XSIZE,VIDEO_DISPLAY_YSIZE,
181                     VX+VIDEO_DISPLAY2_XPOS,VY+VIDEO_DISPLAY2_YPOS);
182         if (redraw_mask & REDRAW_VIDEO_3)
183           XCopyArea(display,backbuffer,window,gc,
184                     VX+VIDEO_CONTROL_XPOS,VY+VIDEO_CONTROL_YPOS,
185                     VIDEO_CONTROL_XSIZE,VIDEO_CONTROL_YSIZE,
186                     VX+VIDEO_CONTROL_XPOS,VY+VIDEO_CONTROL_YPOS);
187       }
188     }
189     if (redraw_mask & REDRAW_DOOR_3)
190       XCopyArea(display, backbuffer, window, gc,
191                 EX, EY, EXSIZE, EYSIZE,
192                 EX, EY);
193     redraw_mask &= ~REDRAW_DOORS;
194   }
195
196   if (redraw_mask & REDRAW_MICROLEVEL)
197   {
198     XCopyArea(display,backbuffer,window,gc,
199               MICROLEV_XPOS, MICROLEV_YPOS, MICROLEV_XSIZE, MICROLEV_YSIZE,
200               MICROLEV_XPOS, MICROLEV_YPOS);
201     XCopyArea(display,backbuffer,window,gc,
202               SX, MICROLABEL_YPOS, SXSIZE, FONT4_YSIZE,
203               SX, MICROLABEL_YPOS);
204     redraw_mask &= ~REDRAW_MICROLEVEL;
205   }
206
207   if (redraw_mask & REDRAW_TILES)
208   {
209     for(x=0; x<SCR_FIELDX; x++)
210       for(y=0; y<SCR_FIELDY; y++)
211         if (redraw[redraw_x1 + x][redraw_y1 + y])
212           XCopyArea(display, buffer, window, gc,
213                     FX + x * TILEX, FX + y * TILEY, TILEX, TILEY,
214                     SX + x * TILEX, SY + y * TILEY);
215   }
216
217   XFlush(display);
218
219   for(x=0; x<MAX_BUF_XSIZE; x++)
220     for(y=0; y<MAX_BUF_YSIZE; y++)
221       redraw[x][y] = 0;
222   redraw_tiles = 0;
223   redraw_mask = 0;
224 }
225
226 void FadeToFront()
227 {
228 /*
229   long fading_delay = 300;
230
231   if (setup.fading && (redraw_mask & REDRAW_FIELD))
232   {
233 */
234
235 /*
236     int x,y;
237
238     XFillRectangle(display,window,gc,
239                    REAL_SX,REAL_SY,FULL_SXSIZE,FULL_SYSIZE);
240     XFlush(display);
241
242     for(i=0;i<2*FULL_SYSIZE;i++)
243     {
244       for(y=0;y<FULL_SYSIZE;y++)
245       {
246         XCopyArea(display,backbuffer,window,gc,
247                   REAL_SX,REAL_SY+i, FULL_SXSIZE,1, REAL_SX,REAL_SY+i);
248       }
249       XFlush(display);
250       Delay(10);
251     }
252 */
253
254 /*
255     for(i=1;i<FULL_SYSIZE;i+=2)
256       XCopyArea(display,backbuffer,window,gc,
257                 REAL_SX,REAL_SY+i, FULL_SXSIZE,1, REAL_SX,REAL_SY+i);
258     XFlush(display);
259     Delay(fading_delay);
260 */
261
262 /*
263     XSetClipOrigin(display,clip_gc[PIX_FADEMASK],0,0);
264     XCopyArea(display,backbuffer,window,clip_gc[PIX_FADEMASK],
265               REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE, REAL_SX,REAL_SY);
266     XFlush(display);
267     Delay(fading_delay);
268
269     XSetClipOrigin(display,clip_gc[PIX_FADEMASK],-1,-1);
270     XCopyArea(display,backbuffer,window,clip_gc[PIX_FADEMASK],
271               REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE, REAL_SX,REAL_SY);
272     XFlush(display);
273     Delay(fading_delay);
274
275     XSetClipOrigin(display,clip_gc[PIX_FADEMASK],0,-1);
276     XCopyArea(display,backbuffer,window,clip_gc[PIX_FADEMASK],
277               REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE, REAL_SX,REAL_SY);
278     XFlush(display);
279     Delay(fading_delay);
280
281     XSetClipOrigin(display,clip_gc[PIX_FADEMASK],-1,0);
282     XCopyArea(display,backbuffer,window,clip_gc[PIX_FADEMASK],
283               REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE, REAL_SX,REAL_SY);
284     XFlush(display);
285     Delay(fading_delay);
286
287     redraw_mask &= ~REDRAW_MAIN;
288   }
289 */
290
291   BackToFront();
292 }
293
294 void ClearWindow()
295 {
296   XFillRectangle(display, backbuffer, gc,
297                  REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
298
299   if (setup.soft_scrolling && game_status == PLAYING)
300   {
301     XFillRectangle(display, fieldbuffer, gc, 0, 0, FXSIZE, FYSIZE);
302     SetDrawtoField(DRAW_BUFFERED);
303   }
304   else
305     SetDrawtoField(DRAW_BACKBUFFER);
306
307   if (setup.direct_draw && game_status == PLAYING)
308   {
309     XFillRectangle(display, window, gc,
310                    REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
311     SetDrawtoField(DRAW_DIRECT);
312   }
313
314   redraw_mask |= REDRAW_FIELD;
315 }
316
317 int getFontWidth(int font_size, int font_type)
318 {
319   return (font_size == FS_BIG ? FONT1_XSIZE :
320           font_type == FC_SPECIAL1 ? FONT3_XSIZE :
321           font_type == FC_SPECIAL2 ? FONT4_XSIZE :
322           font_type == FC_SPECIAL3 ? FONT5_XSIZE :
323           FONT2_XSIZE);
324 }
325
326 int getFontHeight(int font_size, int font_type)
327 {
328   return (font_size == FS_BIG ? FONT1_YSIZE :
329           font_type == FC_SPECIAL1 ? FONT3_YSIZE :
330           font_type == FC_SPECIAL2 ? FONT4_YSIZE :
331           font_type == FC_SPECIAL3 ? FONT5_YSIZE :
332           FONT2_YSIZE);
333 }
334
335 void DrawTextFCentered(int y, int font_type, char *format, ...)
336 {
337   char buffer[FULL_SXSIZE / FONT5_XSIZE + 10];
338   int font_width = getFontWidth(FS_SMALL, font_type);
339   va_list ap;
340
341   va_start(ap, format);
342   vsprintf(buffer, format, ap);
343   va_end(ap);
344
345   DrawText(SX + (SXSIZE - strlen(buffer) * font_width) / 2, SY + y,
346            buffer, FS_SMALL, font_type);
347 }
348
349 void DrawTextF(int x, int y, int font_type, char *format, ...)
350 {
351   char buffer[FULL_SXSIZE / FONT5_XSIZE + 10];
352   va_list ap;
353
354   va_start(ap, format);
355   vsprintf(buffer, format, ap);
356   va_end(ap);
357
358   DrawText(SX + x, SY + y, buffer, FS_SMALL, font_type);
359 }
360
361 void DrawText(int x, int y, char *text, int font_size, int font_type)
362 {
363   DrawTextExt(drawto, gc, x, y, text, font_size, font_type);
364
365   if (x < DX)
366     redraw_mask |= REDRAW_FIELD;
367   else if (y < VY)
368     redraw_mask |= REDRAW_DOOR_1;
369 }
370
371 void DrawTextExt(Drawable d, GC gc, int x, int y,
372                  char *text, int font_size, int font_type)
373 {
374   int font_width, font_height, font_start;
375   int font_pixmap;
376   boolean print_inverse = FALSE;
377
378   if (font_size != FS_SMALL && font_size != FS_BIG)
379     font_size = FS_SMALL;
380   if (font_type < FC_RED || font_type > FC_SPECIAL3)
381     font_type = FC_RED;
382
383   font_width = getFontWidth(font_size, font_type);
384   font_height = getFontHeight(font_size, font_type);
385
386   font_pixmap = (font_size == FS_BIG ? PIX_BIGFONT : PIX_SMALLFONT);
387   font_start = (font_type * (font_size == FS_BIG ? FONT1_YSIZE : FONT2_YSIZE) *
388                 FONT_LINES_PER_FONT);
389
390   if (font_type == FC_SPECIAL3)
391     font_start += (FONT4_YSIZE - FONT2_YSIZE) * FONT_LINES_PER_FONT;
392
393   while (*text)
394   {
395     char c = *text++;
396
397     if (c == '~' && font_size == FS_SMALL)
398     {
399       print_inverse = TRUE;
400       continue;
401     }
402
403     if (c >= 'a' && c <= 'z')
404       c = 'A' + (c - 'a');
405     else if (c == 'ä' || c == 'Ä')
406       c = 91;
407     else if (c == 'ö' || c == 'Ö')
408       c = 92;
409     else if (c == 'ü' || c == 'Ãœ')
410       c = 93;
411
412     if (c >= 32 && c <= 95)
413     {
414       int src_x = ((c - 32) % FONT_CHARS_PER_LINE) * font_width;
415       int src_y = ((c - 32) / FONT_CHARS_PER_LINE) * font_height + font_start;
416       int dest_x = x, dest_y = y;
417
418       if (print_inverse)
419       {
420         XCopyArea(display, pix[font_pixmap], d, gc,
421                   FONT_CHARS_PER_LINE * font_width,
422                   3 * font_height + font_start,
423                   font_width, font_height, x, y);
424
425         XSetClipOrigin(display, clip_gc[font_pixmap],
426                        dest_x - src_x, dest_y - src_y);
427         XCopyArea(display, pix[font_pixmap], d, clip_gc[font_pixmap],
428                   0, 0, font_width, font_height, dest_x, dest_y);
429       }
430       else
431         XCopyArea(display, pix[font_pixmap], d, gc,
432                   src_x, src_y, font_width, font_height, dest_x, dest_y);
433     }
434
435     x += font_width;
436   }
437 }
438
439 void DrawAllPlayers()
440 {
441   int i;
442
443   for(i=0; i<MAX_PLAYERS; i++)
444     if (stored_player[i].active)
445       DrawPlayer(&stored_player[i]);
446 }
447
448 void DrawPlayerField(int x, int y)
449 {
450   if (!IS_PLAYER(x, y))
451     return;
452
453   DrawPlayer(PLAYERINFO(x, y));
454 }
455
456 void DrawPlayer(struct PlayerInfo *player)
457 {
458   int jx = player->jx, jy = player->jy;
459   int last_jx = player->last_jx, last_jy = player->last_jy;
460   int next_jx = jx + (jx - last_jx), next_jy = jy + (jy - last_jy);
461   int sx = SCREENX(jx), sy = SCREENY(jy);
462   int sxx = 0, syy = 0;
463   int element = Feld[jx][jy], last_element = Feld[last_jx][last_jy];
464   int graphic, phase;
465   boolean player_is_moving = (last_jx != jx || last_jy != jy ? TRUE : FALSE);
466
467   if (!player->active || !IN_SCR_FIELD(SCREENX(last_jx), SCREENY(last_jy)))
468     return;
469
470 #if DEBUG
471   if (!IN_LEV_FIELD(jx,jy))
472   {
473     printf("DrawPlayerField(): x = %d, y = %d\n",jx,jy);
474     printf("DrawPlayerField(): sx = %d, sy = %d\n",sx,sy);
475     printf("DrawPlayerField(): This should never happen!\n");
476     return;
477   }
478 #endif
479
480   if (element == EL_EXPLODING)
481     return;
482
483   /* draw things in the field the player is leaving, if needed */
484
485   if (player_is_moving)
486   {
487     if (Store[last_jx][last_jy] && IS_DRAWABLE(last_element))
488     {
489       DrawLevelElement(last_jx, last_jy, Store[last_jx][last_jy]);
490       DrawLevelFieldThruMask(last_jx, last_jy);
491     }
492     else if (last_element == EL_DYNAMITE_ACTIVE)
493       DrawDynamite(last_jx, last_jy);
494     else
495       DrawLevelField(last_jx, last_jy);
496
497     if (player->Pushing && IN_SCR_FIELD(SCREENX(next_jx), SCREENY(next_jy)))
498     {
499       if (player->GfxPos)
500       {
501         if (Feld[next_jx][next_jy] == EL_SOKOBAN_FELD_VOLL)
502           DrawLevelElement(next_jx, next_jy, EL_SOKOBAN_FELD_LEER);
503         else
504           DrawLevelElement(next_jx, next_jy, EL_LEERRAUM);
505       }
506       else
507         DrawLevelField(next_jx, next_jy);
508     }
509   }
510
511   if (!IN_SCR_FIELD(sx, sy))
512     return;
513
514   if (setup.direct_draw)
515     SetDrawtoField(DRAW_BUFFERED);
516
517   /* draw things behind the player, if needed */
518
519   if (Store[jx][jy])
520     DrawLevelElement(jx, jy, Store[jx][jy]);
521   else if (!IS_ACTIVE_BOMB(element))
522     DrawLevelField(jx, jy);
523
524   /* draw player himself */
525
526   if (game.emulation == EMU_SUPAPLEX)
527   {
528     static int last_dir = MV_LEFT;
529     int action = (player->programmed_action ? player->programmed_action :
530                   player->action);
531     boolean action_moving =
532       (player_is_moving ||
533        ((action & (MV_LEFT | MV_RIGHT | MV_UP | MV_DOWN)) &&
534         !(action & ~(MV_LEFT | MV_RIGHT | MV_UP | MV_DOWN))));
535
536     graphic = GFX_SP_MURPHY;
537
538     if (player->Pushing)
539     {
540       if (player->MovDir == MV_LEFT)
541         graphic = GFX_MURPHY_PUSH_LEFT;
542       else if (player->MovDir == MV_RIGHT)
543         graphic = GFX_MURPHY_PUSH_RIGHT;
544       else if (player->MovDir & (MV_UP | MV_DOWN) && last_dir == MV_LEFT)
545         graphic = GFX_MURPHY_PUSH_LEFT;
546       else if (player->MovDir & (MV_UP | MV_DOWN) && last_dir == MV_RIGHT)
547         graphic = GFX_MURPHY_PUSH_RIGHT;
548     }
549     else if (player->snapped)
550     {
551       if (player->MovDir == MV_LEFT)
552         graphic = GFX_MURPHY_SNAP_LEFT;
553       else if (player->MovDir == MV_RIGHT)
554         graphic = GFX_MURPHY_SNAP_RIGHT;
555       else if (player->MovDir == MV_UP)
556         graphic = GFX_MURPHY_SNAP_UP;
557       else if (player->MovDir == MV_DOWN)
558         graphic = GFX_MURPHY_SNAP_DOWN;
559     }
560     else if (action_moving)
561     {
562       if (player->MovDir == MV_LEFT)
563         graphic = GFX_MURPHY_GO_LEFT;
564       else if (player->MovDir == MV_RIGHT)
565         graphic = GFX_MURPHY_GO_RIGHT;
566       else if (player->MovDir & (MV_UP | MV_DOWN) && last_dir == MV_LEFT)
567         graphic = GFX_MURPHY_GO_LEFT;
568       else if (player->MovDir & (MV_UP | MV_DOWN) && last_dir == MV_RIGHT)
569         graphic = GFX_MURPHY_GO_RIGHT;
570
571       graphic += getGraphicAnimationPhase(3, 2, ANIM_OSCILLATE);
572     }
573
574     if (player->MovDir == MV_LEFT || player->MovDir == MV_RIGHT)
575       last_dir = player->MovDir;
576   }
577   else
578   {
579     if (player->MovDir == MV_LEFT)
580       graphic =
581         (player->Pushing ? GFX_SPIELER1_PUSH_LEFT : GFX_SPIELER1_LEFT);
582     else if (player->MovDir == MV_RIGHT)
583       graphic =
584         (player->Pushing ? GFX_SPIELER1_PUSH_RIGHT : GFX_SPIELER1_RIGHT);
585     else if (player->MovDir == MV_UP)
586       graphic = GFX_SPIELER1_UP;
587     else        /* MV_DOWN || MV_NO_MOVING */
588       graphic = GFX_SPIELER1_DOWN;
589
590     graphic += player->index_nr * 3 * HEROES_PER_LINE;
591     graphic += player->Frame;
592   }
593
594   if (player->GfxPos)
595   {
596     if (player->MovDir == MV_LEFT || player->MovDir == MV_RIGHT)
597       sxx = player->GfxPos;
598     else
599       syy = player->GfxPos;
600   }
601
602   if (!setup.soft_scrolling && ScreenMovPos)
603     sxx = syy = 0;
604
605   DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, NO_CUTTING);
606
607   if (player->Pushing && player->GfxPos)
608   {
609     int px = SCREENX(next_jx), py = SCREENY(next_jy);
610
611     if (element == EL_SOKOBAN_FELD_LEER ||
612         Feld[next_jx][next_jy] == EL_SOKOBAN_FELD_VOLL)
613       DrawGraphicShiftedThruMask(px, py, sxx, syy, GFX_SOKOBAN_OBJEKT,
614                                  NO_CUTTING);
615     else
616     {
617       int element = Feld[next_jx][next_jy];
618       int graphic = el2gfx(element);
619
620       if ((element == EL_FELSBROCKEN || element == EL_SP_ZONK) && sxx)
621       {
622         int phase = (player->GfxPos / (TILEX / 4));
623
624         if (player->MovDir == MV_LEFT)
625           graphic += phase;
626         else
627           graphic += (phase + 4) % 4;
628       }
629
630       DrawGraphicShifted(px, py, sxx, syy, graphic, NO_CUTTING, NO_MASKING);
631     }
632   }
633
634   /* draw things in front of player (active dynamite or dynabombs) */
635
636   if (IS_ACTIVE_BOMB(element))
637   {
638     graphic = el2gfx(element);
639
640     if (element == EL_DYNAMITE_ACTIVE)
641     {
642       if ((phase = (96 - MovDelay[jx][jy]) / 12) > 6)
643         phase = 6;
644     }
645     else
646     {
647       if ((phase = ((96 - MovDelay[jx][jy]) / 6) % 8) > 3)
648         phase = 7 - phase;
649     }
650
651     if (game.emulation == EMU_SUPAPLEX)
652       DrawGraphic(sx, sy, GFX_SP_DISK_RED);
653     else
654       DrawGraphicThruMask(sx, sy, graphic + phase);
655   }
656
657   if (player_is_moving && last_element == EL_EXPLODING)
658   {
659     int phase = Frame[last_jx][last_jy];
660     int delay = 2;
661
662     if (phase > 2)
663       DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy),
664                           GFX_EXPLOSION + ((phase - 1) / delay - 1));
665   }
666
667   /* draw elements that stay over the player */
668   /* handle the field the player is leaving ... */
669   if (player_is_moving && IS_OVER_PLAYER(last_element))
670     DrawLevelField(last_jx, last_jy);
671   /* ... and the field the player is entering */
672   if (IS_OVER_PLAYER(element))
673     DrawLevelField(jx, jy);
674
675   if (setup.direct_draw)
676   {
677     int dest_x = SX + SCREENX(MIN(jx, last_jx)) * TILEX;
678     int dest_y = SY + SCREENY(MIN(jy, last_jy)) * TILEY;
679     int x_size = TILEX * (1 + ABS(jx - last_jx));
680     int y_size = TILEY * (1 + ABS(jy - last_jy));
681
682     XCopyArea(display, drawto_field, window, gc,
683               dest_x, dest_y, x_size, y_size, dest_x, dest_y);
684     SetDrawtoField(DRAW_DIRECT);
685   }
686
687   MarkTileDirty(sx,sy);
688 }
689
690 static int getGraphicAnimationPhase(int frames, int delay, int mode)
691 {
692   int phase;
693
694   if (mode == ANIM_OSCILLATE)
695   {
696     int max_anim_frames = 2 * frames - 2;
697     phase = (FrameCounter % (delay * max_anim_frames)) / delay;
698     phase = (phase < frames ? phase : max_anim_frames - phase);
699   }
700   else
701     phase = (FrameCounter % (delay * frames)) / delay;
702
703   if (mode == ANIM_REVERSE)
704     phase = -phase;
705
706   return(phase);
707 }
708
709 void DrawGraphicAnimationExt(int x, int y, int graphic,
710                              int frames, int delay, int mode, int mask_mode)
711 {
712   int phase = getGraphicAnimationPhase(frames, delay, mode);
713
714   if (!(FrameCounter % delay) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
715   {
716     if (mask_mode == USE_MASKING)
717       DrawGraphicThruMask(SCREENX(x), SCREENY(y), graphic + phase);
718     else
719       DrawGraphic(SCREENX(x), SCREENY(y), graphic + phase);
720   }
721 }
722
723 void DrawGraphicAnimation(int x, int y, int graphic,
724                           int frames, int delay, int mode)
725 {
726   DrawGraphicAnimationExt(x, y, graphic, frames, delay, mode, NO_MASKING);
727 }
728
729 void DrawGraphicAnimationThruMask(int x, int y, int graphic,
730                                   int frames, int delay, int mode)
731 {
732   DrawGraphicAnimationExt(x, y, graphic, frames, delay, mode, USE_MASKING);
733 }
734
735 void getGraphicSource(int graphic, int *pixmap_nr, int *x, int *y)
736 {
737   if (graphic >= GFX_START_ROCKSSCREEN && graphic <= GFX_END_ROCKSSCREEN)
738   {
739     graphic -= GFX_START_ROCKSSCREEN;
740     *pixmap_nr = PIX_BACK;
741     *x = SX + (graphic % GFX_PER_LINE) * TILEX;
742     *y = SY + (graphic / GFX_PER_LINE) * TILEY;
743   }
744   else if (graphic >= GFX_START_ROCKSMORE && graphic <= GFX_END_ROCKSMORE)
745   {
746     graphic -= GFX_START_ROCKSMORE;
747     *pixmap_nr = PIX_MORE;
748     *x = (graphic % MORE_PER_LINE) * TILEX;
749     *y = (graphic / MORE_PER_LINE) * TILEY;
750   }
751   else if (graphic >= GFX_START_ROCKSHEROES && graphic <= GFX_END_ROCKSHEROES)
752   {
753     graphic -= GFX_START_ROCKSHEROES;
754     *pixmap_nr = PIX_HEROES;
755     *x = (graphic % HEROES_PER_LINE) * TILEX;
756     *y = (graphic / HEROES_PER_LINE) * TILEY;
757   }
758   else if (graphic >= GFX_START_ROCKSFONT && graphic <= GFX_END_ROCKSFONT)
759   {
760     graphic -= GFX_START_ROCKSFONT;
761     *pixmap_nr = PIX_BIGFONT;
762     *x = (graphic % FONT_CHARS_PER_LINE) * TILEX;
763     *y = ((graphic / FONT_CHARS_PER_LINE) * TILEY +
764           FC_SPECIAL1 * FONT_LINES_PER_FONT * TILEY);
765   }
766   else
767   {
768     *pixmap_nr = PIX_MORE;
769     *x = 0;
770     *y = 0;
771   }
772 }
773
774 void DrawGraphic(int x, int y, int graphic)
775 {
776 #if DEBUG
777   if (!IN_SCR_FIELD(x,y))
778   {
779     printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
780     printf("DrawGraphic(): This should never happen!\n");
781     return;
782   }
783 #endif
784
785   DrawGraphicExt(drawto_field, gc, FX + x*TILEX, FY + y*TILEY, graphic);
786   MarkTileDirty(x,y);
787 }
788
789 void DrawGraphicExt(Drawable d, GC gc, int x, int y, int graphic)
790 {
791   int pixmap_nr;
792   int src_x, src_y;
793
794   getGraphicSource(graphic, &pixmap_nr, &src_x, &src_y);
795   XCopyArea(display, pix[pixmap_nr], d, gc,
796             src_x, src_y, TILEX, TILEY, x, y);
797 }
798
799 void DrawGraphicThruMask(int x, int y, int graphic)
800 {
801 #if DEBUG
802   if (!IN_SCR_FIELD(x,y))
803   {
804     printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
805     printf("DrawGraphicThruMask(): This should never happen!\n");
806     return;
807   }
808 #endif
809
810   DrawGraphicThruMaskExt(drawto_field, FX + x*TILEX, FY + y*TILEY, graphic);
811   MarkTileDirty(x,y);
812 }
813
814 void DrawGraphicThruMaskExt(Drawable d, int dest_x, int dest_y, int graphic)
815 {
816   int tile = graphic;
817   int pixmap_nr;
818   int src_x, src_y;
819   Pixmap src_pixmap;
820   GC drawing_gc;
821
822   if (graphic == GFX_LEERRAUM)
823     return;
824
825   getGraphicSource(graphic, &pixmap_nr, &src_x, &src_y);
826   src_pixmap = pix[pixmap_nr];
827   drawing_gc = clip_gc[pixmap_nr];
828
829   if (tile_clipmask[tile] != None)
830   {
831     XSetClipMask(display, tile_clip_gc, tile_clipmask[tile]);
832     XSetClipOrigin(display, tile_clip_gc, dest_x, dest_y);
833     XCopyArea(display, src_pixmap, d, tile_clip_gc,
834               src_x, src_y, TILEX, TILEY, dest_x, dest_y);
835   }
836   else
837   {
838 #if DEBUG
839     printf("DrawGraphicThruMask(): tile '%d' needs clipping!\n", tile);
840 #endif
841
842     XSetClipOrigin(display, drawing_gc, dest_x-src_x, dest_y-src_y);
843     XCopyArea(display, src_pixmap, d, drawing_gc,
844               src_x, src_y, TILEX, TILEY, dest_x, dest_y);
845   }
846 }
847
848 void DrawMiniGraphic(int x, int y, int graphic)
849 {
850   DrawMiniGraphicExt(drawto,gc, SX + x*MINI_TILEX, SY + y*MINI_TILEY, graphic);
851   MarkTileDirty(x/2, y/2);
852 }
853
854 void getMiniGraphicSource(int graphic, Pixmap *pixmap, int *x, int *y)
855 {
856   if (graphic >= GFX_START_ROCKSSCREEN && graphic <= GFX_END_ROCKSSCREEN)
857   {
858     graphic -= GFX_START_ROCKSSCREEN;
859     *pixmap = pix[PIX_BACK];
860     *x = MINI_GFX_STARTX + (graphic % MINI_GFX_PER_LINE) * MINI_TILEX;
861     *y = MINI_GFX_STARTY + (graphic / MINI_GFX_PER_LINE) * MINI_TILEY;
862   }
863   else if (graphic >= GFX_START_ROCKSMORE && graphic <= GFX_END_ROCKSMORE)
864   {
865     graphic -= GFX_START_ROCKSMORE;
866     graphic -= ((graphic / MORE_PER_LINE) * MORE_PER_LINE) / 2;
867     *pixmap = pix[PIX_MORE];
868     *x = MINI_MORE_STARTX + (graphic % MINI_MORE_PER_LINE) * MINI_TILEX;
869     *y = MINI_MORE_STARTY + (graphic / MINI_MORE_PER_LINE) * MINI_TILEY;
870   }
871   else if (graphic >= GFX_START_ROCKSFONT && graphic <= GFX_END_ROCKSFONT)
872   {
873     graphic -= GFX_START_ROCKSFONT;
874     *pixmap = pix[PIX_SMALLFONT];
875     *x = (graphic % FONT_CHARS_PER_LINE) * FONT4_XSIZE;
876     *y = ((graphic / FONT_CHARS_PER_LINE) * FONT4_YSIZE +
877               FC_SPECIAL2 * FONT2_YSIZE * FONT_LINES_PER_FONT);
878   }
879   else
880   {
881     *pixmap = pix[PIX_MORE];
882     *x = MINI_MORE_STARTX;
883     *y = MINI_MORE_STARTY;
884   }
885 }
886
887 void DrawMiniGraphicExt(Drawable d, GC gc, int x, int y, int graphic)
888 {
889   Pixmap pixmap;
890   int src_x, src_y;
891
892   getMiniGraphicSource(graphic, &pixmap, &src_x, &src_y);
893   XCopyArea(display, pixmap, d, gc,
894             src_x, src_y, MINI_TILEX, MINI_TILEY, x, y);
895 }
896
897 void DrawGraphicShifted(int x,int y, int dx,int dy, int graphic,
898                         int cut_mode, int mask_mode)
899 {
900   int width = TILEX, height = TILEY;
901   int cx = 0, cy = 0;
902   int src_x, src_y, dest_x, dest_y;
903   int tile = graphic;
904   int pixmap_nr;
905   Pixmap src_pixmap;
906   GC drawing_gc;
907
908   if (graphic < 0)
909   {
910     DrawGraphic(x, y, graphic);
911     return;
912   }
913
914   if (dx || dy)                 /* Verschiebung der Grafik? */
915   {
916     if (x < BX1)                /* Element kommt von links ins Bild */
917     {
918       x = BX1;
919       width = dx;
920       cx = TILEX - dx;
921       dx = 0;
922     }
923     else if (x > BX2)           /* Element kommt von rechts ins Bild */
924     {
925       x = BX2;
926       width = -dx;
927       dx = TILEX + dx;
928     }
929     else if (x==BX1 && dx < 0)  /* Element verläßt links das Bild */
930     {
931       width += dx;
932       cx = -dx;
933       dx = 0;
934     }
935     else if (x==BX2 && dx > 0)  /* Element verläßt rechts das Bild */
936       width -= dx;
937     else if (dx)                /* allg. Bewegung in x-Richtung */
938       MarkTileDirty(x + SIGN(dx), y);
939
940     if (y < BY1)                /* Element kommt von oben ins Bild */
941     {
942       if (cut_mode==CUT_BELOW)  /* Element oberhalb des Bildes */
943         return;
944
945       y = BY1;
946       height = dy;
947       cy = TILEY - dy;
948       dy = 0;
949     }
950     else if (y > BY2)           /* Element kommt von unten ins Bild */
951     {
952       y = BY2;
953       height = -dy;
954       dy = TILEY + dy;
955     }
956     else if (y==BY1 && dy < 0)  /* Element verläßt oben das Bild */
957     {
958       height += dy;
959       cy = -dy;
960       dy = 0;
961     }
962     else if (dy > 0 && cut_mode == CUT_ABOVE)
963     {
964       if (y == BY2)             /* Element unterhalb des Bildes */
965         return;
966
967       height = dy;
968       cy = TILEY - dy;
969       dy = TILEY;
970       MarkTileDirty(x, y + 1);
971     }                           /* Element verläßt unten das Bild */
972     else if (dy > 0 && (y == BY2 || cut_mode == CUT_BELOW))
973       height -= dy;
974     else if (dy)                /* allg. Bewegung in y-Richtung */
975       MarkTileDirty(x, y + SIGN(dy));
976   }
977
978   getGraphicSource(graphic, &pixmap_nr, &src_x, &src_y);
979   src_pixmap = pix[pixmap_nr];
980   drawing_gc = clip_gc[pixmap_nr];
981
982   src_x += cx;
983   src_y += cy;
984
985   dest_x = FX + x * TILEX + dx;
986   dest_y = FY + y * TILEY + dy;
987
988 #if DEBUG
989   if (!IN_SCR_FIELD(x,y))
990   {
991     printf("DrawGraphicShifted(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
992     printf("DrawGraphicShifted(): This should never happen!\n");
993     return;
994   }
995 #endif
996
997   if (mask_mode == USE_MASKING)
998   {
999     if (tile_clipmask[tile] != None)
1000     {
1001       XSetClipMask(display, tile_clip_gc, tile_clipmask[tile]);
1002       XSetClipOrigin(display, tile_clip_gc, dest_x, dest_y);
1003       XCopyArea(display, src_pixmap, drawto_field, tile_clip_gc,
1004                 src_x, src_y, TILEX, TILEY, dest_x, dest_y);
1005     }
1006     else
1007     {
1008 #if DEBUG
1009       printf("DrawGraphicShifted(): tile '%d' needs clipping!\n", tile);
1010 #endif
1011
1012       XSetClipOrigin(display, drawing_gc, dest_x - src_x, dest_y - src_y);
1013       XCopyArea(display, src_pixmap, drawto_field, drawing_gc,
1014                 src_x, src_y, width, height, dest_x, dest_y);
1015     }
1016   }
1017   else
1018     XCopyArea(display, src_pixmap, drawto_field, gc,
1019               src_x, src_y, width, height, dest_x, dest_y);
1020
1021   MarkTileDirty(x,y);
1022 }
1023
1024 void DrawGraphicShiftedThruMask(int x,int y, int dx,int dy, int graphic,
1025                                 int cut_mode)
1026 {
1027   DrawGraphicShifted(x,y, dx,dy, graphic, cut_mode, USE_MASKING);
1028 }
1029
1030 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
1031                           int cut_mode, int mask_mode)
1032 {
1033   int ux = LEVELX(x), uy = LEVELY(y);
1034   int graphic = el2gfx(element);
1035   int phase8 = ABS(MovPos[ux][uy]) / (TILEX / 8);
1036   int phase4 = phase8 / 2;
1037   int phase2  = phase8 / 4;
1038   int dir = MovDir[ux][uy];
1039
1040   if (element == EL_PACMAN || element == EL_KAEFER || element == EL_FLIEGER)
1041   {
1042     graphic += 4 * !phase2;
1043
1044     if (dir == MV_UP)
1045       graphic += 1;
1046     else if (dir == MV_LEFT)
1047       graphic += 2;
1048     else if (dir == MV_DOWN)
1049       graphic += 3;
1050   }
1051   else if (element == EL_SP_SNIKSNAK)
1052   {
1053     if (dir == MV_LEFT)
1054       graphic = GFX_SP_SNIKSNAK_LEFT;
1055     else if (dir == MV_RIGHT)
1056       graphic = GFX_SP_SNIKSNAK_RIGHT;
1057     else if (dir == MV_UP)
1058       graphic = GFX_SP_SNIKSNAK_UP;
1059     else
1060       graphic = GFX_SP_SNIKSNAK_DOWN;
1061
1062     graphic += (phase8 < 4 ? phase8 : 7 - phase8);
1063   }
1064   else if (element == EL_SP_ELECTRON)
1065   {
1066     graphic = GFX2_SP_ELECTRON + getGraphicAnimationPhase(8, 2, ANIM_NORMAL);
1067   }
1068   else if (element == EL_MAULWURF || element == EL_PINGUIN ||
1069            element == EL_SCHWEIN || element == EL_DRACHE)
1070   {
1071     if (dir == MV_LEFT)
1072       graphic = (element == EL_MAULWURF ? GFX_MAULWURF_LEFT :
1073                  element == EL_PINGUIN ? GFX_PINGUIN_LEFT :
1074                  element == EL_SCHWEIN ? GFX_SCHWEIN_LEFT : GFX_DRACHE_LEFT);
1075     else if (dir == MV_RIGHT)
1076       graphic = (element == EL_MAULWURF ? GFX_MAULWURF_RIGHT :
1077                  element == EL_PINGUIN ? GFX_PINGUIN_RIGHT :
1078                  element == EL_SCHWEIN ? GFX_SCHWEIN_RIGHT : GFX_DRACHE_RIGHT);
1079     else if (dir == MV_UP)
1080       graphic = (element == EL_MAULWURF ? GFX_MAULWURF_UP :
1081                  element == EL_PINGUIN ? GFX_PINGUIN_UP :
1082                  element == EL_SCHWEIN ? GFX_SCHWEIN_UP : GFX_DRACHE_UP);
1083     else
1084       graphic = (element == EL_MAULWURF ? GFX_MAULWURF_DOWN :
1085                  element == EL_PINGUIN ? GFX_PINGUIN_DOWN :
1086                  element == EL_SCHWEIN ? GFX_SCHWEIN_DOWN : GFX_DRACHE_DOWN);
1087
1088     graphic += phase4;
1089   }
1090   else if (element == EL_SONDE)
1091   {
1092     graphic = GFX_SONDE_START + getGraphicAnimationPhase(8, 2, ANIM_NORMAL);
1093   }
1094   else if (element == EL_SALZSAEURE)
1095   {
1096     graphic = GFX_GEBLUBBER + getGraphicAnimationPhase(4, 10, ANIM_NORMAL);
1097   }
1098   else if (element == EL_BUTTERFLY || element == EL_FIREFLY)
1099   {
1100     graphic += !phase2;
1101   }
1102   else if ((element == EL_FELSBROCKEN || element == EL_SP_ZONK ||
1103             IS_GEM(element)) && !cut_mode)
1104   {
1105     if (element == EL_FELSBROCKEN || element == EL_SP_ZONK)
1106     {
1107       if (dir == MV_LEFT)
1108         graphic += (4 - phase4) % 4;
1109       else if (dir == MV_RIGHT)
1110         graphic += phase4;
1111       else
1112         graphic += phase2 * 2;
1113     }
1114     else if (element != EL_SP_INFOTRON)
1115       graphic += phase2;
1116   }
1117   else if (element == EL_SIEB_LEER || element == EL_SIEB2_LEER ||
1118            element == EL_SIEB_VOLL || element == EL_SIEB2_VOLL)
1119   {
1120     graphic += 3 + getGraphicAnimationPhase(4, 4, ANIM_REVERSE);
1121   }
1122   else if (IS_AMOEBOID(element))
1123   {
1124     graphic = (element == EL_AMOEBE_TOT ? GFX_AMOEBE_TOT : GFX_AMOEBE_LEBT);
1125     graphic += (x + 2 * y + 4) % 4;
1126   }
1127   else if (element == EL_MAUER_LEBT)
1128   {
1129     boolean links_massiv = FALSE, rechts_massiv = FALSE;
1130
1131     if (!IN_LEV_FIELD(ux-1, uy) || IS_MAUER(Feld[ux-1][uy]))
1132       links_massiv = TRUE;
1133     if (!IN_LEV_FIELD(ux+1, uy) || IS_MAUER(Feld[ux+1][uy]))
1134       rechts_massiv = TRUE;
1135
1136     if (links_massiv && rechts_massiv)
1137       graphic = GFX_MAUERWERK;
1138     else if (links_massiv)
1139       graphic = GFX_MAUER_R;
1140     else if (rechts_massiv)
1141       graphic = GFX_MAUER_L;
1142   }
1143
1144   if (dx || dy)
1145     DrawGraphicShifted(x, y, dx, dy, graphic, cut_mode, mask_mode);
1146   else if (mask_mode == USE_MASKING)
1147     DrawGraphicThruMask(x, y, graphic);
1148   else
1149     DrawGraphic(x, y, graphic);
1150 }
1151
1152 void DrawLevelElementExt(int x, int y, int dx, int dy, int element,
1153                          int cut_mode, int mask_mode)
1154 {
1155   if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1156     DrawScreenElementExt(SCREENX(x), SCREENY(y), dx, dy, element,
1157                          cut_mode, mask_mode);
1158 }
1159
1160 void DrawScreenElementShifted(int x, int y, int dx, int dy, int element,
1161                               int cut_mode)
1162 {
1163   DrawScreenElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1164 }
1165
1166 void DrawLevelElementShifted(int x, int y, int dx, int dy, int element,
1167                              int cut_mode)
1168 {
1169   DrawLevelElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1170 }
1171
1172 void DrawScreenElementThruMask(int x, int y, int element)
1173 {
1174   DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1175 }
1176
1177 void DrawLevelElementThruMask(int x, int y, int element)
1178 {
1179   DrawLevelElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1180 }
1181
1182 void DrawLevelFieldThruMask(int x, int y)
1183 {
1184   DrawLevelElementExt(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
1185 }
1186
1187 void ErdreichAnbroeckeln(int x, int y)
1188 {
1189   int i, width, height, cx,cy;
1190   int ux = LEVELX(x), uy = LEVELY(y);
1191   int element, graphic;
1192   int snip = 4;
1193   static int xy[4][2] =
1194   {
1195     { 0, -1 },
1196     { -1, 0 },
1197     { +1, 0 },
1198     { 0, +1 }
1199   };
1200
1201   if (!IN_LEV_FIELD(ux, uy))
1202     return;
1203
1204   element = Feld[ux][uy];
1205
1206   if (element == EL_ERDREICH)
1207   {
1208     if (!IN_SCR_FIELD(x, y))
1209       return;
1210
1211     graphic = GFX_ERDENRAND;
1212
1213     for(i=0; i<4; i++)
1214     {
1215       int uxx, uyy;
1216
1217       uxx = ux + xy[i][0];
1218       uyy = uy + xy[i][1];
1219       if (!IN_LEV_FIELD(uxx, uyy))
1220         element = EL_BETON;
1221       else
1222         element = Feld[uxx][uyy];
1223
1224       if (element == EL_ERDREICH)
1225         continue;
1226
1227       if (i == 1 || i == 2)
1228       {
1229         width = snip;
1230         height = TILEY;
1231         cx = (i == 2 ? TILEX - snip : 0);
1232         cy = 0;
1233       }
1234       else
1235       {
1236         width = TILEX;
1237         height = snip;
1238         cx = 0;
1239         cy = (i == 3 ? TILEY - snip : 0);
1240       }
1241
1242       XCopyArea(display, pix[PIX_BACK], drawto_field, gc,
1243                 SX + (graphic % GFX_PER_LINE) * TILEX + cx,
1244                 SY + (graphic / GFX_PER_LINE) * TILEY + cy,
1245                 width, height, FX + x * TILEX + cx, FY + y * TILEY + cy);
1246     }
1247
1248     MarkTileDirty(x, y);
1249   }
1250   else
1251   {
1252     graphic = GFX_ERDENRAND;
1253
1254     for(i=0; i<4; i++)
1255     {
1256       int xx, yy, uxx, uyy;
1257
1258       xx = x + xy[i][0];
1259       yy = y + xy[i][1];
1260       uxx = ux + xy[i][0];
1261       uyy = uy + xy[i][1];
1262
1263       if (!IN_LEV_FIELD(uxx, uyy) || Feld[uxx][uyy] != EL_ERDREICH ||
1264           !IN_SCR_FIELD(xx, yy))
1265         continue;
1266
1267       if (i == 1 || i == 2)
1268       {
1269         width = snip;
1270         height = TILEY;
1271         cx = (i == 1 ? TILEX - snip : 0);
1272         cy = 0;
1273       }
1274       else
1275       {
1276         width = TILEX;
1277         height = snip;
1278         cx = 0;
1279         cy = (i==0 ? TILEY-snip : 0);
1280       }
1281
1282       XCopyArea(display, pix[PIX_BACK], drawto_field, gc,
1283                 SX + (graphic % GFX_PER_LINE) * TILEX + cx,
1284                 SY + (graphic / GFX_PER_LINE) * TILEY + cy,
1285                 width, height, FX + xx * TILEX + cx, FY + yy * TILEY + cy);
1286
1287       MarkTileDirty(xx, yy);
1288     }
1289   }
1290 }
1291
1292 void DrawScreenElement(int x, int y, int element)
1293 {
1294   DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
1295   ErdreichAnbroeckeln(x, y);
1296 }
1297
1298 void DrawLevelElement(int x, int y, int element)
1299 {
1300   if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1301     DrawScreenElement(SCREENX(x), SCREENY(y), element);
1302 }
1303
1304 void DrawScreenField(int x, int y)
1305 {
1306   int ux = LEVELX(x), uy = LEVELY(y);
1307   int element;
1308
1309   if (!IN_LEV_FIELD(ux, uy))
1310   {
1311     if (ux < -1 || ux > lev_fieldx || uy < -1 || uy > lev_fieldy)
1312       element = EL_LEERRAUM;
1313     else
1314       element = BorderElement;
1315
1316     DrawScreenElement(x, y, element);
1317     return;
1318   }
1319
1320   element = Feld[ux][uy];
1321
1322   if (IS_MOVING(ux, uy))
1323   {
1324     int horiz_move = (MovDir[ux][uy] == MV_LEFT || MovDir[ux][uy] == MV_RIGHT);
1325     boolean cut_mode = NO_CUTTING;
1326
1327     if (Store[ux][uy] == EL_MORAST_LEER ||
1328         Store[ux][uy] == EL_SIEB_LEER ||
1329         Store[ux][uy] == EL_SIEB2_LEER ||
1330         Store[ux][uy] == EL_AMOEBE_NASS)
1331       cut_mode = CUT_ABOVE;
1332     else if (Store[ux][uy] == EL_MORAST_VOLL ||
1333              Store[ux][uy] == EL_SIEB_VOLL ||
1334              Store[ux][uy] == EL_SIEB2_VOLL)
1335       cut_mode = CUT_BELOW;
1336
1337     if (cut_mode == CUT_ABOVE)
1338       DrawScreenElementShifted(x, y, 0, 0, Store[ux][uy], NO_CUTTING);
1339     else
1340       DrawScreenElement(x, y, EL_LEERRAUM);
1341
1342     if (horiz_move)
1343       DrawScreenElementShifted(x, y, MovPos[ux][uy], 0, element, NO_CUTTING);
1344     else
1345       DrawScreenElementShifted(x, y, 0, MovPos[ux][uy], element, cut_mode);
1346
1347     if (Store[ux][uy] == EL_SALZSAEURE)
1348       DrawLevelElementThruMask(ux, uy + 1, EL_SALZSAEURE);
1349   }
1350   else if (IS_BLOCKED(ux, uy))
1351   {
1352     int oldx, oldy;
1353     int sx, sy;
1354     int horiz_move;
1355     boolean cut_mode = NO_CUTTING;
1356
1357     Blocked2Moving(ux, uy, &oldx, &oldy);
1358     sx = SCREENX(oldx);
1359     sy = SCREENY(oldy);
1360     horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
1361                   MovDir[oldx][oldy] == MV_RIGHT);
1362
1363     if (Store[oldx][oldy] == EL_MORAST_LEER ||
1364         Store[oldx][oldy] == EL_SIEB_LEER ||
1365         Store[oldx][oldy] == EL_SIEB2_LEER ||
1366         Store[oldx][oldy] == EL_AMOEBE_NASS)
1367       cut_mode = CUT_ABOVE;
1368
1369     DrawScreenElement(x, y, EL_LEERRAUM);
1370     element = Feld[oldx][oldy];
1371
1372     if (horiz_move)
1373       DrawScreenElementShifted(sx,sy, MovPos[oldx][oldy],0,element,NO_CUTTING);
1374     else
1375       DrawScreenElementShifted(sx,sy, 0,MovPos[oldx][oldy],element,cut_mode);
1376   }
1377   else if (IS_DRAWABLE(element))
1378     DrawScreenElement(x, y, element);
1379   else
1380     DrawScreenElement(x, y, EL_LEERRAUM);
1381 }
1382
1383 void DrawLevelField(int x, int y)
1384 {
1385   if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1386     DrawScreenField(SCREENX(x), SCREENY(y));
1387   else if (IS_MOVING(x, y))
1388   {
1389     int newx,newy;
1390
1391     Moving2Blocked(x, y, &newx, &newy);
1392     if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
1393       DrawScreenField(SCREENX(newx), SCREENY(newy));
1394   }
1395   else if (IS_BLOCKED(x, y))
1396   {
1397     int oldx, oldy;
1398
1399     Blocked2Moving(x, y, &oldx, &oldy);
1400     if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
1401       DrawScreenField(SCREENX(oldx), SCREENY(oldy));
1402   }
1403 }
1404
1405 void DrawMiniElement(int x, int y, int element)
1406 {
1407   int graphic;
1408
1409   if (!element)
1410   {
1411     DrawMiniGraphic(x, y, -1);
1412     return;
1413   }
1414
1415   graphic = el2gfx(element);
1416   DrawMiniGraphic(x, y, graphic);
1417 }
1418
1419 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
1420 {
1421   int x = sx + scroll_x, y = sy + scroll_y;
1422
1423   if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
1424     DrawMiniElement(sx, sy, EL_LEERRAUM);
1425   else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
1426     DrawMiniElement(sx, sy, Feld[x][y]);
1427   else
1428   {
1429     int steel_type, steel_position;
1430     int border[6][2] =
1431     {
1432       { GFX_VSTEEL_UPPER_LEFT,  GFX_ISTEEL_UPPER_LEFT  },
1433       { GFX_VSTEEL_UPPER_RIGHT, GFX_ISTEEL_UPPER_RIGHT },
1434       { GFX_VSTEEL_LOWER_LEFT,  GFX_ISTEEL_LOWER_LEFT  },
1435       { GFX_VSTEEL_LOWER_RIGHT, GFX_ISTEEL_LOWER_RIGHT },
1436       { GFX_VSTEEL_VERTICAL,    GFX_ISTEEL_VERTICAL    },
1437       { GFX_VSTEEL_HORIZONTAL,  GFX_ISTEEL_HORIZONTAL  }
1438     };
1439
1440     steel_type = (BorderElement == EL_BETON ? 0 : 1);
1441     steel_position = (x == -1 && y == -1                        ? 0 :
1442                       x == lev_fieldx && y == -1                ? 1 :
1443                       x == -1 && y == lev_fieldy                ? 2 :
1444                       x == lev_fieldx && y == lev_fieldy        ? 3 :
1445                       x == -1 || x == lev_fieldx                ? 4 :
1446                       y == -1 || y == lev_fieldy                ? 5 : -1);
1447
1448     if (steel_position != -1)
1449       DrawMiniGraphic(sx, sy, border[steel_position][steel_type]);
1450   }
1451 }
1452
1453 void DrawMicroElement(int xpos, int ypos, int element)
1454 {
1455   int graphic;
1456
1457   if (element == EL_LEERRAUM)
1458     return;
1459
1460   graphic = el2gfx(element);
1461
1462   if (graphic >= GFX_START_ROCKSMORE && graphic <= GFX_END_ROCKSMORE)
1463   {
1464     graphic -= GFX_START_ROCKSMORE;
1465     graphic -= ((graphic / MORE_PER_LINE) * MORE_PER_LINE) / 2;
1466     XCopyArea(display, pix[PIX_MORE], drawto, gc,
1467               MICRO_MORE_STARTX + (graphic % MICRO_MORE_PER_LINE) *MICRO_TILEX,
1468               MICRO_MORE_STARTY + (graphic / MICRO_MORE_PER_LINE) *MICRO_TILEY,
1469               MICRO_TILEX, MICRO_TILEY, xpos, ypos);
1470   }
1471   else
1472     XCopyArea(display, pix[PIX_BACK], drawto, gc,
1473               MICRO_GFX_STARTX + (graphic % MICRO_GFX_PER_LINE) * MICRO_TILEX,
1474               MICRO_GFX_STARTY + (graphic / MICRO_GFX_PER_LINE) * MICRO_TILEY,
1475               MICRO_TILEX, MICRO_TILEY, xpos, ypos);
1476 }
1477
1478 void DrawLevel()
1479 {
1480   int x,y;
1481
1482   ClearWindow();
1483
1484   for(x=BX1; x<=BX2; x++)
1485     for(y=BY1; y<=BY2; y++)
1486       DrawScreenField(x, y);
1487
1488   redraw_mask |= REDRAW_FIELD;
1489 }
1490
1491 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
1492 {
1493   int x,y;
1494
1495   for(x=0; x<size_x; x++)
1496     for(y=0; y<size_y; y++)
1497       DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
1498
1499   redraw_mask |= REDRAW_FIELD;
1500 }
1501
1502 static void DrawMicroLevelExt(int xpos, int ypos, int from_x, int from_y)
1503 {
1504   int x, y;
1505
1506   XFillRectangle(display, drawto, gc,
1507                  xpos, ypos, MICROLEV_XSIZE, MICROLEV_YSIZE);
1508
1509   if (lev_fieldx < STD_LEV_FIELDX)
1510     xpos += (STD_LEV_FIELDX - lev_fieldx) / 2 * MICRO_TILEX;
1511   if (lev_fieldy < STD_LEV_FIELDY)
1512     ypos += (STD_LEV_FIELDY - lev_fieldy) / 2 * MICRO_TILEY;
1513
1514   xpos += MICRO_TILEX;
1515   ypos += MICRO_TILEY;
1516
1517   for(x=-1; x<=STD_LEV_FIELDX; x++)
1518   {
1519     for(y=-1; y<=STD_LEV_FIELDY; y++)
1520     {
1521       int lx = from_x + x, ly = from_y + y;
1522
1523       if (lx >= 0 && lx < lev_fieldx && ly >= 0 && ly < lev_fieldy)
1524         DrawMicroElement(xpos + x * MICRO_TILEX, ypos + y * MICRO_TILEY,
1525                          Ur[lx][ly]);
1526       else if (lx >= -1 && lx < lev_fieldx+1 && ly >= -1 && ly < lev_fieldy+1)
1527         DrawMicroElement(xpos + x * MICRO_TILEX, ypos + y * MICRO_TILEY,
1528                          BorderElement);
1529     }
1530   }
1531
1532   redraw_mask |= REDRAW_MICROLEVEL;
1533 }
1534
1535 static void DrawMicroLevelLabelExt(int mode)
1536 {
1537   char label_text[100];
1538
1539   XFillRectangle(display, drawto,gc,
1540                  SX, MICROLABEL_YPOS, SXSIZE, FONT4_YSIZE);
1541
1542   strcpy(label_text, (mode == 1 ? level.name :
1543                       mode == 2 ? "created by" :
1544                       mode == 3 ? level.author : ""));
1545
1546   if (strlen(label_text) > 0)
1547   {
1548     int size, lxpos, lypos;
1549
1550     label_text[SXSIZE / FONT4_XSIZE] = '\0';
1551
1552     size = strlen(label_text);
1553     lxpos = SX + (SXSIZE - size * FONT4_XSIZE) / 2;
1554     lypos = MICROLABEL_YPOS;
1555
1556     DrawText(lxpos, lypos, label_text, FS_SMALL, FC_SPECIAL2);
1557   }
1558
1559   redraw_mask |= REDRAW_MICROLEVEL;
1560 }
1561
1562 void DrawMicroLevel(int xpos, int ypos, boolean restart)
1563 {
1564   static unsigned long scroll_delay = 0;
1565   static unsigned long label_delay = 0;
1566   static int from_x, from_y, scroll_direction;
1567   static int label_state, label_counter;
1568
1569   if (restart)
1570   {
1571     from_x = from_y = 0;
1572     scroll_direction = MV_RIGHT;
1573     label_state = 1;
1574     label_counter = 0;
1575
1576     DrawMicroLevelExt(xpos, ypos, from_x, from_y);
1577     DrawMicroLevelLabelExt(label_state);
1578
1579     /* initialize delay counters */
1580     DelayReached(&scroll_delay, 0);
1581     DelayReached(&label_delay, 0);
1582
1583     return;
1584   }
1585
1586   /* scroll micro level, if needed */
1587   if ((lev_fieldx > STD_LEV_FIELDX || lev_fieldy > STD_LEV_FIELDY) &&
1588       DelayReached(&scroll_delay, MICROLEVEL_SCROLL_DELAY))
1589   {
1590     switch (scroll_direction)
1591     {
1592       case MV_LEFT:
1593         if (from_x > 0)
1594           from_x--;
1595         else
1596           scroll_direction = MV_UP;
1597         break;
1598
1599       case MV_RIGHT:
1600         if (from_x < lev_fieldx - STD_LEV_FIELDX)
1601           from_x++;
1602         else
1603           scroll_direction = MV_DOWN;
1604         break;
1605
1606       case MV_UP:
1607         if (from_y > 0)
1608           from_y--;
1609         else
1610           scroll_direction = MV_RIGHT;
1611         break;
1612
1613       case MV_DOWN:
1614         if (from_y < lev_fieldy - STD_LEV_FIELDY)
1615           from_y++;
1616         else
1617           scroll_direction = MV_LEFT;
1618         break;
1619
1620       default:
1621         break;
1622     }
1623
1624     DrawMicroLevelExt(xpos, ypos, from_x, from_y);
1625   }
1626
1627   /* redraw micro level label, if needed */
1628   if (strcmp(level.name, NAMELESS_LEVEL_NAME) != 0 &&
1629       strcmp(level.author, ANONYMOUS_NAME) != 0 &&
1630       strcmp(level.author, leveldir[leveldir_nr].name) != 0 &&
1631       DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
1632   {
1633     label_counter = (label_counter + 1) % 23;
1634     label_state = (label_counter >= 0 && label_counter <= 7 ? 1 :
1635                    label_counter >= 9 && label_counter <= 12 ? 2 :
1636                    label_counter >= 14 && label_counter <= 21 ? 3 : 0);
1637     DrawMicroLevelLabelExt(label_state);
1638   }
1639 }
1640
1641 int REQ_in_range(int x, int y)
1642 {
1643   if (y > DY+249 && y < DY+278)
1644   {
1645     if (x > DX+1 && x < DX+48)
1646       return 1;
1647     else if (x > DX+51 && x < DX+98) 
1648       return 2;
1649   }
1650   return 0;
1651 }
1652
1653 boolean Request(char *text, unsigned int req_state)
1654 {
1655   int mx, my, ty, result = -1;
1656   unsigned int old_door_state;
1657
1658 #ifndef MSDOS
1659   /* pause network game while waiting for request to answer */
1660   if (options.network &&
1661       game_status == PLAYING &&
1662       req_state & REQUEST_WAIT_FOR)
1663     SendToServer_PausePlaying();
1664 #endif
1665
1666   old_door_state = GetDoorState();
1667
1668   UnmapAllGadgets();
1669
1670   CloseDoor(DOOR_CLOSE_1);
1671
1672   /* save old door content */
1673   XCopyArea(display, pix[PIX_DB_DOOR], pix[PIX_DB_DOOR], gc,
1674             DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
1675             DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
1676
1677   /* clear door drawing field */
1678   XFillRectangle(display, drawto, gc, DX, DY, DXSIZE, DYSIZE);
1679
1680   /* write text for request */
1681   for(ty=0; ty<13; ty++)
1682   {
1683     int tx, tl, tc;
1684     char txt[256];
1685
1686     if (!*text)
1687       break;
1688
1689     for(tl=0,tx=0; tx<7; tl++,tx++)
1690     {
1691       tc = *(text + tx);
1692       if (!tc || tc == 32)
1693         break;
1694     }
1695     if (!tl)
1696     { 
1697       text++; 
1698       ty--; 
1699       continue; 
1700     }
1701     sprintf(txt, text); 
1702     txt[tl] = 0;
1703     DrawTextExt(drawto, gc,
1704                 DX + 51 - (tl * 14)/2, DY + 8 + ty * 16,
1705                 txt, FS_SMALL, FC_YELLOW);
1706     text += tl + (tc == 32 ? 1 : 0);
1707   }
1708
1709   if (req_state & REQ_ASK)
1710   {
1711     MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
1712     MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
1713   }
1714   else if (req_state & REQ_CONFIRM)
1715   {
1716     MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
1717   }
1718   else if (req_state & REQ_PLAYER)
1719   {
1720     MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
1721     MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
1722     MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
1723     MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
1724   }
1725
1726   /* copy request gadgets to door backbuffer */
1727   XCopyArea(display, drawto, pix[PIX_DB_DOOR], gc,
1728             DX, DY, DXSIZE, DYSIZE,
1729             DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
1730
1731   OpenDoor(DOOR_OPEN_1);
1732
1733 #if 0
1734   ClearEventQueue();
1735 #endif
1736
1737   if (!(req_state & REQUEST_WAIT_FOR))
1738     return(FALSE);
1739
1740   if (game_status != MAINMENU)
1741     InitAnimation();
1742
1743   button_status = MB_RELEASED;
1744
1745   request_gadget_id = -1;
1746
1747   while(result < 0)
1748   {
1749     if (XPending(display))
1750     {
1751       XEvent event;
1752
1753       XNextEvent(display, &event);
1754
1755       switch(event.type)
1756       {
1757         case ButtonPress:
1758         case ButtonRelease:
1759         case MotionNotify:
1760         {
1761           if (event.type == MotionNotify)
1762           {
1763             Window root, child;
1764             int root_x, root_y;
1765             int win_x, win_y;
1766             unsigned int mask;
1767
1768             if (!XQueryPointer(display, window, &root, &child,
1769                                &root_x, &root_y, &win_x, &win_y, &mask))
1770               continue;
1771
1772             if (!button_status)
1773               continue;
1774
1775             motion_status = TRUE;
1776             mx = ((XMotionEvent *) &event)->x;
1777             my = ((XMotionEvent *) &event)->y;
1778           }
1779           else
1780           {
1781             motion_status = FALSE;
1782             mx = ((XButtonEvent *) &event)->x;
1783             my = ((XButtonEvent *) &event)->y;
1784             if (event.type==ButtonPress)
1785               button_status = ((XButtonEvent *) &event)->button;
1786             else
1787               button_status = MB_RELEASED;
1788           }
1789
1790           /* this sets 'request_gadget_id' */
1791           HandleGadgets(mx, my, button_status);
1792
1793           switch(request_gadget_id)
1794           {
1795             case TOOL_CTRL_ID_YES:
1796               result = TRUE;
1797               break;
1798             case TOOL_CTRL_ID_NO:
1799               result = FALSE;
1800               break;
1801             case TOOL_CTRL_ID_CONFIRM:
1802               result = TRUE | FALSE;
1803               break;
1804
1805             case TOOL_CTRL_ID_PLAYER_1:
1806               result = 1;
1807               break;
1808             case TOOL_CTRL_ID_PLAYER_2:
1809               result = 2;
1810               break;
1811             case TOOL_CTRL_ID_PLAYER_3:
1812               result = 3;
1813               break;
1814             case TOOL_CTRL_ID_PLAYER_4:
1815               result = 4;
1816               break;
1817
1818             default:
1819               break;
1820           }
1821
1822           break;
1823         }
1824
1825         case KeyPress:
1826           switch(XLookupKeysym((XKeyEvent *)&event,
1827                                ((XKeyEvent *)&event)->state))
1828           {
1829             case XK_Return:
1830               result = 1;
1831               break;
1832
1833             case XK_Escape:
1834               result = 0;
1835               break;
1836
1837             default:
1838               break;
1839           }
1840           if (req_state & REQ_PLAYER)
1841             result = 0;
1842           break;
1843
1844         case KeyRelease:
1845           key_joystick_mapping = 0;
1846           break;
1847
1848         default:
1849           HandleOtherEvents(&event);
1850           break;
1851       }
1852     }
1853     else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
1854     {
1855       int joy = AnyJoystick();
1856
1857       if (joy & JOY_BUTTON_1)
1858         result = 1;
1859       else if (joy & JOY_BUTTON_2)
1860         result = 0;
1861     }
1862
1863     DoAnimation();
1864
1865     /* don't eat all CPU time */
1866     Delay(10);
1867   }
1868
1869   if (game_status != MAINMENU)
1870     StopAnimation();
1871
1872   UnmapToolButtons();
1873
1874   if (!(req_state & REQ_STAY_OPEN))
1875   {
1876     CloseDoor(DOOR_CLOSE_1);
1877
1878     if (!(req_state & REQ_STAY_CLOSED) && (old_door_state & DOOR_OPEN_1))
1879     {
1880       XCopyArea(display,pix[PIX_DB_DOOR],pix[PIX_DB_DOOR],gc,
1881                 DOOR_GFX_PAGEX2,DOOR_GFX_PAGEY1, DXSIZE,DYSIZE,
1882                 DOOR_GFX_PAGEX1,DOOR_GFX_PAGEY1);
1883       OpenDoor(DOOR_OPEN_1);
1884     }
1885   }
1886
1887   RemapAllGadgets();
1888
1889 #ifndef MSDOS
1890   /* continue network game after request */
1891   if (options.network &&
1892       game_status == PLAYING &&
1893       req_state & REQUEST_WAIT_FOR)
1894     SendToServer_ContinuePlaying();
1895 #endif
1896
1897   return(result);
1898 }
1899
1900 unsigned int OpenDoor(unsigned int door_state)
1901 {
1902   unsigned int new_door_state;
1903
1904   if (door_state & DOOR_COPY_BACK)
1905   {
1906     XCopyArea(display, pix[PIX_DB_DOOR], pix[PIX_DB_DOOR], gc,
1907               DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE + VYSIZE,
1908               DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
1909     door_state &= ~DOOR_COPY_BACK;
1910   }
1911
1912   new_door_state = MoveDoor(door_state);
1913
1914   return(new_door_state);
1915 }
1916
1917 unsigned int CloseDoor(unsigned int door_state)
1918 {
1919   unsigned int new_door_state;
1920
1921   XCopyArea(display, backbuffer, pix[PIX_DB_DOOR], gc,
1922             DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
1923   XCopyArea(display, backbuffer, pix[PIX_DB_DOOR], gc,
1924             VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
1925
1926   new_door_state = MoveDoor(door_state);
1927
1928   return(new_door_state);
1929 }
1930
1931 unsigned int GetDoorState()
1932 {
1933   return(MoveDoor(DOOR_GET_STATE));
1934 }
1935
1936 unsigned int MoveDoor(unsigned int door_state)
1937 {
1938   static int door1 = DOOR_OPEN_1;
1939   static int door2 = DOOR_CLOSE_2;
1940   static unsigned long door_delay = 0;
1941   int x, start, stepsize = 2;
1942   unsigned long door_delay_value = stepsize * 5;
1943
1944   if (door_state == DOOR_GET_STATE)
1945     return(door1 | door2);
1946
1947   if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
1948     door_state &= ~DOOR_OPEN_1;
1949   else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
1950     door_state &= ~DOOR_CLOSE_1;
1951   if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
1952     door_state &= ~DOOR_OPEN_2;
1953   else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
1954     door_state &= ~DOOR_CLOSE_2;
1955
1956   if (setup.quick_doors)
1957   {
1958     stepsize = 20;
1959     door_delay_value = 0;
1960     StopSound(SND_OEFFNEN);
1961   }
1962
1963   if (door_state & DOOR_ACTION)
1964   {
1965     if (!(door_state & DOOR_NO_DELAY))
1966       PlaySoundStereo(SND_OEFFNEN, PSND_MAX_RIGHT);
1967
1968     start = ((door_state & DOOR_NO_DELAY) ? DXSIZE : 0);
1969
1970     for(x=start; x<=DXSIZE; x+=stepsize)
1971     {
1972       WaitUntilDelayReached(&door_delay, door_delay_value);
1973
1974       if (door_state & DOOR_ACTION_1)
1975       {
1976         int i = (door_state & DOOR_OPEN_1 ? DXSIZE-x : x);
1977         int j = (DXSIZE - i) / 3;
1978
1979         XCopyArea(display, pix[PIX_DB_DOOR], drawto, gc,
1980                   DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + i/2,
1981                   DXSIZE,DYSIZE - i/2, DX, DY);
1982
1983         XFillRectangle(display, drawto, gc, DX, DY + DYSIZE - i/2, DXSIZE,i/2);
1984
1985         XSetClipOrigin(display, clip_gc[PIX_DOOR],
1986                        DX - i, (DY + j) - DOOR_GFX_PAGEY1);
1987         XCopyArea(display, pix[PIX_DOOR], drawto,clip_gc[PIX_DOOR],
1988                   DXSIZE, DOOR_GFX_PAGEY1, i, 77, DX + DXSIZE - i, DY + j);
1989         XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
1990                   DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63, DX + DXSIZE - i,
1991                   DY + 140 + j);
1992         XSetClipOrigin(display, clip_gc[PIX_DOOR],
1993                        DX - DXSIZE + i, DY - (DOOR_GFX_PAGEY1 + j));
1994         XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
1995                   DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j, DX, DY);
1996         XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
1997                   DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63, DX, DY + 140 - j);
1998
1999         XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
2000                   DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
2001                   DX, DY + 77 - j);
2002         XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
2003                   DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
2004                   DX, DY + 203 - j);
2005         XSetClipOrigin(display, clip_gc[PIX_DOOR],
2006                        DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2007         XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
2008                   DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
2009                   DX + DXSIZE - i, DY + 77 + j);
2010         XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
2011                   DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
2012                   DX + DXSIZE - i, DY + 203 + j);
2013
2014         redraw_mask |= REDRAW_DOOR_1;
2015       }
2016
2017       if (door_state & DOOR_ACTION_2)
2018       {
2019         int i = (door_state & DOOR_OPEN_2 ? VXSIZE - x : x);
2020         int j = (VXSIZE - i) / 3;
2021
2022         XCopyArea(display, pix[PIX_DB_DOOR], drawto, gc,
2023                   DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + i/2,
2024                   VXSIZE, VYSIZE - i/2, VX, VY);
2025
2026         XFillRectangle(display, drawto, gc, VX, VY + VYSIZE-i/2, VXSIZE, i/2);
2027
2028         XSetClipOrigin(display, clip_gc[PIX_DOOR],
2029                        VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2030         XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
2031                   VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2, VX + VXSIZE-i, VY+j);
2032         XSetClipOrigin(display, clip_gc[PIX_DOOR],
2033                        VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
2034         XCopyArea(display, pix[PIX_DOOR], drawto,clip_gc[PIX_DOOR],
2035                   VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j, VX, VY);
2036
2037         XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
2038                   VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2, i, VYSIZE / 2,
2039                   VX, VY + VYSIZE / 2 - j);
2040         XSetClipOrigin(display, clip_gc[PIX_DOOR],
2041                        VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2042         XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
2043                   VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2, i, VYSIZE / 2 - j,
2044                   VX + VXSIZE - i, VY + VYSIZE / 2 + j);
2045
2046         redraw_mask |= REDRAW_DOOR_2;
2047       }
2048
2049       BackToFront();
2050
2051       if (game_status == MAINMENU)
2052         DoAnimation();
2053     }
2054   }
2055
2056   if (setup.quick_doors)
2057     StopSound(SND_OEFFNEN);
2058
2059   if (door_state & DOOR_ACTION_1)
2060     door1 = door_state & DOOR_ACTION_1;
2061   if (door_state & DOOR_ACTION_2)
2062     door2 = door_state & DOOR_ACTION_2;
2063
2064   return (door1 | door2);
2065 }
2066
2067 void DrawSpecialEditorDoor()
2068 {
2069   /* draw bigger toolbox window */
2070   XCopyArea(display, pix[PIX_DOOR], drawto, gc,
2071             DOOR_GFX_PAGEX7, 0, 108, 56, EX - 4, EY - 12);
2072
2073   redraw_mask |= REDRAW_ALL;
2074 }
2075
2076 void UndrawSpecialEditorDoor()
2077 {
2078   /* draw normal tape recorder window */
2079   XCopyArea(display, pix[PIX_BACK], drawto, gc,
2080             562, 344, 108, 56, EX - 4, EY - 12);
2081
2082   redraw_mask |= REDRAW_ALL;
2083 }
2084
2085 int ReadPixel(Drawable d, int x, int y)
2086 {
2087   XImage *pixel_image;
2088   unsigned long pixel_value;
2089
2090   pixel_image = XGetImage(display, d, x, y, 1, 1, AllPlanes, ZPixmap);
2091   pixel_value = XGetPixel(pixel_image, 0, 0);
2092
2093   XDestroyImage(pixel_image);
2094
2095   return pixel_value;
2096 }
2097
2098 /* ---------- new tool button stuff ---------------------------------------- */
2099
2100 /* graphic position values for tool buttons */
2101 #define TOOL_BUTTON_YES_XPOS            2
2102 #define TOOL_BUTTON_YES_YPOS            250
2103 #define TOOL_BUTTON_YES_GFX_YPOS        0
2104 #define TOOL_BUTTON_YES_XSIZE           46
2105 #define TOOL_BUTTON_YES_YSIZE           28
2106 #define TOOL_BUTTON_NO_XPOS             52
2107 #define TOOL_BUTTON_NO_YPOS             TOOL_BUTTON_YES_YPOS
2108 #define TOOL_BUTTON_NO_GFX_YPOS         TOOL_BUTTON_YES_GFX_YPOS
2109 #define TOOL_BUTTON_NO_XSIZE            TOOL_BUTTON_YES_XSIZE
2110 #define TOOL_BUTTON_NO_YSIZE            TOOL_BUTTON_YES_YSIZE
2111 #define TOOL_BUTTON_CONFIRM_XPOS        TOOL_BUTTON_YES_XPOS
2112 #define TOOL_BUTTON_CONFIRM_YPOS        TOOL_BUTTON_YES_YPOS
2113 #define TOOL_BUTTON_CONFIRM_GFX_YPOS    30
2114 #define TOOL_BUTTON_CONFIRM_XSIZE       96
2115 #define TOOL_BUTTON_CONFIRM_YSIZE       TOOL_BUTTON_YES_YSIZE
2116 #define TOOL_BUTTON_PLAYER_XSIZE        30
2117 #define TOOL_BUTTON_PLAYER_YSIZE        30
2118 #define TOOL_BUTTON_PLAYER_GFX_XPOS     5
2119 #define TOOL_BUTTON_PLAYER_GFX_YPOS     185
2120 #define TOOL_BUTTON_PLAYER_XPOS         (5 + TOOL_BUTTON_PLAYER_XSIZE / 2)
2121 #define TOOL_BUTTON_PLAYER_YPOS         (215 - TOOL_BUTTON_PLAYER_YSIZE / 2)
2122 #define TOOL_BUTTON_PLAYER1_XPOS        (TOOL_BUTTON_PLAYER_XPOS \
2123                                          + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2124 #define TOOL_BUTTON_PLAYER2_XPOS        (TOOL_BUTTON_PLAYER_XPOS \
2125                                          + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2126 #define TOOL_BUTTON_PLAYER3_XPOS        (TOOL_BUTTON_PLAYER_XPOS \
2127                                          + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2128 #define TOOL_BUTTON_PLAYER4_XPOS        (TOOL_BUTTON_PLAYER_XPOS \
2129                                          + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2130 #define TOOL_BUTTON_PLAYER1_YPOS        (TOOL_BUTTON_PLAYER_YPOS \
2131                                          + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2132 #define TOOL_BUTTON_PLAYER2_YPOS        (TOOL_BUTTON_PLAYER_YPOS \
2133                                          + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2134 #define TOOL_BUTTON_PLAYER3_YPOS        (TOOL_BUTTON_PLAYER_YPOS \
2135                                          + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2136 #define TOOL_BUTTON_PLAYER4_YPOS        (TOOL_BUTTON_PLAYER_YPOS \
2137                                          + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2138
2139 static struct
2140 {
2141   int xpos, ypos;
2142   int x, y;
2143   int width, height;
2144   int gadget_id;
2145   char *infotext;
2146 } toolbutton_info[NUM_TOOL_BUTTONS] =
2147 {
2148   {
2149     TOOL_BUTTON_YES_XPOS,       TOOL_BUTTON_YES_GFX_YPOS,
2150     TOOL_BUTTON_YES_XPOS,       TOOL_BUTTON_YES_YPOS,
2151     TOOL_BUTTON_YES_XSIZE,      TOOL_BUTTON_YES_YSIZE,
2152     TOOL_CTRL_ID_YES,
2153     "yes"
2154   },
2155   {
2156     TOOL_BUTTON_NO_XPOS,        TOOL_BUTTON_NO_GFX_YPOS,
2157     TOOL_BUTTON_NO_XPOS,        TOOL_BUTTON_NO_YPOS,
2158     TOOL_BUTTON_NO_XSIZE,       TOOL_BUTTON_NO_YSIZE,
2159     TOOL_CTRL_ID_NO,
2160     "no"
2161   },
2162   {
2163     TOOL_BUTTON_CONFIRM_XPOS,   TOOL_BUTTON_CONFIRM_GFX_YPOS,
2164     TOOL_BUTTON_CONFIRM_XPOS,   TOOL_BUTTON_CONFIRM_YPOS,
2165     TOOL_BUTTON_CONFIRM_XSIZE,  TOOL_BUTTON_CONFIRM_YSIZE,
2166     TOOL_CTRL_ID_CONFIRM,
2167     "confirm"
2168   },
2169   {
2170     TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2171     TOOL_BUTTON_PLAYER1_XPOS,   TOOL_BUTTON_PLAYER1_YPOS,
2172     TOOL_BUTTON_PLAYER_XSIZE,   TOOL_BUTTON_PLAYER_YSIZE,
2173     TOOL_CTRL_ID_PLAYER_1,
2174     "player 1"
2175   },
2176   {
2177     TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2178     TOOL_BUTTON_PLAYER2_XPOS,   TOOL_BUTTON_PLAYER2_YPOS,
2179     TOOL_BUTTON_PLAYER_XSIZE,   TOOL_BUTTON_PLAYER_YSIZE,
2180     TOOL_CTRL_ID_PLAYER_2,
2181     "player 2"
2182   },
2183   {
2184     TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2185     TOOL_BUTTON_PLAYER3_XPOS,   TOOL_BUTTON_PLAYER3_YPOS,
2186     TOOL_BUTTON_PLAYER_XSIZE,   TOOL_BUTTON_PLAYER_YSIZE,
2187     TOOL_CTRL_ID_PLAYER_3,
2188     "player 3"
2189   },
2190   {
2191     TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2192     TOOL_BUTTON_PLAYER4_XPOS,   TOOL_BUTTON_PLAYER4_YPOS,
2193     TOOL_BUTTON_PLAYER_XSIZE,   TOOL_BUTTON_PLAYER_YSIZE,
2194     TOOL_CTRL_ID_PLAYER_4,
2195     "player 4"
2196   }
2197 };
2198
2199 static void DoNotDisplayInfoText(void *ptr)
2200 {
2201   return;
2202 }
2203
2204 void CreateToolButtons()
2205 {
2206   int i;
2207
2208   for (i=0; i<NUM_TOOL_BUTTONS; i++)
2209   {
2210     Pixmap gd_pixmap = pix[PIX_DOOR];
2211     Pixmap deco_pixmap = None;
2212     int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
2213     struct GadgetInfo *gi;
2214     unsigned long event_mask;
2215     int gd_xoffset, gd_yoffset;
2216     int gd_x1, gd_x2, gd_y;
2217     int id = i;
2218
2219     event_mask = GD_EVENT_RELEASED;
2220
2221     gd_xoffset = toolbutton_info[i].xpos;
2222     gd_yoffset = toolbutton_info[i].ypos;
2223     gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
2224     gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
2225     gd_y = DOOR_GFX_PAGEY1 + gd_yoffset;
2226
2227     if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
2228     {
2229       getMiniGraphicSource(GFX_SPIELER1 + id - TOOL_CTRL_ID_PLAYER_1,
2230                            &deco_pixmap, &deco_x, &deco_y);
2231       deco_xpos = (toolbutton_info[i].width - MINI_TILEX) / 2;
2232       deco_ypos = (toolbutton_info[i].height - MINI_TILEY) / 2;
2233     }
2234
2235     gi = CreateGadget(GDI_CUSTOM_ID, id,
2236                       GDI_INFO_TEXT, toolbutton_info[i].infotext,
2237                       GDI_X, DX + toolbutton_info[i].x,
2238                       GDI_Y, DY + toolbutton_info[i].y,
2239                       GDI_WIDTH, toolbutton_info[i].width,
2240                       GDI_HEIGHT, toolbutton_info[i].height,
2241                       GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
2242                       GDI_STATE, GD_BUTTON_UNPRESSED,
2243                       GDI_DESIGN_UNPRESSED, gd_pixmap, gd_x1, gd_y,
2244                       GDI_DESIGN_PRESSED, gd_pixmap, gd_x2, gd_y,
2245                       GDI_DECORATION_DESIGN, deco_pixmap, deco_x, deco_y,
2246                       GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
2247                       GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
2248                       GDI_DECORATION_SHIFTING, 1, 1,
2249                       GDI_EVENT_MASK, event_mask,
2250                       GDI_CALLBACK_ACTION, HandleToolButtons,
2251                       GDI_CALLBACK_INFO, DoNotDisplayInfoText,
2252                       GDI_END);
2253
2254     if (gi == NULL)
2255       Error(ERR_EXIT, "cannot create gadget");
2256
2257     tool_gadget[id] = gi;
2258   }
2259 }
2260
2261 static void UnmapToolButtons()
2262 {
2263   int i;
2264
2265   for (i=0; i<NUM_TOOL_BUTTONS; i++)
2266     UnmapGadget(tool_gadget[i]);
2267 }
2268
2269 static void HandleToolButtons(struct GadgetInfo *gi)
2270 {
2271   request_gadget_id = gi->custom_id;
2272 }
2273
2274 int el2gfx(int element)
2275 {
2276   switch(element)
2277   {
2278     case EL_LEERRAUM:           return -1;
2279     case EL_ERDREICH:           return GFX_ERDREICH;
2280     case EL_MAUERWERK:          return GFX_MAUERWERK;
2281     case EL_FELSBODEN:          return GFX_FELSBODEN;
2282     case EL_FELSBROCKEN:        return GFX_FELSBROCKEN;
2283     case EL_SCHLUESSEL:         return GFX_SCHLUESSEL;
2284     case EL_EDELSTEIN:          return GFX_EDELSTEIN;
2285     case EL_AUSGANG_ZU:         return GFX_AUSGANG_ZU;
2286     case EL_AUSGANG_ACT:        return GFX_AUSGANG_ACT;
2287     case EL_AUSGANG_AUF:        return GFX_AUSGANG_AUF;
2288     case EL_SPIELFIGUR:         return GFX_SPIELFIGUR;
2289     case EL_SPIELER1:           return GFX_SPIELER1;
2290     case EL_SPIELER2:           return GFX_SPIELER2;
2291     case EL_SPIELER3:           return GFX_SPIELER3;
2292     case EL_SPIELER4:           return GFX_SPIELER4;
2293     case EL_KAEFER:             return GFX_KAEFER;
2294     case EL_KAEFER_R:           return GFX_KAEFER_R;
2295     case EL_KAEFER_O:           return GFX_KAEFER_O;
2296     case EL_KAEFER_L:           return GFX_KAEFER_L;
2297     case EL_KAEFER_U:           return GFX_KAEFER_U;
2298     case EL_FLIEGER:            return GFX_FLIEGER;
2299     case EL_FLIEGER_R:          return GFX_FLIEGER_R;
2300     case EL_FLIEGER_O:          return GFX_FLIEGER_O;
2301     case EL_FLIEGER_L:          return GFX_FLIEGER_L;
2302     case EL_FLIEGER_U:          return GFX_FLIEGER_U;
2303     case EL_BUTTERFLY:          return GFX_BUTTERFLY;
2304     case EL_BUTTERFLY_R:        return GFX_BUTTERFLY_R;
2305     case EL_BUTTERFLY_O:        return GFX_BUTTERFLY_O;
2306     case EL_BUTTERFLY_L:        return GFX_BUTTERFLY_L;
2307     case EL_BUTTERFLY_U:        return GFX_BUTTERFLY_U;
2308     case EL_FIREFLY:            return GFX_FIREFLY;
2309     case EL_FIREFLY_R:          return GFX_FIREFLY_R;
2310     case EL_FIREFLY_O:          return GFX_FIREFLY_O;
2311     case EL_FIREFLY_L:          return GFX_FIREFLY_L;
2312     case EL_FIREFLY_U:          return GFX_FIREFLY_U;
2313     case EL_MAMPFER:            return GFX_MAMPFER;
2314     case EL_ROBOT:              return GFX_ROBOT;
2315     case EL_BETON:              return GFX_BETON;
2316     case EL_DIAMANT:            return GFX_DIAMANT;
2317     case EL_MORAST_LEER:        return GFX_MORAST_LEER;
2318     case EL_MORAST_VOLL:        return GFX_MORAST_VOLL;
2319     case EL_TROPFEN:            return GFX_TROPFEN;
2320     case EL_BOMBE:              return GFX_BOMBE;
2321     case EL_SIEB_INAKTIV:       return GFX_SIEB_INAKTIV;
2322     case EL_SIEB_LEER:          return GFX_SIEB_LEER;
2323     case EL_SIEB_VOLL:          return GFX_SIEB_VOLL;
2324     case EL_SIEB_TOT:           return GFX_SIEB_TOT;
2325     case EL_SALZSAEURE:         return GFX_SALZSAEURE;
2326     case EL_AMOEBE_TOT:         return GFX_AMOEBE_TOT;
2327     case EL_AMOEBE_NASS:        return GFX_AMOEBE_NASS;
2328     case EL_AMOEBE_NORM:        return GFX_AMOEBE_NORM;
2329     case EL_AMOEBE_VOLL:        return GFX_AMOEBE_VOLL;
2330     case EL_AMOEBE_BD:          return GFX_AMOEBE_BD;
2331     case EL_AMOEBA2DIAM:        return GFX_AMOEBA2DIAM;
2332     case EL_KOKOSNUSS:          return GFX_KOKOSNUSS;
2333     case EL_LIFE:               return GFX_LIFE;
2334     case EL_LIFE_ASYNC:         return GFX_LIFE_ASYNC;
2335     case EL_DYNAMITE_ACTIVE:    return GFX_DYNAMIT;
2336     case EL_BADEWANNE:          return GFX_BADEWANNE;
2337     case EL_BADEWANNE1:         return GFX_BADEWANNE1;
2338     case EL_BADEWANNE2:         return GFX_BADEWANNE2;
2339     case EL_BADEWANNE3:         return GFX_BADEWANNE3;
2340     case EL_BADEWANNE4:         return GFX_BADEWANNE4;
2341     case EL_BADEWANNE5:         return GFX_BADEWANNE5;
2342     case EL_ABLENK_AUS:         return GFX_ABLENK_AUS;
2343     case EL_ABLENK_EIN:         return GFX_ABLENK_EIN;
2344     case EL_SCHLUESSEL1:        return GFX_SCHLUESSEL1;
2345     case EL_SCHLUESSEL2:        return GFX_SCHLUESSEL2;
2346     case EL_SCHLUESSEL3:        return GFX_SCHLUESSEL3;
2347     case EL_SCHLUESSEL4:        return GFX_SCHLUESSEL4;
2348     case EL_PFORTE1:            return GFX_PFORTE1;
2349     case EL_PFORTE2:            return GFX_PFORTE2;
2350     case EL_PFORTE3:            return GFX_PFORTE3;
2351     case EL_PFORTE4:            return GFX_PFORTE4;
2352     case EL_PFORTE1X:           return GFX_PFORTE1X;
2353     case EL_PFORTE2X:           return GFX_PFORTE2X;
2354     case EL_PFORTE3X:           return GFX_PFORTE3X;
2355     case EL_PFORTE4X:           return GFX_PFORTE4X;
2356     case EL_DYNAMITE_INACTIVE:  return GFX_DYNAMIT_AUS;
2357     case EL_PACMAN:             return GFX_PACMAN;
2358     case EL_PACMAN_R:           return GFX_PACMAN_R;
2359     case EL_PACMAN_O:           return GFX_PACMAN_O;
2360     case EL_PACMAN_L:           return GFX_PACMAN_L;
2361     case EL_PACMAN_U:           return GFX_PACMAN_U;
2362     case EL_UNSICHTBAR:         return GFX_UNSICHTBAR;
2363     case EL_ERZ_EDEL:           return GFX_ERZ_EDEL;
2364     case EL_ERZ_DIAM:           return GFX_ERZ_DIAM;
2365     case EL_BIRNE_AUS:          return GFX_BIRNE_AUS;
2366     case EL_BIRNE_EIN:          return GFX_BIRNE_EIN;
2367     case EL_ZEIT_VOLL:          return GFX_ZEIT_VOLL;
2368     case EL_ZEIT_LEER:          return GFX_ZEIT_LEER;
2369     case EL_MAUER_LEBT:         return GFX_MAUER_LEBT;
2370     case EL_MAUER_X:            return GFX_MAUER_X;
2371     case EL_MAUER_Y:            return GFX_MAUER_Y;
2372     case EL_MAUER_XY:           return GFX_MAUER_XY;
2373     case EL_EDELSTEIN_BD:       return GFX_EDELSTEIN_BD;
2374     case EL_EDELSTEIN_GELB:     return GFX_EDELSTEIN_GELB;
2375     case EL_EDELSTEIN_ROT:      return GFX_EDELSTEIN_ROT;
2376     case EL_EDELSTEIN_LILA:     return GFX_EDELSTEIN_LILA;
2377     case EL_ERZ_EDEL_BD:        return GFX_ERZ_EDEL_BD;
2378     case EL_ERZ_EDEL_GELB:      return GFX_ERZ_EDEL_GELB;
2379     case EL_ERZ_EDEL_ROT:       return GFX_ERZ_EDEL_ROT;
2380     case EL_ERZ_EDEL_LILA:      return GFX_ERZ_EDEL_LILA;
2381     case EL_MAMPFER2:           return GFX_MAMPFER2;
2382     case EL_SIEB2_INAKTIV:      return GFX_SIEB2_INAKTIV;
2383     case EL_SIEB2_LEER:         return GFX_SIEB2_LEER;
2384     case EL_SIEB2_VOLL:         return GFX_SIEB2_VOLL;
2385     case EL_SIEB2_TOT:          return GFX_SIEB2_TOT;
2386     case EL_DYNABOMB_ACTIVE_1:  return GFX_DYNABOMB;
2387     case EL_DYNABOMB_ACTIVE_2:  return GFX_DYNABOMB;
2388     case EL_DYNABOMB_ACTIVE_3:  return GFX_DYNABOMB;
2389     case EL_DYNABOMB_ACTIVE_4:  return GFX_DYNABOMB;
2390     case EL_DYNABOMB_NR:        return GFX_DYNABOMB_NR;
2391     case EL_DYNABOMB_SZ:        return GFX_DYNABOMB_SZ;
2392     case EL_DYNABOMB_XL:        return GFX_DYNABOMB_XL;
2393     case EL_SOKOBAN_OBJEKT:     return GFX_SOKOBAN_OBJEKT;
2394     case EL_SOKOBAN_FELD_LEER:  return GFX_SOKOBAN_FELD_LEER;
2395     case EL_SOKOBAN_FELD_VOLL:  return GFX_SOKOBAN_FELD_VOLL;
2396     case EL_MAULWURF:           return GFX_MAULWURF;
2397     case EL_PINGUIN:            return GFX_PINGUIN;
2398     case EL_SCHWEIN:            return GFX_SCHWEIN;
2399     case EL_DRACHE:             return GFX_DRACHE;
2400     case EL_SONDE:              return GFX_SONDE;
2401     case EL_PFEIL_L:            return GFX_PFEIL_L;
2402     case EL_PFEIL_R:            return GFX_PFEIL_R;
2403     case EL_PFEIL_O:            return GFX_PFEIL_O;
2404     case EL_PFEIL_U:            return GFX_PFEIL_U;
2405     case EL_SPEED_PILL:         return GFX_SPEED_PILL;
2406     case EL_SP_TERMINAL_ACTIVE: return GFX_SP_TERMINAL;
2407     case EL_SP_BUG_ACTIVE:      return GFX_SP_BUG_ACTIVE;
2408     case EL_SP_ZONK:            return GFX_SP_ZONK;
2409       /* ^^^^^^^^^^ non-standard position in supaplex graphic set! */
2410     case EL_INVISIBLE_STEEL:    return GFX_INVISIBLE_STEEL;
2411     case EL_BLACK_ORB:          return GFX_BLACK_ORB;
2412     case EL_EM_GATE_1:          return GFX_EM_GATE_1;
2413     case EL_EM_GATE_2:          return GFX_EM_GATE_2;
2414     case EL_EM_GATE_3:          return GFX_EM_GATE_3;
2415     case EL_EM_GATE_4:          return GFX_EM_GATE_4;
2416     case EL_EM_GATE_1X:         return GFX_EM_GATE_1X;
2417     case EL_EM_GATE_2X:         return GFX_EM_GATE_2X;
2418     case EL_EM_GATE_3X:         return GFX_EM_GATE_3X;
2419     case EL_EM_GATE_4X:         return GFX_EM_GATE_4X;
2420     case EL_EM_KEY_1_FILE:      return GFX_EM_KEY_1;
2421     case EL_EM_KEY_2_FILE:      return GFX_EM_KEY_2;
2422     case EL_EM_KEY_3_FILE:      return GFX_EM_KEY_3;
2423     case EL_EM_KEY_4_FILE:      return GFX_EM_KEY_4;
2424     case EL_EM_KEY_1:           return GFX_EM_KEY_1;
2425     case EL_EM_KEY_2:           return GFX_EM_KEY_2;
2426     case EL_EM_KEY_3:           return GFX_EM_KEY_3;
2427     case EL_EM_KEY_4:           return GFX_EM_KEY_4;
2428
2429     default:
2430     {
2431       if (IS_CHAR(element))
2432         return GFX_CHAR_START + (element - EL_CHAR_START);
2433       else if (element >= EL_SP_START && element <= EL_SP_END)
2434       {
2435         int nr_element = element - EL_SP_START;
2436         int gfx_per_line = 8;
2437         int nr_graphic =
2438           (nr_element / gfx_per_line) * MORE_PER_LINE +
2439           (nr_element % gfx_per_line);
2440
2441         return GFX_START_ROCKSMORE + nr_graphic;
2442       }
2443       else
2444         return -1;
2445     }
2446   }
2447 }