rnd-19990610-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 #define MICROLABEL_EMPTY                0
1536 #define MICROLABEL_LEVEL_NAME           1
1537 #define MICROLABEL_CREATED_BY           2
1538 #define MICROLABEL_LEVEL_AUTHOR         3
1539 #define MICROLABEL_IMPORTED_FROM        4
1540 #define MICROLABEL_LEVEL_IMPORT_INFO    5
1541
1542 #define MAX_MICROLABEL_SIZE             (SXSIZE / FONT4_XSIZE)
1543
1544 static void DrawMicroLevelLabelExt(int mode)
1545 {
1546   char label_text[MAX_MICROLABEL_SIZE + 1];
1547
1548   XFillRectangle(display, drawto,gc,
1549                  SX, MICROLABEL_YPOS, SXSIZE, FONT4_YSIZE);
1550
1551   strncpy(label_text, (mode == MICROLABEL_LEVEL_NAME ? level.name :
1552                        mode == MICROLABEL_CREATED_BY ? "created by" :
1553                        mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
1554                        mode == MICROLABEL_IMPORTED_FROM ? "imported from" :
1555                        mode == MICROLABEL_LEVEL_IMPORT_INFO ?
1556                        leveldir[leveldir_nr].imported_from : ""),
1557           MAX_MICROLABEL_SIZE);
1558   label_text[MAX_MICROLABEL_SIZE] = '\0';
1559
1560   if (strlen(label_text) > 0)
1561   {
1562     int lxpos = SX + (SXSIZE - strlen(label_text) * FONT4_XSIZE) / 2;
1563     int lypos = MICROLABEL_YPOS;
1564
1565     DrawText(lxpos, lypos, label_text, FS_SMALL, FC_SPECIAL2);
1566   }
1567
1568   redraw_mask |= REDRAW_MICROLEVEL;
1569 }
1570
1571 void DrawMicroLevel(int xpos, int ypos, boolean restart)
1572 {
1573   static unsigned long scroll_delay = 0;
1574   static unsigned long label_delay = 0;
1575   static int from_x, from_y, scroll_direction;
1576   static int label_state, label_counter;
1577
1578   if (restart)
1579   {
1580     from_x = from_y = 0;
1581     scroll_direction = MV_RIGHT;
1582     label_state = 1;
1583     label_counter = 0;
1584
1585     DrawMicroLevelExt(xpos, ypos, from_x, from_y);
1586     DrawMicroLevelLabelExt(label_state);
1587
1588     /* initialize delay counters */
1589     DelayReached(&scroll_delay, 0);
1590     DelayReached(&label_delay, 0);
1591
1592     return;
1593   }
1594
1595   /* scroll micro level, if needed */
1596   if ((lev_fieldx > STD_LEV_FIELDX || lev_fieldy > STD_LEV_FIELDY) &&
1597       DelayReached(&scroll_delay, MICROLEVEL_SCROLL_DELAY))
1598   {
1599     switch (scroll_direction)
1600     {
1601       case MV_LEFT:
1602         if (from_x > 0)
1603           from_x--;
1604         else
1605           scroll_direction = MV_UP;
1606         break;
1607
1608       case MV_RIGHT:
1609         if (from_x < lev_fieldx - STD_LEV_FIELDX)
1610           from_x++;
1611         else
1612           scroll_direction = MV_DOWN;
1613         break;
1614
1615       case MV_UP:
1616         if (from_y > 0)
1617           from_y--;
1618         else
1619           scroll_direction = MV_RIGHT;
1620         break;
1621
1622       case MV_DOWN:
1623         if (from_y < lev_fieldy - STD_LEV_FIELDY)
1624           from_y++;
1625         else
1626           scroll_direction = MV_LEFT;
1627         break;
1628
1629       default:
1630         break;
1631     }
1632
1633     DrawMicroLevelExt(xpos, ypos, from_x, from_y);
1634   }
1635
1636   /* redraw micro level label, if needed */
1637   if (strcmp(level.name, NAMELESS_LEVEL_NAME) != 0 &&
1638       strcmp(level.author, ANONYMOUS_NAME) != 0 &&
1639       strcmp(level.author, leveldir[leveldir_nr].name) != 0 &&
1640       DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
1641   {
1642     int max_label_counter = 23;
1643
1644     if (leveldir[leveldir_nr].imported_from != NULL)
1645       max_label_counter += 14;
1646
1647     label_counter = (label_counter + 1) % max_label_counter;
1648     label_state = (label_counter >= 0 && label_counter <= 7 ?
1649                    MICROLABEL_LEVEL_NAME :
1650                    label_counter >= 9 && label_counter <= 12 ?
1651                    MICROLABEL_CREATED_BY :
1652                    label_counter >= 14 && label_counter <= 21 ?
1653                    MICROLABEL_LEVEL_AUTHOR :
1654                    label_counter >= 23 && label_counter <= 26 ?
1655                    MICROLABEL_IMPORTED_FROM :
1656                    label_counter >= 28 && label_counter <= 35 ?
1657                    MICROLABEL_LEVEL_IMPORT_INFO : MICROLABEL_EMPTY);
1658     DrawMicroLevelLabelExt(label_state);
1659   }
1660 }
1661
1662 int REQ_in_range(int x, int y)
1663 {
1664   if (y > DY+249 && y < DY+278)
1665   {
1666     if (x > DX+1 && x < DX+48)
1667       return 1;
1668     else if (x > DX+51 && x < DX+98) 
1669       return 2;
1670   }
1671   return 0;
1672 }
1673
1674 boolean Request(char *text, unsigned int req_state)
1675 {
1676   int mx, my, ty, result = -1;
1677   unsigned int old_door_state;
1678
1679 #ifndef MSDOS
1680   /* pause network game while waiting for request to answer */
1681   if (options.network &&
1682       game_status == PLAYING &&
1683       req_state & REQUEST_WAIT_FOR)
1684     SendToServer_PausePlaying();
1685 #endif
1686
1687   old_door_state = GetDoorState();
1688
1689   UnmapAllGadgets();
1690
1691   CloseDoor(DOOR_CLOSE_1);
1692
1693   /* save old door content */
1694   XCopyArea(display, pix[PIX_DB_DOOR], pix[PIX_DB_DOOR], gc,
1695             DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
1696             DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
1697
1698   /* clear door drawing field */
1699   XFillRectangle(display, drawto, gc, DX, DY, DXSIZE, DYSIZE);
1700
1701   /* write text for request */
1702   for(ty=0; ty<13; ty++)
1703   {
1704     int tx, tl, tc;
1705     char txt[256];
1706
1707     if (!*text)
1708       break;
1709
1710     for(tl=0,tx=0; tx<7; tl++,tx++)
1711     {
1712       tc = *(text + tx);
1713       if (!tc || tc == 32)
1714         break;
1715     }
1716     if (!tl)
1717     { 
1718       text++; 
1719       ty--; 
1720       continue; 
1721     }
1722     sprintf(txt, text); 
1723     txt[tl] = 0;
1724     DrawTextExt(drawto, gc,
1725                 DX + 51 - (tl * 14)/2, DY + 8 + ty * 16,
1726                 txt, FS_SMALL, FC_YELLOW);
1727     text += tl + (tc == 32 ? 1 : 0);
1728   }
1729
1730   if (req_state & REQ_ASK)
1731   {
1732     MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
1733     MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
1734   }
1735   else if (req_state & REQ_CONFIRM)
1736   {
1737     MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
1738   }
1739   else if (req_state & REQ_PLAYER)
1740   {
1741     MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
1742     MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
1743     MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
1744     MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
1745   }
1746
1747   /* copy request gadgets to door backbuffer */
1748   XCopyArea(display, drawto, pix[PIX_DB_DOOR], gc,
1749             DX, DY, DXSIZE, DYSIZE,
1750             DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
1751
1752   OpenDoor(DOOR_OPEN_1);
1753
1754 #if 0
1755   ClearEventQueue();
1756 #endif
1757
1758   if (!(req_state & REQUEST_WAIT_FOR))
1759     return(FALSE);
1760
1761   if (game_status != MAINMENU)
1762     InitAnimation();
1763
1764   button_status = MB_RELEASED;
1765
1766   request_gadget_id = -1;
1767
1768   while(result < 0)
1769   {
1770     if (XPending(display))
1771     {
1772       XEvent event;
1773
1774       XNextEvent(display, &event);
1775
1776       switch(event.type)
1777       {
1778         case ButtonPress:
1779         case ButtonRelease:
1780         case MotionNotify:
1781         {
1782           if (event.type == MotionNotify)
1783           {
1784             Window root, child;
1785             int root_x, root_y;
1786             int win_x, win_y;
1787             unsigned int mask;
1788
1789             if (!XQueryPointer(display, window, &root, &child,
1790                                &root_x, &root_y, &win_x, &win_y, &mask))
1791               continue;
1792
1793             if (!button_status)
1794               continue;
1795
1796             motion_status = TRUE;
1797             mx = ((XMotionEvent *) &event)->x;
1798             my = ((XMotionEvent *) &event)->y;
1799           }
1800           else
1801           {
1802             motion_status = FALSE;
1803             mx = ((XButtonEvent *) &event)->x;
1804             my = ((XButtonEvent *) &event)->y;
1805             if (event.type==ButtonPress)
1806               button_status = ((XButtonEvent *) &event)->button;
1807             else
1808               button_status = MB_RELEASED;
1809           }
1810
1811           /* this sets 'request_gadget_id' */
1812           HandleGadgets(mx, my, button_status);
1813
1814           switch(request_gadget_id)
1815           {
1816             case TOOL_CTRL_ID_YES:
1817               result = TRUE;
1818               break;
1819             case TOOL_CTRL_ID_NO:
1820               result = FALSE;
1821               break;
1822             case TOOL_CTRL_ID_CONFIRM:
1823               result = TRUE | FALSE;
1824               break;
1825
1826             case TOOL_CTRL_ID_PLAYER_1:
1827               result = 1;
1828               break;
1829             case TOOL_CTRL_ID_PLAYER_2:
1830               result = 2;
1831               break;
1832             case TOOL_CTRL_ID_PLAYER_3:
1833               result = 3;
1834               break;
1835             case TOOL_CTRL_ID_PLAYER_4:
1836               result = 4;
1837               break;
1838
1839             default:
1840               break;
1841           }
1842
1843           break;
1844         }
1845
1846         case KeyPress:
1847           switch(XLookupKeysym((XKeyEvent *)&event,
1848                                ((XKeyEvent *)&event)->state))
1849           {
1850             case XK_Return:
1851               result = 1;
1852               break;
1853
1854             case XK_Escape:
1855               result = 0;
1856               break;
1857
1858             default:
1859               break;
1860           }
1861           if (req_state & REQ_PLAYER)
1862             result = 0;
1863           break;
1864
1865         case KeyRelease:
1866           key_joystick_mapping = 0;
1867           break;
1868
1869         default:
1870           HandleOtherEvents(&event);
1871           break;
1872       }
1873     }
1874     else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
1875     {
1876       int joy = AnyJoystick();
1877
1878       if (joy & JOY_BUTTON_1)
1879         result = 1;
1880       else if (joy & JOY_BUTTON_2)
1881         result = 0;
1882     }
1883
1884     DoAnimation();
1885
1886     /* don't eat all CPU time */
1887     Delay(10);
1888   }
1889
1890   if (game_status != MAINMENU)
1891     StopAnimation();
1892
1893   UnmapToolButtons();
1894
1895   if (!(req_state & REQ_STAY_OPEN))
1896   {
1897     CloseDoor(DOOR_CLOSE_1);
1898
1899     if (!(req_state & REQ_STAY_CLOSED) && (old_door_state & DOOR_OPEN_1))
1900     {
1901       XCopyArea(display,pix[PIX_DB_DOOR],pix[PIX_DB_DOOR],gc,
1902                 DOOR_GFX_PAGEX2,DOOR_GFX_PAGEY1, DXSIZE,DYSIZE,
1903                 DOOR_GFX_PAGEX1,DOOR_GFX_PAGEY1);
1904       OpenDoor(DOOR_OPEN_1);
1905     }
1906   }
1907
1908   RemapAllGadgets();
1909
1910 #ifndef MSDOS
1911   /* continue network game after request */
1912   if (options.network &&
1913       game_status == PLAYING &&
1914       req_state & REQUEST_WAIT_FOR)
1915     SendToServer_ContinuePlaying();
1916 #endif
1917
1918   return(result);
1919 }
1920
1921 unsigned int OpenDoor(unsigned int door_state)
1922 {
1923   unsigned int new_door_state;
1924
1925   if (door_state & DOOR_COPY_BACK)
1926   {
1927     XCopyArea(display, pix[PIX_DB_DOOR], pix[PIX_DB_DOOR], gc,
1928               DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE + VYSIZE,
1929               DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
1930     door_state &= ~DOOR_COPY_BACK;
1931   }
1932
1933   new_door_state = MoveDoor(door_state);
1934
1935   return(new_door_state);
1936 }
1937
1938 unsigned int CloseDoor(unsigned int door_state)
1939 {
1940   unsigned int new_door_state;
1941
1942   XCopyArea(display, backbuffer, pix[PIX_DB_DOOR], gc,
1943             DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
1944   XCopyArea(display, backbuffer, pix[PIX_DB_DOOR], gc,
1945             VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
1946
1947   new_door_state = MoveDoor(door_state);
1948
1949   return(new_door_state);
1950 }
1951
1952 unsigned int GetDoorState()
1953 {
1954   return(MoveDoor(DOOR_GET_STATE));
1955 }
1956
1957 unsigned int MoveDoor(unsigned int door_state)
1958 {
1959   static int door1 = DOOR_OPEN_1;
1960   static int door2 = DOOR_CLOSE_2;
1961   static unsigned long door_delay = 0;
1962   int x, start, stepsize = 2;
1963   unsigned long door_delay_value = stepsize * 5;
1964
1965   if (door_state == DOOR_GET_STATE)
1966     return(door1 | door2);
1967
1968   if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
1969     door_state &= ~DOOR_OPEN_1;
1970   else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
1971     door_state &= ~DOOR_CLOSE_1;
1972   if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
1973     door_state &= ~DOOR_OPEN_2;
1974   else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
1975     door_state &= ~DOOR_CLOSE_2;
1976
1977   if (setup.quick_doors)
1978   {
1979     stepsize = 20;
1980     door_delay_value = 0;
1981     StopSound(SND_OEFFNEN);
1982   }
1983
1984   if (door_state & DOOR_ACTION)
1985   {
1986     if (!(door_state & DOOR_NO_DELAY))
1987       PlaySoundStereo(SND_OEFFNEN, PSND_MAX_RIGHT);
1988
1989     start = ((door_state & DOOR_NO_DELAY) ? DXSIZE : 0);
1990
1991     for(x=start; x<=DXSIZE; x+=stepsize)
1992     {
1993       WaitUntilDelayReached(&door_delay, door_delay_value);
1994
1995       if (door_state & DOOR_ACTION_1)
1996       {
1997         int i = (door_state & DOOR_OPEN_1 ? DXSIZE-x : x);
1998         int j = (DXSIZE - i) / 3;
1999
2000         XCopyArea(display, pix[PIX_DB_DOOR], drawto, gc,
2001                   DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + i/2,
2002                   DXSIZE,DYSIZE - i/2, DX, DY);
2003
2004         XFillRectangle(display, drawto, gc, DX, DY + DYSIZE - i/2, DXSIZE,i/2);
2005
2006         XSetClipOrigin(display, clip_gc[PIX_DOOR],
2007                        DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2008         XCopyArea(display, pix[PIX_DOOR], drawto,clip_gc[PIX_DOOR],
2009                   DXSIZE, DOOR_GFX_PAGEY1, i, 77, DX + DXSIZE - i, DY + j);
2010         XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
2011                   DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63, DX + DXSIZE - i,
2012                   DY + 140 + j);
2013         XSetClipOrigin(display, clip_gc[PIX_DOOR],
2014                        DX - DXSIZE + i, DY - (DOOR_GFX_PAGEY1 + j));
2015         XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
2016                   DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j, DX, DY);
2017         XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
2018                   DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63, DX, DY + 140 - j);
2019
2020         XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
2021                   DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
2022                   DX, DY + 77 - j);
2023         XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
2024                   DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
2025                   DX, DY + 203 - j);
2026         XSetClipOrigin(display, clip_gc[PIX_DOOR],
2027                        DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2028         XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
2029                   DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
2030                   DX + DXSIZE - i, DY + 77 + j);
2031         XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
2032                   DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
2033                   DX + DXSIZE - i, DY + 203 + j);
2034
2035         redraw_mask |= REDRAW_DOOR_1;
2036       }
2037
2038       if (door_state & DOOR_ACTION_2)
2039       {
2040         int i = (door_state & DOOR_OPEN_2 ? VXSIZE - x : x);
2041         int j = (VXSIZE - i) / 3;
2042
2043         XCopyArea(display, pix[PIX_DB_DOOR], drawto, gc,
2044                   DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + i/2,
2045                   VXSIZE, VYSIZE - i/2, VX, VY);
2046
2047         XFillRectangle(display, drawto, gc, VX, VY + VYSIZE-i/2, VXSIZE, i/2);
2048
2049         XSetClipOrigin(display, clip_gc[PIX_DOOR],
2050                        VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2051         XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
2052                   VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2, VX + VXSIZE-i, VY+j);
2053         XSetClipOrigin(display, clip_gc[PIX_DOOR],
2054                        VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
2055         XCopyArea(display, pix[PIX_DOOR], drawto,clip_gc[PIX_DOOR],
2056                   VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j, VX, VY);
2057
2058         XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
2059                   VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2, i, VYSIZE / 2,
2060                   VX, VY + VYSIZE / 2 - j);
2061         XSetClipOrigin(display, clip_gc[PIX_DOOR],
2062                        VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2063         XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
2064                   VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2, i, VYSIZE / 2 - j,
2065                   VX + VXSIZE - i, VY + VYSIZE / 2 + j);
2066
2067         redraw_mask |= REDRAW_DOOR_2;
2068       }
2069
2070       BackToFront();
2071
2072       if (game_status == MAINMENU)
2073         DoAnimation();
2074     }
2075   }
2076
2077   if (setup.quick_doors)
2078     StopSound(SND_OEFFNEN);
2079
2080   if (door_state & DOOR_ACTION_1)
2081     door1 = door_state & DOOR_ACTION_1;
2082   if (door_state & DOOR_ACTION_2)
2083     door2 = door_state & DOOR_ACTION_2;
2084
2085   return (door1 | door2);
2086 }
2087
2088 void DrawSpecialEditorDoor()
2089 {
2090   /* draw bigger toolbox window */
2091   XCopyArea(display, pix[PIX_DOOR], drawto, gc,
2092             DOOR_GFX_PAGEX7, 0, 108, 56, EX - 4, EY - 12);
2093
2094   redraw_mask |= REDRAW_ALL;
2095 }
2096
2097 void UndrawSpecialEditorDoor()
2098 {
2099   /* draw normal tape recorder window */
2100   XCopyArea(display, pix[PIX_BACK], drawto, gc,
2101             562, 344, 108, 56, EX - 4, EY - 12);
2102
2103   redraw_mask |= REDRAW_ALL;
2104 }
2105
2106 int ReadPixel(Drawable d, int x, int y)
2107 {
2108   XImage *pixel_image;
2109   unsigned long pixel_value;
2110
2111   pixel_image = XGetImage(display, d, x, y, 1, 1, AllPlanes, ZPixmap);
2112   pixel_value = XGetPixel(pixel_image, 0, 0);
2113
2114   XDestroyImage(pixel_image);
2115
2116   return pixel_value;
2117 }
2118
2119 /* ---------- new tool button stuff ---------------------------------------- */
2120
2121 /* graphic position values for tool buttons */
2122 #define TOOL_BUTTON_YES_XPOS            2
2123 #define TOOL_BUTTON_YES_YPOS            250
2124 #define TOOL_BUTTON_YES_GFX_YPOS        0
2125 #define TOOL_BUTTON_YES_XSIZE           46
2126 #define TOOL_BUTTON_YES_YSIZE           28
2127 #define TOOL_BUTTON_NO_XPOS             52
2128 #define TOOL_BUTTON_NO_YPOS             TOOL_BUTTON_YES_YPOS
2129 #define TOOL_BUTTON_NO_GFX_YPOS         TOOL_BUTTON_YES_GFX_YPOS
2130 #define TOOL_BUTTON_NO_XSIZE            TOOL_BUTTON_YES_XSIZE
2131 #define TOOL_BUTTON_NO_YSIZE            TOOL_BUTTON_YES_YSIZE
2132 #define TOOL_BUTTON_CONFIRM_XPOS        TOOL_BUTTON_YES_XPOS
2133 #define TOOL_BUTTON_CONFIRM_YPOS        TOOL_BUTTON_YES_YPOS
2134 #define TOOL_BUTTON_CONFIRM_GFX_YPOS    30
2135 #define TOOL_BUTTON_CONFIRM_XSIZE       96
2136 #define TOOL_BUTTON_CONFIRM_YSIZE       TOOL_BUTTON_YES_YSIZE
2137 #define TOOL_BUTTON_PLAYER_XSIZE        30
2138 #define TOOL_BUTTON_PLAYER_YSIZE        30
2139 #define TOOL_BUTTON_PLAYER_GFX_XPOS     5
2140 #define TOOL_BUTTON_PLAYER_GFX_YPOS     185
2141 #define TOOL_BUTTON_PLAYER_XPOS         (5 + TOOL_BUTTON_PLAYER_XSIZE / 2)
2142 #define TOOL_BUTTON_PLAYER_YPOS         (215 - TOOL_BUTTON_PLAYER_YSIZE / 2)
2143 #define TOOL_BUTTON_PLAYER1_XPOS        (TOOL_BUTTON_PLAYER_XPOS \
2144                                          + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2145 #define TOOL_BUTTON_PLAYER2_XPOS        (TOOL_BUTTON_PLAYER_XPOS \
2146                                          + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2147 #define TOOL_BUTTON_PLAYER3_XPOS        (TOOL_BUTTON_PLAYER_XPOS \
2148                                          + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2149 #define TOOL_BUTTON_PLAYER4_XPOS        (TOOL_BUTTON_PLAYER_XPOS \
2150                                          + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2151 #define TOOL_BUTTON_PLAYER1_YPOS        (TOOL_BUTTON_PLAYER_YPOS \
2152                                          + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2153 #define TOOL_BUTTON_PLAYER2_YPOS        (TOOL_BUTTON_PLAYER_YPOS \
2154                                          + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2155 #define TOOL_BUTTON_PLAYER3_YPOS        (TOOL_BUTTON_PLAYER_YPOS \
2156                                          + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2157 #define TOOL_BUTTON_PLAYER4_YPOS        (TOOL_BUTTON_PLAYER_YPOS \
2158                                          + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2159
2160 static struct
2161 {
2162   int xpos, ypos;
2163   int x, y;
2164   int width, height;
2165   int gadget_id;
2166   char *infotext;
2167 } toolbutton_info[NUM_TOOL_BUTTONS] =
2168 {
2169   {
2170     TOOL_BUTTON_YES_XPOS,       TOOL_BUTTON_YES_GFX_YPOS,
2171     TOOL_BUTTON_YES_XPOS,       TOOL_BUTTON_YES_YPOS,
2172     TOOL_BUTTON_YES_XSIZE,      TOOL_BUTTON_YES_YSIZE,
2173     TOOL_CTRL_ID_YES,
2174     "yes"
2175   },
2176   {
2177     TOOL_BUTTON_NO_XPOS,        TOOL_BUTTON_NO_GFX_YPOS,
2178     TOOL_BUTTON_NO_XPOS,        TOOL_BUTTON_NO_YPOS,
2179     TOOL_BUTTON_NO_XSIZE,       TOOL_BUTTON_NO_YSIZE,
2180     TOOL_CTRL_ID_NO,
2181     "no"
2182   },
2183   {
2184     TOOL_BUTTON_CONFIRM_XPOS,   TOOL_BUTTON_CONFIRM_GFX_YPOS,
2185     TOOL_BUTTON_CONFIRM_XPOS,   TOOL_BUTTON_CONFIRM_YPOS,
2186     TOOL_BUTTON_CONFIRM_XSIZE,  TOOL_BUTTON_CONFIRM_YSIZE,
2187     TOOL_CTRL_ID_CONFIRM,
2188     "confirm"
2189   },
2190   {
2191     TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2192     TOOL_BUTTON_PLAYER1_XPOS,   TOOL_BUTTON_PLAYER1_YPOS,
2193     TOOL_BUTTON_PLAYER_XSIZE,   TOOL_BUTTON_PLAYER_YSIZE,
2194     TOOL_CTRL_ID_PLAYER_1,
2195     "player 1"
2196   },
2197   {
2198     TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2199     TOOL_BUTTON_PLAYER2_XPOS,   TOOL_BUTTON_PLAYER2_YPOS,
2200     TOOL_BUTTON_PLAYER_XSIZE,   TOOL_BUTTON_PLAYER_YSIZE,
2201     TOOL_CTRL_ID_PLAYER_2,
2202     "player 2"
2203   },
2204   {
2205     TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2206     TOOL_BUTTON_PLAYER3_XPOS,   TOOL_BUTTON_PLAYER3_YPOS,
2207     TOOL_BUTTON_PLAYER_XSIZE,   TOOL_BUTTON_PLAYER_YSIZE,
2208     TOOL_CTRL_ID_PLAYER_3,
2209     "player 3"
2210   },
2211   {
2212     TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2213     TOOL_BUTTON_PLAYER4_XPOS,   TOOL_BUTTON_PLAYER4_YPOS,
2214     TOOL_BUTTON_PLAYER_XSIZE,   TOOL_BUTTON_PLAYER_YSIZE,
2215     TOOL_CTRL_ID_PLAYER_4,
2216     "player 4"
2217   }
2218 };
2219
2220 static void DoNotDisplayInfoText(void *ptr)
2221 {
2222   return;
2223 }
2224
2225 void CreateToolButtons()
2226 {
2227   int i;
2228
2229   for (i=0; i<NUM_TOOL_BUTTONS; i++)
2230   {
2231     Pixmap gd_pixmap = pix[PIX_DOOR];
2232     Pixmap deco_pixmap = None;
2233     int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
2234     struct GadgetInfo *gi;
2235     unsigned long event_mask;
2236     int gd_xoffset, gd_yoffset;
2237     int gd_x1, gd_x2, gd_y;
2238     int id = i;
2239
2240     event_mask = GD_EVENT_RELEASED;
2241
2242     gd_xoffset = toolbutton_info[i].xpos;
2243     gd_yoffset = toolbutton_info[i].ypos;
2244     gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
2245     gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
2246     gd_y = DOOR_GFX_PAGEY1 + gd_yoffset;
2247
2248     if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
2249     {
2250       getMiniGraphicSource(GFX_SPIELER1 + id - TOOL_CTRL_ID_PLAYER_1,
2251                            &deco_pixmap, &deco_x, &deco_y);
2252       deco_xpos = (toolbutton_info[i].width - MINI_TILEX) / 2;
2253       deco_ypos = (toolbutton_info[i].height - MINI_TILEY) / 2;
2254     }
2255
2256     gi = CreateGadget(GDI_CUSTOM_ID, id,
2257                       GDI_INFO_TEXT, toolbutton_info[i].infotext,
2258                       GDI_X, DX + toolbutton_info[i].x,
2259                       GDI_Y, DY + toolbutton_info[i].y,
2260                       GDI_WIDTH, toolbutton_info[i].width,
2261                       GDI_HEIGHT, toolbutton_info[i].height,
2262                       GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
2263                       GDI_STATE, GD_BUTTON_UNPRESSED,
2264                       GDI_DESIGN_UNPRESSED, gd_pixmap, gd_x1, gd_y,
2265                       GDI_DESIGN_PRESSED, gd_pixmap, gd_x2, gd_y,
2266                       GDI_DECORATION_DESIGN, deco_pixmap, deco_x, deco_y,
2267                       GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
2268                       GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
2269                       GDI_DECORATION_SHIFTING, 1, 1,
2270                       GDI_EVENT_MASK, event_mask,
2271                       GDI_CALLBACK_ACTION, HandleToolButtons,
2272                       GDI_CALLBACK_INFO, DoNotDisplayInfoText,
2273                       GDI_END);
2274
2275     if (gi == NULL)
2276       Error(ERR_EXIT, "cannot create gadget");
2277
2278     tool_gadget[id] = gi;
2279   }
2280 }
2281
2282 static void UnmapToolButtons()
2283 {
2284   int i;
2285
2286   for (i=0; i<NUM_TOOL_BUTTONS; i++)
2287     UnmapGadget(tool_gadget[i]);
2288 }
2289
2290 static void HandleToolButtons(struct GadgetInfo *gi)
2291 {
2292   request_gadget_id = gi->custom_id;
2293 }
2294
2295 int el2gfx(int element)
2296 {
2297   switch(element)
2298   {
2299     case EL_LEERRAUM:           return -1;
2300     case EL_ERDREICH:           return GFX_ERDREICH;
2301     case EL_MAUERWERK:          return GFX_MAUERWERK;
2302     case EL_FELSBODEN:          return GFX_FELSBODEN;
2303     case EL_FELSBROCKEN:        return GFX_FELSBROCKEN;
2304     case EL_SCHLUESSEL:         return GFX_SCHLUESSEL;
2305     case EL_EDELSTEIN:          return GFX_EDELSTEIN;
2306     case EL_AUSGANG_ZU:         return GFX_AUSGANG_ZU;
2307     case EL_AUSGANG_ACT:        return GFX_AUSGANG_ACT;
2308     case EL_AUSGANG_AUF:        return GFX_AUSGANG_AUF;
2309     case EL_SPIELFIGUR:         return GFX_SPIELFIGUR;
2310     case EL_SPIELER1:           return GFX_SPIELER1;
2311     case EL_SPIELER2:           return GFX_SPIELER2;
2312     case EL_SPIELER3:           return GFX_SPIELER3;
2313     case EL_SPIELER4:           return GFX_SPIELER4;
2314     case EL_KAEFER:             return GFX_KAEFER;
2315     case EL_KAEFER_R:           return GFX_KAEFER_R;
2316     case EL_KAEFER_O:           return GFX_KAEFER_O;
2317     case EL_KAEFER_L:           return GFX_KAEFER_L;
2318     case EL_KAEFER_U:           return GFX_KAEFER_U;
2319     case EL_FLIEGER:            return GFX_FLIEGER;
2320     case EL_FLIEGER_R:          return GFX_FLIEGER_R;
2321     case EL_FLIEGER_O:          return GFX_FLIEGER_O;
2322     case EL_FLIEGER_L:          return GFX_FLIEGER_L;
2323     case EL_FLIEGER_U:          return GFX_FLIEGER_U;
2324     case EL_BUTTERFLY:          return GFX_BUTTERFLY;
2325     case EL_BUTTERFLY_R:        return GFX_BUTTERFLY_R;
2326     case EL_BUTTERFLY_O:        return GFX_BUTTERFLY_O;
2327     case EL_BUTTERFLY_L:        return GFX_BUTTERFLY_L;
2328     case EL_BUTTERFLY_U:        return GFX_BUTTERFLY_U;
2329     case EL_FIREFLY:            return GFX_FIREFLY;
2330     case EL_FIREFLY_R:          return GFX_FIREFLY_R;
2331     case EL_FIREFLY_O:          return GFX_FIREFLY_O;
2332     case EL_FIREFLY_L:          return GFX_FIREFLY_L;
2333     case EL_FIREFLY_U:          return GFX_FIREFLY_U;
2334     case EL_MAMPFER:            return GFX_MAMPFER;
2335     case EL_ROBOT:              return GFX_ROBOT;
2336     case EL_BETON:              return GFX_BETON;
2337     case EL_DIAMANT:            return GFX_DIAMANT;
2338     case EL_MORAST_LEER:        return GFX_MORAST_LEER;
2339     case EL_MORAST_VOLL:        return GFX_MORAST_VOLL;
2340     case EL_TROPFEN:            return GFX_TROPFEN;
2341     case EL_BOMBE:              return GFX_BOMBE;
2342     case EL_SIEB_INAKTIV:       return GFX_SIEB_INAKTIV;
2343     case EL_SIEB_LEER:          return GFX_SIEB_LEER;
2344     case EL_SIEB_VOLL:          return GFX_SIEB_VOLL;
2345     case EL_SIEB_TOT:           return GFX_SIEB_TOT;
2346     case EL_SALZSAEURE:         return GFX_SALZSAEURE;
2347     case EL_AMOEBE_TOT:         return GFX_AMOEBE_TOT;
2348     case EL_AMOEBE_NASS:        return GFX_AMOEBE_NASS;
2349     case EL_AMOEBE_NORM:        return GFX_AMOEBE_NORM;
2350     case EL_AMOEBE_VOLL:        return GFX_AMOEBE_VOLL;
2351     case EL_AMOEBE_BD:          return GFX_AMOEBE_BD;
2352     case EL_AMOEBA2DIAM:        return GFX_AMOEBA2DIAM;
2353     case EL_KOKOSNUSS:          return GFX_KOKOSNUSS;
2354     case EL_LIFE:               return GFX_LIFE;
2355     case EL_LIFE_ASYNC:         return GFX_LIFE_ASYNC;
2356     case EL_DYNAMITE_ACTIVE:    return GFX_DYNAMIT;
2357     case EL_BADEWANNE:          return GFX_BADEWANNE;
2358     case EL_BADEWANNE1:         return GFX_BADEWANNE1;
2359     case EL_BADEWANNE2:         return GFX_BADEWANNE2;
2360     case EL_BADEWANNE3:         return GFX_BADEWANNE3;
2361     case EL_BADEWANNE4:         return GFX_BADEWANNE4;
2362     case EL_BADEWANNE5:         return GFX_BADEWANNE5;
2363     case EL_ABLENK_AUS:         return GFX_ABLENK_AUS;
2364     case EL_ABLENK_EIN:         return GFX_ABLENK_EIN;
2365     case EL_SCHLUESSEL1:        return GFX_SCHLUESSEL1;
2366     case EL_SCHLUESSEL2:        return GFX_SCHLUESSEL2;
2367     case EL_SCHLUESSEL3:        return GFX_SCHLUESSEL3;
2368     case EL_SCHLUESSEL4:        return GFX_SCHLUESSEL4;
2369     case EL_PFORTE1:            return GFX_PFORTE1;
2370     case EL_PFORTE2:            return GFX_PFORTE2;
2371     case EL_PFORTE3:            return GFX_PFORTE3;
2372     case EL_PFORTE4:            return GFX_PFORTE4;
2373     case EL_PFORTE1X:           return GFX_PFORTE1X;
2374     case EL_PFORTE2X:           return GFX_PFORTE2X;
2375     case EL_PFORTE3X:           return GFX_PFORTE3X;
2376     case EL_PFORTE4X:           return GFX_PFORTE4X;
2377     case EL_DYNAMITE_INACTIVE:  return GFX_DYNAMIT_AUS;
2378     case EL_PACMAN:             return GFX_PACMAN;
2379     case EL_PACMAN_R:           return GFX_PACMAN_R;
2380     case EL_PACMAN_O:           return GFX_PACMAN_O;
2381     case EL_PACMAN_L:           return GFX_PACMAN_L;
2382     case EL_PACMAN_U:           return GFX_PACMAN_U;
2383     case EL_UNSICHTBAR:         return GFX_UNSICHTBAR;
2384     case EL_ERZ_EDEL:           return GFX_ERZ_EDEL;
2385     case EL_ERZ_DIAM:           return GFX_ERZ_DIAM;
2386     case EL_BIRNE_AUS:          return GFX_BIRNE_AUS;
2387     case EL_BIRNE_EIN:          return GFX_BIRNE_EIN;
2388     case EL_ZEIT_VOLL:          return GFX_ZEIT_VOLL;
2389     case EL_ZEIT_LEER:          return GFX_ZEIT_LEER;
2390     case EL_MAUER_LEBT:         return GFX_MAUER_LEBT;
2391     case EL_MAUER_X:            return GFX_MAUER_X;
2392     case EL_MAUER_Y:            return GFX_MAUER_Y;
2393     case EL_MAUER_XY:           return GFX_MAUER_XY;
2394     case EL_EDELSTEIN_BD:       return GFX_EDELSTEIN_BD;
2395     case EL_EDELSTEIN_GELB:     return GFX_EDELSTEIN_GELB;
2396     case EL_EDELSTEIN_ROT:      return GFX_EDELSTEIN_ROT;
2397     case EL_EDELSTEIN_LILA:     return GFX_EDELSTEIN_LILA;
2398     case EL_ERZ_EDEL_BD:        return GFX_ERZ_EDEL_BD;
2399     case EL_ERZ_EDEL_GELB:      return GFX_ERZ_EDEL_GELB;
2400     case EL_ERZ_EDEL_ROT:       return GFX_ERZ_EDEL_ROT;
2401     case EL_ERZ_EDEL_LILA:      return GFX_ERZ_EDEL_LILA;
2402     case EL_MAMPFER2:           return GFX_MAMPFER2;
2403     case EL_SIEB2_INAKTIV:      return GFX_SIEB2_INAKTIV;
2404     case EL_SIEB2_LEER:         return GFX_SIEB2_LEER;
2405     case EL_SIEB2_VOLL:         return GFX_SIEB2_VOLL;
2406     case EL_SIEB2_TOT:          return GFX_SIEB2_TOT;
2407     case EL_DYNABOMB_ACTIVE_1:  return GFX_DYNABOMB;
2408     case EL_DYNABOMB_ACTIVE_2:  return GFX_DYNABOMB;
2409     case EL_DYNABOMB_ACTIVE_3:  return GFX_DYNABOMB;
2410     case EL_DYNABOMB_ACTIVE_4:  return GFX_DYNABOMB;
2411     case EL_DYNABOMB_NR:        return GFX_DYNABOMB_NR;
2412     case EL_DYNABOMB_SZ:        return GFX_DYNABOMB_SZ;
2413     case EL_DYNABOMB_XL:        return GFX_DYNABOMB_XL;
2414     case EL_SOKOBAN_OBJEKT:     return GFX_SOKOBAN_OBJEKT;
2415     case EL_SOKOBAN_FELD_LEER:  return GFX_SOKOBAN_FELD_LEER;
2416     case EL_SOKOBAN_FELD_VOLL:  return GFX_SOKOBAN_FELD_VOLL;
2417     case EL_MAULWURF:           return GFX_MAULWURF;
2418     case EL_PINGUIN:            return GFX_PINGUIN;
2419     case EL_SCHWEIN:            return GFX_SCHWEIN;
2420     case EL_DRACHE:             return GFX_DRACHE;
2421     case EL_SONDE:              return GFX_SONDE;
2422     case EL_PFEIL_L:            return GFX_PFEIL_L;
2423     case EL_PFEIL_R:            return GFX_PFEIL_R;
2424     case EL_PFEIL_O:            return GFX_PFEIL_O;
2425     case EL_PFEIL_U:            return GFX_PFEIL_U;
2426     case EL_SPEED_PILL:         return GFX_SPEED_PILL;
2427     case EL_SP_TERMINAL_ACTIVE: return GFX_SP_TERMINAL;
2428     case EL_SP_BUG_ACTIVE:      return GFX_SP_BUG_ACTIVE;
2429     case EL_SP_ZONK:            return GFX_SP_ZONK;
2430       /* ^^^^^^^^^^ non-standard position in supaplex graphic set! */
2431     case EL_INVISIBLE_STEEL:    return GFX_INVISIBLE_STEEL;
2432     case EL_BLACK_ORB:          return GFX_BLACK_ORB;
2433     case EL_EM_GATE_1:          return GFX_EM_GATE_1;
2434     case EL_EM_GATE_2:          return GFX_EM_GATE_2;
2435     case EL_EM_GATE_3:          return GFX_EM_GATE_3;
2436     case EL_EM_GATE_4:          return GFX_EM_GATE_4;
2437     case EL_EM_GATE_1X:         return GFX_EM_GATE_1X;
2438     case EL_EM_GATE_2X:         return GFX_EM_GATE_2X;
2439     case EL_EM_GATE_3X:         return GFX_EM_GATE_3X;
2440     case EL_EM_GATE_4X:         return GFX_EM_GATE_4X;
2441     case EL_EM_KEY_1_FILE:      return GFX_EM_KEY_1;
2442     case EL_EM_KEY_2_FILE:      return GFX_EM_KEY_2;
2443     case EL_EM_KEY_3_FILE:      return GFX_EM_KEY_3;
2444     case EL_EM_KEY_4_FILE:      return GFX_EM_KEY_4;
2445     case EL_EM_KEY_1:           return GFX_EM_KEY_1;
2446     case EL_EM_KEY_2:           return GFX_EM_KEY_2;
2447     case EL_EM_KEY_3:           return GFX_EM_KEY_3;
2448     case EL_EM_KEY_4:           return GFX_EM_KEY_4;
2449     case EL_PEARL:              return GFX_PEARL;
2450     case EL_CRYSTAL:            return GFX_CRYSTAL;
2451     case EL_WALL_PEARL:         return GFX_WALL_PEARL;
2452     case EL_WALL_CRYSTAL:       return GFX_WALL_CRYSTAL;
2453     case EL_DOOR_WHITE:         return GFX_DOOR_WHITE;
2454     case EL_DOOR_WHITE_GRAY:    return GFX_DOOR_WHITE_GRAY;
2455     case EL_KEY_WHITE:          return GFX_KEY_WHITE;
2456     case EL_FORCE_FIELD:        return GFX_FORCE_FIELD;
2457     case EL_EXTRA_TIME:         return GFX_EXTRA_TIME;
2458     case EL_SWITCH_GATE_OPEN:   return GFX_SWITCH_GATE_OPEN;
2459     case EL_SWITCH_GATE_CLOSED: return GFX_SWITCH_GATE_CLOSED;
2460     case EL_SWITCH_GATE_SWITCH: return GFX_SWITCH_GATE_SWITCH;
2461     case EL_TIME_GATE:          return GFX_TIME_GATE;
2462     case EL_TIME_GATE_WHEEL:    return GFX_TIME_GATE_WHEEL;
2463     case EL_BELT_GREEN_LEFT:    return GFX_BELT_GREEN_LEFT;
2464     case EL_BELT_GREEN_MIDDLE:  return GFX_BELT_GREEN_MIDDLE;
2465     case EL_BELT_GREEN_RIGHT:   return GFX_BELT_GREEN_RIGHT;
2466     case EL_BELT_GREEN_SWITCH:  return GFX_BELT_GREEN_SWITCH;
2467     case EL_BELT_RED_LEFT:      return GFX_BELT_RED_LEFT;
2468     case EL_BELT_RED_MIDDLE:    return GFX_BELT_RED_MIDDLE;
2469     case EL_BELT_RED_RIGHT:     return GFX_BELT_RED_RIGHT;
2470     case EL_BELT_RED_SWITCH:    return GFX_BELT_RED_SWITCH;
2471     case EL_BELT_BLUE_LEFT:     return GFX_BELT_BLUE_LEFT;
2472     case EL_BELT_BLUE_MIDDLE:   return GFX_BELT_BLUE_MIDDLE;
2473     case EL_BELT_BLUE_RIGHT:    return GFX_BELT_BLUE_RIGHT;
2474     case EL_BELT_BLUE_SWITCH:   return GFX_BELT_BLUE_SWITCH;
2475     case EL_LANDMINE:           return GFX_LANDMINE;
2476     case EL_ENVELOPE:           return GFX_ENVELOPE;
2477     case EL_LIGHT_SWITCH:       return GFX_LIGHT_SWITCH;
2478     case EL_SIGN_EXCLAMATION:   return GFX_SIGN_EXCLAMATION;
2479     case EL_SIGN_RADIOACTIVITY: return GFX_SIGN_RADIOACTIVITY;
2480     case EL_SIGN_STOP:          return GFX_SIGN_STOP;
2481     case EL_SIGN_WHEELCHAIR:    return GFX_SIGN_WHEELCHAIR;
2482     case EL_SIGN_PARKING:       return GFX_SIGN_PARKING;
2483     case EL_SIGN_ONEWAY:        return GFX_SIGN_ONEWAY;
2484     case EL_SIGN_HEART:         return GFX_SIGN_HEART;
2485     case EL_SIGN_TRIANGLE:      return GFX_SIGN_TRIANGLE;
2486     case EL_SIGN_ROUND:         return GFX_SIGN_ROUND;
2487     case EL_SIGN_EXIT:          return GFX_SIGN_EXIT;
2488     case EL_SIGN_YINYANG:       return GFX_SIGN_YINYANG;
2489     case EL_SIGN_OTHER:         return GFX_SIGN_OTHER;
2490     case EL_MOLE_LEFT:          return GFX_MOLE_LEFT;
2491     case EL_MOLE_RIGHT:         return GFX_MOLE_RIGHT;
2492     case EL_MOLE_UP:            return GFX_MOLE_UP;
2493     case EL_MOLE_DOWN:          return GFX_MOLE_DOWN;
2494     case EL_STEEL_SLANTED:      return GFX_STEEL_SLANTED;
2495     case EL_SAND_INVISIBLE:     return GFX_SAND_INVISIBLE;
2496
2497     default:
2498     {
2499       if (IS_CHAR(element))
2500         return GFX_CHAR_START + (element - EL_CHAR_START);
2501       else if (element >= EL_SP_START && element <= EL_SP_END)
2502       {
2503         int nr_element = element - EL_SP_START;
2504         int gfx_per_line = 8;
2505         int nr_graphic =
2506           (nr_element / gfx_per_line) * MORE_PER_LINE +
2507           (nr_element % gfx_per_line);
2508
2509         return GFX_START_ROCKSMORE + nr_graphic;
2510       }
2511       else
2512         return -1;
2513     }
2514   }
2515 }