rnd-19990222-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_DYNAMIT)
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 (element != EL_DYNAMIT && element != EL_DYNABOMB)
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 (EL_DYNAMIT or EL_DYNABOMB) */
635
636   if (element == EL_DYNAMIT || element == EL_DYNABOMB)
637   {
638     graphic = el2gfx(element);
639
640     if (element == EL_DYNAMIT)
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   dest_x = FX + x * TILEX + dx;
983   dest_y = FY + y * TILEY + dy;
984
985 #if DEBUG
986   if (!IN_SCR_FIELD(x,y))
987   {
988     printf("DrawGraphicShifted(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
989     printf("DrawGraphicShifted(): This should never happen!\n");
990     return;
991   }
992 #endif
993
994   if (mask_mode == USE_MASKING)
995   {
996     if (tile_clipmask[tile] != None)
997     {
998       XSetClipMask(display, tile_clip_gc, tile_clipmask[tile]);
999       XSetClipOrigin(display, tile_clip_gc, dest_x, dest_y);
1000       XCopyArea(display, src_pixmap, drawto_field, tile_clip_gc,
1001                 src_x, src_y, TILEX, TILEY, dest_x, dest_y);
1002     }
1003     else
1004     {
1005 #if DEBUG
1006       printf("DrawGraphicShifted(): tile '%d' needs clipping!\n", tile);
1007 #endif
1008
1009       XSetClipOrigin(display, drawing_gc, dest_x - src_x, dest_y - src_y);
1010       XCopyArea(display, src_pixmap, drawto_field, drawing_gc,
1011                 src_x, src_y, width, height, dest_x, dest_y);
1012     }
1013   }
1014   else
1015     XCopyArea(display, src_pixmap, drawto_field, gc,
1016               src_x, src_y, width, height, dest_x, dest_y);
1017
1018   MarkTileDirty(x,y);
1019 }
1020
1021 void DrawGraphicShiftedThruMask(int x,int y, int dx,int dy, int graphic,
1022                                 int cut_mode)
1023 {
1024   DrawGraphicShifted(x,y, dx,dy, graphic, cut_mode, USE_MASKING);
1025 }
1026
1027 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
1028                           int cut_mode, int mask_mode)
1029 {
1030   int ux = LEVELX(x), uy = LEVELY(y);
1031   int graphic = el2gfx(element);
1032   int phase8 = ABS(MovPos[ux][uy]) / (TILEX / 8);
1033   int phase4 = phase8 / 2;
1034   int phase2  = phase8 / 4;
1035   int dir = MovDir[ux][uy];
1036
1037   if (element == EL_PACMAN || element == EL_KAEFER || element == EL_FLIEGER)
1038   {
1039     graphic += 4 * !phase2;
1040
1041     if (dir == MV_UP)
1042       graphic += 1;
1043     else if (dir == MV_LEFT)
1044       graphic += 2;
1045     else if (dir == MV_DOWN)
1046       graphic += 3;
1047   }
1048   else if (element == EL_SP_SNIKSNAK)
1049   {
1050     if (dir == MV_LEFT)
1051       graphic = GFX_SP_SNIKSNAK_LEFT;
1052     else if (dir == MV_RIGHT)
1053       graphic = GFX_SP_SNIKSNAK_RIGHT;
1054     else if (dir == MV_UP)
1055       graphic = GFX_SP_SNIKSNAK_UP;
1056     else
1057       graphic = GFX_SP_SNIKSNAK_DOWN;
1058
1059     graphic += (phase8 < 4 ? phase8 : 7 - phase8);
1060   }
1061   else if (element == EL_SP_ELECTRON)
1062   {
1063     graphic = GFX2_SP_ELECTRON + getGraphicAnimationPhase(8, 2, ANIM_NORMAL);
1064   }
1065   else if (element == EL_MAULWURF || element == EL_PINGUIN ||
1066            element == EL_SCHWEIN || element == EL_DRACHE)
1067   {
1068     if (dir == MV_LEFT)
1069       graphic = (element == EL_MAULWURF ? GFX_MAULWURF_LEFT :
1070                  element == EL_PINGUIN ? GFX_PINGUIN_LEFT :
1071                  element == EL_SCHWEIN ? GFX_SCHWEIN_LEFT : GFX_DRACHE_LEFT);
1072     else if (dir == MV_RIGHT)
1073       graphic = (element == EL_MAULWURF ? GFX_MAULWURF_RIGHT :
1074                  element == EL_PINGUIN ? GFX_PINGUIN_RIGHT :
1075                  element == EL_SCHWEIN ? GFX_SCHWEIN_RIGHT : GFX_DRACHE_RIGHT);
1076     else if (dir == MV_UP)
1077       graphic = (element == EL_MAULWURF ? GFX_MAULWURF_UP :
1078                  element == EL_PINGUIN ? GFX_PINGUIN_UP :
1079                  element == EL_SCHWEIN ? GFX_SCHWEIN_UP : GFX_DRACHE_UP);
1080     else
1081       graphic = (element == EL_MAULWURF ? GFX_MAULWURF_DOWN :
1082                  element == EL_PINGUIN ? GFX_PINGUIN_DOWN :
1083                  element == EL_SCHWEIN ? GFX_SCHWEIN_DOWN : GFX_DRACHE_DOWN);
1084
1085     graphic += phase4;
1086   }
1087   else if (element == EL_SONDE)
1088   {
1089     graphic = GFX_SONDE_START + getGraphicAnimationPhase(8, 2, ANIM_NORMAL);
1090   }
1091   else if (element == EL_SALZSAEURE)
1092   {
1093     graphic = GFX_GEBLUBBER + getGraphicAnimationPhase(4, 10, ANIM_NORMAL);
1094   }
1095   else if (element == EL_BUTTERFLY || element == EL_FIREFLY)
1096   {
1097     graphic += !phase2;
1098   }
1099   else if ((element == EL_FELSBROCKEN || element == EL_SP_ZONK ||
1100             IS_GEM(element)) && !cut_mode)
1101   {
1102     if (element == EL_FELSBROCKEN || element == EL_SP_ZONK)
1103     {
1104       if (dir == MV_LEFT)
1105         graphic += (4 - phase4) % 4;
1106       else if (dir == MV_RIGHT)
1107         graphic += phase4;
1108       else
1109         graphic += phase2 * 2;
1110     }
1111     else if (element != EL_SP_INFOTRON)
1112       graphic += phase2;
1113
1114     /*
1115     if (element == EL_SP_ZONK)
1116     {
1117       if (dir == MV_LEFT)
1118         graphic += (4 - phase4) % 4;
1119       else if (dir == MV_RIGHT)
1120         graphic += phase4;
1121       else
1122         graphic += phase2 * 2;
1123     }
1124     else if (element != EL_SP_INFOTRON)
1125       graphic += phase2 * (element == EL_FELSBROCKEN ? 2 : 1);
1126     */
1127
1128   }
1129   else if (element == EL_SIEB_LEER || element == EL_SIEB2_LEER ||
1130            element == EL_SIEB_VOLL || element == EL_SIEB2_VOLL)
1131   {
1132     graphic += 3 + getGraphicAnimationPhase(4, 4, ANIM_REVERSE);
1133   }
1134   else if (IS_AMOEBOID(element))
1135   {
1136     graphic = (element == EL_AMOEBE_TOT ? GFX_AMOEBE_TOT : GFX_AMOEBE_LEBT);
1137     graphic += (x + 2 * y + 4) % 4;
1138   }
1139   else if (element == EL_MAUER_LEBT)
1140   {
1141     boolean links_massiv = FALSE, rechts_massiv = FALSE;
1142
1143     if (!IN_LEV_FIELD(ux-1, uy) || IS_MAUER(Feld[ux-1][uy]))
1144       links_massiv = TRUE;
1145     if (!IN_LEV_FIELD(ux+1, uy) || IS_MAUER(Feld[ux+1][uy]))
1146       rechts_massiv = TRUE;
1147
1148     if (links_massiv && rechts_massiv)
1149       graphic = GFX_MAUERWERK;
1150     else if (links_massiv)
1151       graphic = GFX_MAUER_R;
1152     else if (rechts_massiv)
1153       graphic = GFX_MAUER_L;
1154   }
1155
1156   if (dx || dy)
1157     DrawGraphicShifted(x, y, dx, dy, graphic, cut_mode, mask_mode);
1158   else if (mask_mode == USE_MASKING)
1159     DrawGraphicThruMask(x, y, graphic);
1160   else
1161     DrawGraphic(x, y, graphic);
1162 }
1163
1164 void DrawLevelElementExt(int x, int y, int dx, int dy, int element,
1165                          int cut_mode, int mask_mode)
1166 {
1167   if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1168     DrawScreenElementExt(SCREENX(x), SCREENY(y), dx, dy, element,
1169                          cut_mode, mask_mode);
1170 }
1171
1172 void DrawScreenElementShifted(int x, int y, int dx, int dy, int element,
1173                               int cut_mode)
1174 {
1175   DrawScreenElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1176 }
1177
1178 void DrawLevelElementShifted(int x, int y, int dx, int dy, int element,
1179                              int cut_mode)
1180 {
1181   DrawLevelElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1182 }
1183
1184 void DrawScreenElementThruMask(int x, int y, int element)
1185 {
1186   DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1187 }
1188
1189 void DrawLevelElementThruMask(int x, int y, int element)
1190 {
1191   DrawLevelElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1192 }
1193
1194 void DrawLevelFieldThruMask(int x, int y)
1195 {
1196   DrawLevelElementExt(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
1197 }
1198
1199 void ErdreichAnbroeckeln(int x, int y)
1200 {
1201   int i, width, height, cx,cy;
1202   int ux = LEVELX(x), uy = LEVELY(y);
1203   int element, graphic;
1204   int snip = 4;
1205   static int xy[4][2] =
1206   {
1207     { 0, -1 },
1208     { -1, 0 },
1209     { +1, 0 },
1210     { 0, +1 }
1211   };
1212
1213   if (!IN_LEV_FIELD(ux, uy))
1214     return;
1215
1216   element = Feld[ux][uy];
1217
1218   if (element == EL_ERDREICH)
1219   {
1220     if (!IN_SCR_FIELD(x, y))
1221       return;
1222
1223     graphic = GFX_ERDENRAND;
1224
1225     for(i=0; i<4; i++)
1226     {
1227       int uxx, uyy;
1228
1229       uxx = ux + xy[i][0];
1230       uyy = uy + xy[i][1];
1231       if (!IN_LEV_FIELD(uxx, uyy))
1232         element = EL_BETON;
1233       else
1234         element = Feld[uxx][uyy];
1235
1236       if (element == EL_ERDREICH)
1237         continue;
1238
1239       if (i == 1 || i == 2)
1240       {
1241         width = snip;
1242         height = TILEY;
1243         cx = (i == 2 ? TILEX - snip : 0);
1244         cy = 0;
1245       }
1246       else
1247       {
1248         width = TILEX;
1249         height = snip;
1250         cx = 0;
1251         cy = (i == 3 ? TILEY - snip : 0);
1252       }
1253
1254       XCopyArea(display, pix[PIX_BACK], drawto_field, gc,
1255                 SX + (graphic % GFX_PER_LINE) * TILEX + cx,
1256                 SY + (graphic / GFX_PER_LINE) * TILEY + cy,
1257                 width, height, FX + x * TILEX + cx, FY + y * TILEY + cy);
1258     }
1259
1260     MarkTileDirty(x, y);
1261   }
1262   else
1263   {
1264     graphic = GFX_ERDENRAND;
1265
1266     for(i=0; i<4; i++)
1267     {
1268       int xx, yy, uxx, uyy;
1269
1270       xx = x + xy[i][0];
1271       yy = y + xy[i][1];
1272       uxx = ux + xy[i][0];
1273       uyy = uy + xy[i][1];
1274
1275       if (!IN_LEV_FIELD(uxx, uyy) || Feld[uxx][uyy] != EL_ERDREICH ||
1276           !IN_SCR_FIELD(xx, yy))
1277         continue;
1278
1279       if (i == 1 || i == 2)
1280       {
1281         width = snip;
1282         height = TILEY;
1283         cx = (i == 1 ? TILEX - snip : 0);
1284         cy = 0;
1285       }
1286       else
1287       {
1288         width = TILEX;
1289         height = snip;
1290         cx = 0;
1291         cy = (i==0 ? TILEY-snip : 0);
1292       }
1293
1294       XCopyArea(display, pix[PIX_BACK], drawto_field, gc,
1295                 SX + (graphic % GFX_PER_LINE) * TILEX + cx,
1296                 SY + (graphic / GFX_PER_LINE) * TILEY + cy,
1297                 width, height, FX + xx * TILEX + cx, FY + yy * TILEY + cy);
1298
1299       MarkTileDirty(xx, yy);
1300     }
1301   }
1302 }
1303
1304 void DrawScreenElement(int x, int y, int element)
1305 {
1306   DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
1307   ErdreichAnbroeckeln(x, y);
1308 }
1309
1310 void DrawLevelElement(int x, int y, int element)
1311 {
1312   if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1313     DrawScreenElement(SCREENX(x), SCREENY(y), element);
1314 }
1315
1316 void DrawScreenField(int x, int y)
1317 {
1318   int ux = LEVELX(x), uy = LEVELY(y);
1319   int element;
1320
1321   if (!IN_LEV_FIELD(ux, uy))
1322   {
1323     if (ux < -1 || ux > lev_fieldx || uy < -1 || uy > lev_fieldy)
1324       element = EL_LEERRAUM;
1325     else
1326       element = BorderElement;
1327
1328     DrawScreenElement(x, y, element);
1329     return;
1330   }
1331
1332   element = Feld[ux][uy];
1333
1334   if (IS_MOVING(ux, uy))
1335   {
1336     int horiz_move = (MovDir[ux][uy] == MV_LEFT || MovDir[ux][uy] == MV_RIGHT);
1337     boolean cut_mode = NO_CUTTING;
1338
1339     if (Store[ux][uy] == EL_MORAST_LEER ||
1340         Store[ux][uy] == EL_SIEB_LEER ||
1341         Store[ux][uy] == EL_SIEB2_LEER ||
1342         Store[ux][uy] == EL_AMOEBE_NASS)
1343       cut_mode = CUT_ABOVE;
1344     else if (Store[ux][uy] == EL_MORAST_VOLL ||
1345              Store[ux][uy] == EL_SIEB_VOLL ||
1346              Store[ux][uy] == EL_SIEB2_VOLL)
1347       cut_mode = CUT_BELOW;
1348
1349     if (cut_mode == CUT_ABOVE)
1350       DrawScreenElementShifted(x, y, 0, 0, Store[ux][uy], NO_CUTTING);
1351     else
1352       DrawScreenElement(x, y, EL_LEERRAUM);
1353
1354     if (horiz_move)
1355       DrawScreenElementShifted(x, y, MovPos[ux][uy], 0, element, NO_CUTTING);
1356     else
1357       DrawScreenElementShifted(x, y, 0, MovPos[ux][uy], element, cut_mode);
1358
1359     if (Store[ux][uy] == EL_SALZSAEURE)
1360       DrawLevelElementThruMask(ux, uy + 1, EL_SALZSAEURE);
1361   }
1362   else if (IS_BLOCKED(ux, uy))
1363   {
1364     int oldx, oldy;
1365     int sx, sy;
1366     int horiz_move;
1367     boolean cut_mode = NO_CUTTING;
1368
1369     Blocked2Moving(ux, uy, &oldx, &oldy);
1370     sx = SCREENX(oldx);
1371     sy = SCREENY(oldy);
1372     horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
1373                   MovDir[oldx][oldy] == MV_RIGHT);
1374
1375     if (Store[oldx][oldy] == EL_MORAST_LEER ||
1376         Store[oldx][oldy] == EL_SIEB_LEER ||
1377         Store[oldx][oldy] == EL_SIEB2_LEER ||
1378         Store[oldx][oldy] == EL_AMOEBE_NASS)
1379       cut_mode = CUT_ABOVE;
1380
1381     DrawScreenElement(x, y, EL_LEERRAUM);
1382     element = Feld[oldx][oldy];
1383
1384     if (horiz_move)
1385       DrawScreenElementShifted(sx,sy, MovPos[oldx][oldy],0,element,NO_CUTTING);
1386     else
1387       DrawScreenElementShifted(sx,sy, 0,MovPos[oldx][oldy],element,cut_mode);
1388   }
1389   else if (IS_DRAWABLE(element))
1390     DrawScreenElement(x, y, element);
1391   else
1392     DrawScreenElement(x, y, EL_LEERRAUM);
1393 }
1394
1395 void DrawLevelField(int x, int y)
1396 {
1397   if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1398     DrawScreenField(SCREENX(x), SCREENY(y));
1399   else if (IS_MOVING(x, y))
1400   {
1401     int newx,newy;
1402
1403     Moving2Blocked(x, y, &newx, &newy);
1404     if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
1405       DrawScreenField(SCREENX(newx), SCREENY(newy));
1406   }
1407   else if (IS_BLOCKED(x, y))
1408   {
1409     int oldx, oldy;
1410
1411     Blocked2Moving(x, y, &oldx, &oldy);
1412     if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
1413       DrawScreenField(SCREENX(oldx), SCREENY(oldy));
1414   }
1415 }
1416
1417 void DrawMiniElement(int x, int y, int element)
1418 {
1419   int graphic;
1420
1421   if (!element)
1422   {
1423     DrawMiniGraphic(x, y, -1);
1424     return;
1425   }
1426
1427   graphic = el2gfx(element);
1428   DrawMiniGraphic(x, y, graphic);
1429 }
1430
1431 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
1432 {
1433   int x = sx + scroll_x, y = sy + scroll_y;
1434
1435   if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
1436     DrawMiniElement(sx, sy, EL_LEERRAUM);
1437   else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
1438     DrawMiniElement(sx, sy, Feld[x][y]);
1439   else
1440   {
1441     int steel_type, steel_position;
1442     int border[6][2] =
1443     {
1444       { GFX_VSTEEL_UPPER_LEFT,  GFX_ISTEEL_UPPER_LEFT  },
1445       { GFX_VSTEEL_UPPER_RIGHT, GFX_ISTEEL_UPPER_RIGHT },
1446       { GFX_VSTEEL_LOWER_LEFT,  GFX_ISTEEL_LOWER_LEFT  },
1447       { GFX_VSTEEL_LOWER_RIGHT, GFX_ISTEEL_LOWER_RIGHT },
1448       { GFX_VSTEEL_VERTICAL,    GFX_ISTEEL_VERTICAL    },
1449       { GFX_VSTEEL_HORIZONTAL,  GFX_ISTEEL_HORIZONTAL  }
1450     };
1451
1452     steel_type = (BorderElement == EL_BETON ? 0 : 1);
1453     steel_position = (x == -1 && y == -1                        ? 0 :
1454                       x == lev_fieldx && y == -1                ? 1 :
1455                       x == -1 && y == lev_fieldy                ? 2 :
1456                       x == lev_fieldx && y == lev_fieldy        ? 3 :
1457                       x == -1 || x == lev_fieldx                ? 4 :
1458                       y == -1 || y == lev_fieldy                ? 5 : -1);
1459
1460     if (steel_position != -1)
1461       DrawMiniGraphic(sx, sy, border[steel_position][steel_type]);
1462   }
1463 }
1464
1465 void DrawMicroElement(int xpos, int ypos, int element)
1466 {
1467   int graphic;
1468
1469   if (element == EL_LEERRAUM)
1470     return;
1471
1472   graphic = el2gfx(element);
1473
1474   if (graphic >= GFX_START_ROCKSMORE && graphic <= GFX_END_ROCKSMORE)
1475   {
1476     graphic -= GFX_START_ROCKSMORE;
1477     graphic -= ((graphic / MORE_PER_LINE) * MORE_PER_LINE) / 2;
1478     XCopyArea(display, pix[PIX_MORE], drawto, gc,
1479               MICRO_MORE_STARTX + (graphic % MICRO_MORE_PER_LINE) *MICRO_TILEX,
1480               MICRO_MORE_STARTY + (graphic / MICRO_MORE_PER_LINE) *MICRO_TILEY,
1481               MICRO_TILEX, MICRO_TILEY, xpos, ypos);
1482   }
1483   else
1484     XCopyArea(display, pix[PIX_BACK], drawto, gc,
1485               MICRO_GFX_STARTX + (graphic % MICRO_GFX_PER_LINE) * MICRO_TILEX,
1486               MICRO_GFX_STARTY + (graphic / MICRO_GFX_PER_LINE) * MICRO_TILEY,
1487               MICRO_TILEX, MICRO_TILEY, xpos, ypos);
1488 }
1489
1490 void DrawLevel()
1491 {
1492   int x,y;
1493
1494   ClearWindow();
1495
1496   for(x=BX1; x<=BX2; x++)
1497     for(y=BY1; y<=BY2; y++)
1498       DrawScreenField(x, y);
1499
1500   redraw_mask |= REDRAW_FIELD;
1501 }
1502
1503 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
1504 {
1505   int x,y;
1506
1507   for(x=0; x<size_x; x++)
1508     for(y=0; y<size_y; y++)
1509       DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
1510
1511   redraw_mask |= REDRAW_FIELD;
1512 }
1513
1514 static void DrawMicroLevelExt(int xpos, int ypos, int from_x, int from_y)
1515 {
1516   int x, y;
1517
1518   XFillRectangle(display, drawto, gc,
1519                  xpos, ypos, MICROLEV_XSIZE, MICROLEV_YSIZE);
1520
1521   if (lev_fieldx < STD_LEV_FIELDX)
1522     xpos += (STD_LEV_FIELDX - lev_fieldx) / 2 * MICRO_TILEX;
1523   if (lev_fieldy < STD_LEV_FIELDY)
1524     ypos += (STD_LEV_FIELDY - lev_fieldy) / 2 * MICRO_TILEY;
1525
1526   xpos += MICRO_TILEX;
1527   ypos += MICRO_TILEY;
1528
1529   for(x=-1; x<=STD_LEV_FIELDX; x++)
1530   {
1531     for(y=-1; y<=STD_LEV_FIELDY; y++)
1532     {
1533       int lx = from_x + x, ly = from_y + y;
1534
1535       if (lx >= 0 && lx < lev_fieldx && ly >= 0 && ly < lev_fieldy)
1536         DrawMicroElement(xpos + x * MICRO_TILEX, ypos + y * MICRO_TILEY,
1537                          Ur[lx][ly]);
1538       else if (lx >= -1 && lx < lev_fieldx+1 && ly >= -1 && ly < lev_fieldy+1)
1539         DrawMicroElement(xpos + x * MICRO_TILEX, ypos + y * MICRO_TILEY,
1540                          BorderElement);
1541     }
1542   }
1543
1544   redraw_mask |= REDRAW_MICROLEVEL;
1545 }
1546
1547 static void DrawMicroLevelLabelExt(int mode)
1548 {
1549   char label_text[100];
1550
1551   XFillRectangle(display, drawto,gc,
1552                  SX, MICROLABEL_YPOS, SXSIZE, FONT4_YSIZE);
1553
1554   strcpy(label_text, (mode == 1 ? level.name :
1555                       mode == 2 ? "created by" :
1556                       mode == 3 ? level.author : ""));
1557
1558   if (strlen(label_text) > 0)
1559   {
1560     int size, lxpos, lypos;
1561
1562     label_text[SXSIZE / FONT4_XSIZE] = '\0';
1563
1564     size = strlen(label_text);
1565     lxpos = SX + (SXSIZE - size * FONT4_XSIZE) / 2;
1566     lypos = MICROLABEL_YPOS;
1567
1568     DrawText(lxpos, lypos, label_text, FS_SMALL, FC_SPECIAL2);
1569   }
1570
1571   redraw_mask |= REDRAW_MICROLEVEL;
1572 }
1573
1574 void DrawMicroLevel(int xpos, int ypos, boolean restart)
1575 {
1576   static unsigned long scroll_delay = 0;
1577   static unsigned long label_delay = 0;
1578   static int from_x, from_y, scroll_direction;
1579   static int label_state, label_counter;
1580
1581   if (restart)
1582   {
1583     from_x = from_y = 0;
1584     scroll_direction = MV_RIGHT;
1585     label_state = 1;
1586     label_counter = 0;
1587
1588     DrawMicroLevelExt(xpos, ypos, from_x, from_y);
1589     DrawMicroLevelLabelExt(label_state);
1590
1591     /* initialize delay counters */
1592     DelayReached(&scroll_delay, 0);
1593     DelayReached(&label_delay, 0);
1594
1595     return;
1596   }
1597
1598   /* scroll micro level, if needed */
1599   if ((lev_fieldx > STD_LEV_FIELDX || lev_fieldy > STD_LEV_FIELDY) &&
1600       DelayReached(&scroll_delay, MICROLEVEL_SCROLL_DELAY))
1601   {
1602     switch (scroll_direction)
1603     {
1604       case MV_LEFT:
1605         if (from_x > 0)
1606           from_x--;
1607         else
1608           scroll_direction = MV_UP;
1609         break;
1610
1611       case MV_RIGHT:
1612         if (from_x < lev_fieldx - STD_LEV_FIELDX)
1613           from_x++;
1614         else
1615           scroll_direction = MV_DOWN;
1616         break;
1617
1618       case MV_UP:
1619         if (from_y > 0)
1620           from_y--;
1621         else
1622           scroll_direction = MV_RIGHT;
1623         break;
1624
1625       case MV_DOWN:
1626         if (from_y < lev_fieldy - STD_LEV_FIELDY)
1627           from_y++;
1628         else
1629           scroll_direction = MV_LEFT;
1630         break;
1631
1632       default:
1633         break;
1634     }
1635
1636     DrawMicroLevelExt(xpos, ypos, from_x, from_y);
1637   }
1638
1639   /* redraw micro level label, if needed */
1640   if (strcmp(level.name, NAMELESS_LEVEL_NAME) != 0 &&
1641       strcmp(level.author, ANONYMOUS_NAME) != 0 &&
1642       strcmp(level.author, leveldir[leveldir_nr].name) != 0 &&
1643       DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
1644   {
1645     label_counter = (label_counter + 1) % 23;
1646     label_state = (label_counter >= 0 && label_counter <= 7 ? 1 :
1647                    label_counter >= 9 && label_counter <= 12 ? 2 :
1648                    label_counter >= 14 && label_counter <= 21 ? 3 : 0);
1649     DrawMicroLevelLabelExt(label_state);
1650   }
1651 }
1652
1653 int REQ_in_range(int x, int y)
1654 {
1655   if (y > DY+249 && y < DY+278)
1656   {
1657     if (x > DX+1 && x < DX+48)
1658       return 1;
1659     else if (x > DX+51 && x < DX+98) 
1660       return 2;
1661   }
1662   return 0;
1663 }
1664
1665 boolean Request(char *text, unsigned int req_state)
1666 {
1667   int mx, my, ty, result = -1;
1668   unsigned int old_door_state;
1669
1670 #ifndef MSDOS
1671   /* pause network game while waiting for request to answer */
1672   if (options.network &&
1673       game_status == PLAYING &&
1674       req_state & REQUEST_WAIT_FOR)
1675     SendToServer_PausePlaying();
1676 #endif
1677
1678   old_door_state = GetDoorState();
1679
1680   UnmapAllGadgets();
1681
1682   CloseDoor(DOOR_CLOSE_1);
1683
1684   /* save old door content */
1685   XCopyArea(display, pix[PIX_DB_DOOR], pix[PIX_DB_DOOR], gc,
1686             DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
1687             DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
1688
1689   /* clear door drawing field */
1690   XFillRectangle(display, drawto, gc, DX, DY, DXSIZE, DYSIZE);
1691
1692   /* write text for request */
1693   for(ty=0; ty<13; ty++)
1694   {
1695     int tx, tl, tc;
1696     char txt[256];
1697
1698     if (!*text)
1699       break;
1700
1701     for(tl=0,tx=0; tx<7; tl++,tx++)
1702     {
1703       tc = *(text + tx);
1704       if (!tc || tc == 32)
1705         break;
1706     }
1707     if (!tl)
1708     { 
1709       text++; 
1710       ty--; 
1711       continue; 
1712     }
1713     sprintf(txt, text); 
1714     txt[tl] = 0;
1715     DrawTextExt(drawto, gc,
1716                 DX + 51 - (tl * 14)/2, DY + 8 + ty * 16,
1717                 txt, FS_SMALL, FC_YELLOW);
1718     text += tl + (tc == 32 ? 1 : 0);
1719   }
1720
1721   if (req_state & REQ_ASK)
1722   {
1723     MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
1724     MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
1725   }
1726   else if (req_state & REQ_CONFIRM)
1727   {
1728     MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
1729   }
1730   else if (req_state & REQ_PLAYER)
1731   {
1732     MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
1733     MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
1734     MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
1735     MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
1736   }
1737
1738   /* copy request gadgets to door backbuffer */
1739   XCopyArea(display, drawto, pix[PIX_DB_DOOR], gc,
1740             DX, DY, DXSIZE, DYSIZE,
1741             DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
1742
1743   OpenDoor(DOOR_OPEN_1);
1744
1745 #if 0
1746   ClearEventQueue();
1747 #endif
1748
1749   if (!(req_state & REQUEST_WAIT_FOR))
1750     return(FALSE);
1751
1752   if (game_status != MAINMENU)
1753     InitAnimation();
1754
1755   button_status = MB_RELEASED;
1756
1757   request_gadget_id = -1;
1758
1759   while(result < 0)
1760   {
1761     if (XPending(display))
1762     {
1763       XEvent event;
1764
1765       XNextEvent(display, &event);
1766
1767       switch(event.type)
1768       {
1769         case ButtonPress:
1770         case ButtonRelease:
1771         case MotionNotify:
1772         {
1773           if (event.type == MotionNotify)
1774           {
1775             Window root, child;
1776             int root_x, root_y;
1777             int win_x, win_y;
1778             unsigned int mask;
1779
1780             if (!XQueryPointer(display, window, &root, &child,
1781                                &root_x, &root_y, &win_x, &win_y, &mask))
1782               continue;
1783
1784             if (!button_status)
1785               continue;
1786
1787             motion_status = TRUE;
1788             mx = ((XMotionEvent *) &event)->x;
1789             my = ((XMotionEvent *) &event)->y;
1790           }
1791           else
1792           {
1793             motion_status = FALSE;
1794             mx = ((XButtonEvent *) &event)->x;
1795             my = ((XButtonEvent *) &event)->y;
1796             if (event.type==ButtonPress)
1797               button_status = ((XButtonEvent *) &event)->button;
1798             else
1799               button_status = MB_RELEASED;
1800           }
1801
1802           /* this sets 'request_gadget_id' */
1803           HandleGadgets(mx, my, button_status);
1804
1805           switch(request_gadget_id)
1806           {
1807             case TOOL_CTRL_ID_YES:
1808               result = TRUE;
1809               break;
1810             case TOOL_CTRL_ID_NO:
1811               result = FALSE;
1812               break;
1813             case TOOL_CTRL_ID_CONFIRM:
1814               result = TRUE | FALSE;
1815               break;
1816
1817             case TOOL_CTRL_ID_PLAYER_1:
1818               result = 1;
1819               break;
1820             case TOOL_CTRL_ID_PLAYER_2:
1821               result = 2;
1822               break;
1823             case TOOL_CTRL_ID_PLAYER_3:
1824               result = 3;
1825               break;
1826             case TOOL_CTRL_ID_PLAYER_4:
1827               result = 4;
1828               break;
1829
1830             default:
1831               break;
1832           }
1833
1834           break;
1835         }
1836
1837         case KeyPress:
1838           switch(XLookupKeysym((XKeyEvent *)&event,
1839                                ((XKeyEvent *)&event)->state))
1840           {
1841             case XK_Return:
1842               result = 1;
1843               break;
1844
1845             case XK_Escape:
1846               result = 0;
1847               break;
1848
1849             default:
1850               break;
1851           }
1852           if (req_state & REQ_PLAYER)
1853             result = 0;
1854           break;
1855
1856         case KeyRelease:
1857           key_joystick_mapping = 0;
1858           break;
1859
1860         default:
1861           HandleOtherEvents(&event);
1862           break;
1863       }
1864     }
1865     else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
1866     {
1867       int joy = AnyJoystick();
1868
1869       if (joy & JOY_BUTTON_1)
1870         result = 1;
1871       else if (joy & JOY_BUTTON_2)
1872         result = 0;
1873     }
1874
1875     DoAnimation();
1876
1877     /* don't eat all CPU time */
1878     Delay(10);
1879   }
1880
1881   if (game_status != MAINMENU)
1882     StopAnimation();
1883
1884   UnmapToolButtons();
1885
1886   if (!(req_state & REQ_STAY_OPEN))
1887   {
1888     CloseDoor(DOOR_CLOSE_1);
1889
1890     if (!(req_state & REQ_STAY_CLOSED) && (old_door_state & DOOR_OPEN_1))
1891     {
1892       XCopyArea(display,pix[PIX_DB_DOOR],pix[PIX_DB_DOOR],gc,
1893                 DOOR_GFX_PAGEX2,DOOR_GFX_PAGEY1, DXSIZE,DYSIZE,
1894                 DOOR_GFX_PAGEX1,DOOR_GFX_PAGEY1);
1895       OpenDoor(DOOR_OPEN_1);
1896     }
1897   }
1898
1899   RemapAllGadgets();
1900
1901 #ifndef MSDOS
1902   /* continue network game after request */
1903   if (options.network &&
1904       game_status == PLAYING &&
1905       req_state & REQUEST_WAIT_FOR)
1906     SendToServer_ContinuePlaying();
1907 #endif
1908
1909   return(result);
1910 }
1911
1912 unsigned int OpenDoor(unsigned int door_state)
1913 {
1914   unsigned int new_door_state;
1915
1916   if (door_state & DOOR_COPY_BACK)
1917   {
1918     XCopyArea(display, pix[PIX_DB_DOOR], pix[PIX_DB_DOOR], gc,
1919               DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE + VYSIZE,
1920               DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
1921     door_state &= ~DOOR_COPY_BACK;
1922   }
1923
1924   new_door_state = MoveDoor(door_state);
1925
1926   return(new_door_state);
1927 }
1928
1929 unsigned int CloseDoor(unsigned int door_state)
1930 {
1931   unsigned int new_door_state;
1932
1933   XCopyArea(display, backbuffer, pix[PIX_DB_DOOR], gc,
1934             DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
1935   XCopyArea(display, backbuffer, pix[PIX_DB_DOOR], gc,
1936             VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
1937
1938   new_door_state = MoveDoor(door_state);
1939
1940   return(new_door_state);
1941 }
1942
1943 unsigned int GetDoorState()
1944 {
1945   return(MoveDoor(DOOR_GET_STATE));
1946 }
1947
1948 unsigned int MoveDoor(unsigned int door_state)
1949 {
1950   static int door1 = DOOR_OPEN_1;
1951   static int door2 = DOOR_CLOSE_2;
1952   static unsigned long door_delay = 0;
1953   int x, start, stepsize = 2;
1954   unsigned long door_delay_value = stepsize * 5;
1955
1956   if (door_state == DOOR_GET_STATE)
1957     return(door1 | door2);
1958
1959   if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
1960     door_state &= ~DOOR_OPEN_1;
1961   else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
1962     door_state &= ~DOOR_CLOSE_1;
1963   if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
1964     door_state &= ~DOOR_OPEN_2;
1965   else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
1966     door_state &= ~DOOR_CLOSE_2;
1967
1968   if (setup.quick_doors)
1969   {
1970     stepsize = 20;
1971     door_delay_value = 0;
1972     StopSound(SND_OEFFNEN);
1973   }
1974
1975   if (door_state & DOOR_ACTION)
1976   {
1977     if (!(door_state & DOOR_NO_DELAY))
1978       PlaySoundStereo(SND_OEFFNEN, PSND_MAX_RIGHT);
1979
1980     start = ((door_state & DOOR_NO_DELAY) ? DXSIZE : 0);
1981
1982     for(x=start; x<=DXSIZE; x+=stepsize)
1983     {
1984       WaitUntilDelayReached(&door_delay, door_delay_value);
1985
1986       if (door_state & DOOR_ACTION_1)
1987       {
1988         int i = (door_state & DOOR_OPEN_1 ? DXSIZE-x : x);
1989         int j = (DXSIZE - i) / 3;
1990
1991         XCopyArea(display, pix[PIX_DB_DOOR], drawto, gc,
1992                   DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + i/2,
1993                   DXSIZE,DYSIZE - i/2, DX, DY);
1994
1995         XFillRectangle(display, drawto, gc, DX, DY + DYSIZE - i/2, DXSIZE,i/2);
1996
1997         XSetClipOrigin(display, clip_gc[PIX_DOOR],
1998                        DX - i, (DY + j) - DOOR_GFX_PAGEY1);
1999         XCopyArea(display, pix[PIX_DOOR], drawto,clip_gc[PIX_DOOR],
2000                   DXSIZE, DOOR_GFX_PAGEY1, i, 77, DX + DXSIZE - i, DY + j);
2001         XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
2002                   DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63, DX + DXSIZE - i,
2003                   DY + 140 + j);
2004         XSetClipOrigin(display, clip_gc[PIX_DOOR],
2005                        DX - DXSIZE + i, DY - (DOOR_GFX_PAGEY1 + j));
2006         XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
2007                   DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j, DX, DY);
2008         XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
2009                   DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63, DX, DY + 140 - j);
2010
2011         XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
2012                   DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
2013                   DX, DY + 77 - j);
2014         XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
2015                   DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
2016                   DX, DY + 203 - j);
2017         XSetClipOrigin(display, clip_gc[PIX_DOOR],
2018                        DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2019         XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
2020                   DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
2021                   DX + DXSIZE - i, DY + 77 + j);
2022         XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
2023                   DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
2024                   DX + DXSIZE - i, DY + 203 + j);
2025
2026         redraw_mask |= REDRAW_DOOR_1;
2027       }
2028
2029       if (door_state & DOOR_ACTION_2)
2030       {
2031         int i = (door_state & DOOR_OPEN_2 ? VXSIZE - x : x);
2032         int j = (VXSIZE - i) / 3;
2033
2034         XCopyArea(display, pix[PIX_DB_DOOR], drawto, gc,
2035                   DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + i/2,
2036                   VXSIZE, VYSIZE - i/2, VX, VY);
2037
2038         XFillRectangle(display, drawto, gc, VX, VY + VYSIZE-i/2, VXSIZE, i/2);
2039
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, i, VYSIZE / 2, VX + VXSIZE-i, VY+j);
2044         XSetClipOrigin(display, clip_gc[PIX_DOOR],
2045                        VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
2046         XCopyArea(display, pix[PIX_DOOR], drawto,clip_gc[PIX_DOOR],
2047                   VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j, VX, VY);
2048
2049         XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
2050                   VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2, i, VYSIZE / 2,
2051                   VX, VY + VYSIZE / 2 - j);
2052         XSetClipOrigin(display, clip_gc[PIX_DOOR],
2053                        VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2054         XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
2055                   VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2, i, VYSIZE / 2 - j,
2056                   VX + VXSIZE - i, VY + VYSIZE / 2 + j);
2057
2058         redraw_mask |= REDRAW_DOOR_2;
2059       }
2060
2061       BackToFront();
2062
2063       if (game_status == MAINMENU)
2064         DoAnimation();
2065     }
2066   }
2067
2068   if (setup.quick_doors)
2069     StopSound(SND_OEFFNEN);
2070
2071   if (door_state & DOOR_ACTION_1)
2072     door1 = door_state & DOOR_ACTION_1;
2073   if (door_state & DOOR_ACTION_2)
2074     door2 = door_state & DOOR_ACTION_2;
2075
2076   return (door1 | door2);
2077 }
2078
2079 void DrawSpecialEditorDoor()
2080 {
2081   /* draw bigger toolbox window */
2082   XCopyArea(display, pix[PIX_DOOR], drawto, gc,
2083             DOOR_GFX_PAGEX7, 0, 108, 56, EX - 4, EY - 12);
2084
2085   redraw_mask |= REDRAW_ALL;
2086 }
2087
2088 void UndrawSpecialEditorDoor()
2089 {
2090   /* draw normal tape recorder window */
2091   XCopyArea(display, pix[PIX_BACK], drawto, gc,
2092             562, 344, 108, 56, EX - 4, EY - 12);
2093
2094   redraw_mask |= REDRAW_ALL;
2095 }
2096
2097 int ReadPixel(Drawable d, int x, int y)
2098 {
2099   XImage *pixel_image;
2100   unsigned long pixel_value;
2101
2102   pixel_image = XGetImage(display, d, x, y, 1, 1, AllPlanes, ZPixmap);
2103   pixel_value = XGetPixel(pixel_image, 0, 0);
2104
2105   XDestroyImage(pixel_image);
2106
2107   return pixel_value;
2108 }
2109
2110 /* ---------- new tool button stuff ---------------------------------------- */
2111
2112 /* graphic position values for tool buttons */
2113 #define TOOL_BUTTON_YES_XPOS            2
2114 #define TOOL_BUTTON_YES_YPOS            250
2115 #define TOOL_BUTTON_YES_GFX_YPOS        0
2116 #define TOOL_BUTTON_YES_XSIZE           46
2117 #define TOOL_BUTTON_YES_YSIZE           28
2118 #define TOOL_BUTTON_NO_XPOS             52
2119 #define TOOL_BUTTON_NO_YPOS             TOOL_BUTTON_YES_YPOS
2120 #define TOOL_BUTTON_NO_GFX_YPOS         TOOL_BUTTON_YES_GFX_YPOS
2121 #define TOOL_BUTTON_NO_XSIZE            TOOL_BUTTON_YES_XSIZE
2122 #define TOOL_BUTTON_NO_YSIZE            TOOL_BUTTON_YES_YSIZE
2123 #define TOOL_BUTTON_CONFIRM_XPOS        TOOL_BUTTON_YES_XPOS
2124 #define TOOL_BUTTON_CONFIRM_YPOS        TOOL_BUTTON_YES_YPOS
2125 #define TOOL_BUTTON_CONFIRM_GFX_YPOS    30
2126 #define TOOL_BUTTON_CONFIRM_XSIZE       96
2127 #define TOOL_BUTTON_CONFIRM_YSIZE       TOOL_BUTTON_YES_YSIZE
2128 #define TOOL_BUTTON_PLAYER_XSIZE        30
2129 #define TOOL_BUTTON_PLAYER_YSIZE        30
2130 #define TOOL_BUTTON_PLAYER_GFX_XPOS     5
2131 #define TOOL_BUTTON_PLAYER_GFX_YPOS     185
2132 #define TOOL_BUTTON_PLAYER_XPOS         (5 + TOOL_BUTTON_PLAYER_XSIZE / 2)
2133 #define TOOL_BUTTON_PLAYER_YPOS         (215 - TOOL_BUTTON_PLAYER_YSIZE / 2)
2134 #define TOOL_BUTTON_PLAYER1_XPOS        (TOOL_BUTTON_PLAYER_XPOS \
2135                                          + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2136 #define TOOL_BUTTON_PLAYER2_XPOS        (TOOL_BUTTON_PLAYER_XPOS \
2137                                          + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2138 #define TOOL_BUTTON_PLAYER3_XPOS        (TOOL_BUTTON_PLAYER_XPOS \
2139                                          + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2140 #define TOOL_BUTTON_PLAYER4_XPOS        (TOOL_BUTTON_PLAYER_XPOS \
2141                                          + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2142 #define TOOL_BUTTON_PLAYER1_YPOS        (TOOL_BUTTON_PLAYER_YPOS \
2143                                          + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2144 #define TOOL_BUTTON_PLAYER2_YPOS        (TOOL_BUTTON_PLAYER_YPOS \
2145                                          + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2146 #define TOOL_BUTTON_PLAYER3_YPOS        (TOOL_BUTTON_PLAYER_YPOS \
2147                                          + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2148 #define TOOL_BUTTON_PLAYER4_YPOS        (TOOL_BUTTON_PLAYER_YPOS \
2149                                          + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2150
2151 static struct
2152 {
2153   int xpos, ypos;
2154   int x, y;
2155   int width, height;
2156   int gadget_id;
2157   char *infotext;
2158 } toolbutton_info[NUM_TOOL_BUTTONS] =
2159 {
2160   {
2161     TOOL_BUTTON_YES_XPOS,       TOOL_BUTTON_YES_GFX_YPOS,
2162     TOOL_BUTTON_YES_XPOS,       TOOL_BUTTON_YES_YPOS,
2163     TOOL_BUTTON_YES_XSIZE,      TOOL_BUTTON_YES_YSIZE,
2164     TOOL_CTRL_ID_YES,
2165     "yes"
2166   },
2167   {
2168     TOOL_BUTTON_NO_XPOS,        TOOL_BUTTON_NO_GFX_YPOS,
2169     TOOL_BUTTON_NO_XPOS,        TOOL_BUTTON_NO_YPOS,
2170     TOOL_BUTTON_NO_XSIZE,       TOOL_BUTTON_NO_YSIZE,
2171     TOOL_CTRL_ID_NO,
2172     "no"
2173   },
2174   {
2175     TOOL_BUTTON_CONFIRM_XPOS,   TOOL_BUTTON_CONFIRM_GFX_YPOS,
2176     TOOL_BUTTON_CONFIRM_XPOS,   TOOL_BUTTON_CONFIRM_YPOS,
2177     TOOL_BUTTON_CONFIRM_XSIZE,  TOOL_BUTTON_CONFIRM_YSIZE,
2178     TOOL_CTRL_ID_CONFIRM,
2179     "confirm"
2180   },
2181   {
2182     TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2183     TOOL_BUTTON_PLAYER1_XPOS,   TOOL_BUTTON_PLAYER1_YPOS,
2184     TOOL_BUTTON_PLAYER_XSIZE,   TOOL_BUTTON_PLAYER_YSIZE,
2185     TOOL_CTRL_ID_PLAYER_1,
2186     "player 1"
2187   },
2188   {
2189     TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2190     TOOL_BUTTON_PLAYER2_XPOS,   TOOL_BUTTON_PLAYER2_YPOS,
2191     TOOL_BUTTON_PLAYER_XSIZE,   TOOL_BUTTON_PLAYER_YSIZE,
2192     TOOL_CTRL_ID_PLAYER_2,
2193     "player 2"
2194   },
2195   {
2196     TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2197     TOOL_BUTTON_PLAYER3_XPOS,   TOOL_BUTTON_PLAYER3_YPOS,
2198     TOOL_BUTTON_PLAYER_XSIZE,   TOOL_BUTTON_PLAYER_YSIZE,
2199     TOOL_CTRL_ID_PLAYER_3,
2200     "player 3"
2201   },
2202   {
2203     TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2204     TOOL_BUTTON_PLAYER4_XPOS,   TOOL_BUTTON_PLAYER4_YPOS,
2205     TOOL_BUTTON_PLAYER_XSIZE,   TOOL_BUTTON_PLAYER_YSIZE,
2206     TOOL_CTRL_ID_PLAYER_4,
2207     "player 4"
2208   }
2209 };
2210
2211 static void DoNotDisplayInfoText(void *ptr)
2212 {
2213   return;
2214 }
2215
2216 void CreateToolButtons()
2217 {
2218   int i;
2219
2220   for (i=0; i<NUM_TOOL_BUTTONS; i++)
2221   {
2222     Pixmap gd_pixmap = pix[PIX_DOOR];
2223     Pixmap deco_pixmap = None;
2224     int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
2225     struct GadgetInfo *gi;
2226     unsigned long event_mask;
2227     int gd_xoffset, gd_yoffset;
2228     int gd_x1, gd_x2, gd_y;
2229     int id = i;
2230
2231     event_mask = GD_EVENT_RELEASED;
2232
2233     gd_xoffset = toolbutton_info[i].xpos;
2234     gd_yoffset = toolbutton_info[i].ypos;
2235     gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
2236     gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
2237     gd_y = DOOR_GFX_PAGEY1 + gd_yoffset;
2238
2239     if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
2240     {
2241       getMiniGraphicSource(GFX_SPIELER1 + id - TOOL_CTRL_ID_PLAYER_1,
2242                            &deco_pixmap, &deco_x, &deco_y);
2243       deco_xpos = (toolbutton_info[i].width - MINI_TILEX) / 2;
2244       deco_ypos = (toolbutton_info[i].height - MINI_TILEY) / 2;
2245     }
2246
2247     gi = CreateGadget(GDI_CUSTOM_ID, id,
2248                       GDI_INFO_TEXT, toolbutton_info[i].infotext,
2249                       GDI_X, DX + toolbutton_info[i].x,
2250                       GDI_Y, DY + toolbutton_info[i].y,
2251                       GDI_WIDTH, toolbutton_info[i].width,
2252                       GDI_HEIGHT, toolbutton_info[i].height,
2253                       GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
2254                       GDI_STATE, GD_BUTTON_UNPRESSED,
2255                       GDI_DESIGN_UNPRESSED, gd_pixmap, gd_x1, gd_y,
2256                       GDI_DESIGN_PRESSED, gd_pixmap, gd_x2, gd_y,
2257                       GDI_DECORATION_DESIGN, deco_pixmap, deco_x, deco_y,
2258                       GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
2259                       GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
2260                       GDI_DECORATION_SHIFTING, 1, 1,
2261                       GDI_EVENT_MASK, event_mask,
2262                       GDI_CALLBACK_ACTION, HandleToolButtons,
2263                       GDI_CALLBACK_INFO, DoNotDisplayInfoText,
2264                       GDI_END);
2265
2266     if (gi == NULL)
2267       Error(ERR_EXIT, "cannot create gadget");
2268
2269     tool_gadget[id] = gi;
2270   }
2271 }
2272
2273 static void UnmapToolButtons()
2274 {
2275   int i;
2276
2277   for (i=0; i<NUM_TOOL_BUTTONS; i++)
2278     UnmapGadget(tool_gadget[i]);
2279 }
2280
2281 static void HandleToolButtons(struct GadgetInfo *gi)
2282 {
2283   request_gadget_id = gi->custom_id;
2284 }
2285
2286 int el2gfx(int element)
2287 {
2288   switch(element)
2289   {
2290     case EL_LEERRAUM:           return -1;
2291     case EL_ERDREICH:           return GFX_ERDREICH;
2292     case EL_MAUERWERK:          return GFX_MAUERWERK;
2293     case EL_FELSBODEN:          return GFX_FELSBODEN;
2294     case EL_FELSBROCKEN:        return GFX_FELSBROCKEN;
2295     case EL_SCHLUESSEL:         return GFX_SCHLUESSEL;
2296     case EL_EDELSTEIN:          return GFX_EDELSTEIN;
2297     case EL_AUSGANG_ZU:         return GFX_AUSGANG_ZU;
2298     case EL_AUSGANG_ACT:        return GFX_AUSGANG_ACT;
2299     case EL_AUSGANG_AUF:        return GFX_AUSGANG_AUF;
2300     case EL_SPIELFIGUR:         return GFX_SPIELFIGUR;
2301     case EL_SPIELER1:           return GFX_SPIELER1;
2302     case EL_SPIELER2:           return GFX_SPIELER2;
2303     case EL_SPIELER3:           return GFX_SPIELER3;
2304     case EL_SPIELER4:           return GFX_SPIELER4;
2305     case EL_KAEFER:             return GFX_KAEFER;
2306     case EL_KAEFER_R:           return GFX_KAEFER_R;
2307     case EL_KAEFER_O:           return GFX_KAEFER_O;
2308     case EL_KAEFER_L:           return GFX_KAEFER_L;
2309     case EL_KAEFER_U:           return GFX_KAEFER_U;
2310     case EL_FLIEGER:            return GFX_FLIEGER;
2311     case EL_FLIEGER_R:          return GFX_FLIEGER_R;
2312     case EL_FLIEGER_O:          return GFX_FLIEGER_O;
2313     case EL_FLIEGER_L:          return GFX_FLIEGER_L;
2314     case EL_FLIEGER_U:          return GFX_FLIEGER_U;
2315     case EL_BUTTERFLY:          return GFX_BUTTERFLY;
2316     case EL_BUTTERFLY_R:        return GFX_BUTTERFLY_R;
2317     case EL_BUTTERFLY_O:        return GFX_BUTTERFLY_O;
2318     case EL_BUTTERFLY_L:        return GFX_BUTTERFLY_L;
2319     case EL_BUTTERFLY_U:        return GFX_BUTTERFLY_U;
2320     case EL_FIREFLY:            return GFX_FIREFLY;
2321     case EL_FIREFLY_R:          return GFX_FIREFLY_R;
2322     case EL_FIREFLY_O:          return GFX_FIREFLY_O;
2323     case EL_FIREFLY_L:          return GFX_FIREFLY_L;
2324     case EL_FIREFLY_U:          return GFX_FIREFLY_U;
2325     case EL_MAMPFER:            return GFX_MAMPFER;
2326     case EL_ROBOT:              return GFX_ROBOT;
2327     case EL_BETON:              return GFX_BETON;
2328     case EL_DIAMANT:            return GFX_DIAMANT;
2329     case EL_MORAST_LEER:        return GFX_MORAST_LEER;
2330     case EL_MORAST_VOLL:        return GFX_MORAST_VOLL;
2331     case EL_TROPFEN:            return GFX_TROPFEN;
2332     case EL_BOMBE:              return GFX_BOMBE;
2333     case EL_SIEB_INAKTIV:       return GFX_SIEB_INAKTIV;
2334     case EL_SIEB_LEER:          return GFX_SIEB_LEER;
2335     case EL_SIEB_VOLL:          return GFX_SIEB_VOLL;
2336     case EL_SIEB_TOT:           return GFX_SIEB_TOT;
2337     case EL_SALZSAEURE:         return GFX_SALZSAEURE;
2338     case EL_AMOEBE_TOT:         return GFX_AMOEBE_TOT;
2339     case EL_AMOEBE_NASS:        return GFX_AMOEBE_NASS;
2340     case EL_AMOEBE_NORM:        return GFX_AMOEBE_NORM;
2341     case EL_AMOEBE_VOLL:        return GFX_AMOEBE_VOLL;
2342     case EL_AMOEBE_BD:          return GFX_AMOEBE_BD;
2343     case EL_AMOEBA2DIAM:        return GFX_AMOEBA2DIAM;
2344     case EL_KOKOSNUSS:          return GFX_KOKOSNUSS;
2345     case EL_LIFE:               return GFX_LIFE;
2346     case EL_LIFE_ASYNC:         return GFX_LIFE_ASYNC;
2347     case EL_DYNAMIT:            return GFX_DYNAMIT;
2348     case EL_BADEWANNE:          return GFX_BADEWANNE;
2349     case EL_BADEWANNE1:         return GFX_BADEWANNE1;
2350     case EL_BADEWANNE2:         return GFX_BADEWANNE2;
2351     case EL_BADEWANNE3:         return GFX_BADEWANNE3;
2352     case EL_BADEWANNE4:         return GFX_BADEWANNE4;
2353     case EL_BADEWANNE5:         return GFX_BADEWANNE5;
2354     case EL_ABLENK_AUS:         return GFX_ABLENK_AUS;
2355     case EL_ABLENK_EIN:         return GFX_ABLENK_EIN;
2356     case EL_SCHLUESSEL1:        return GFX_SCHLUESSEL1;
2357     case EL_SCHLUESSEL2:        return GFX_SCHLUESSEL2;
2358     case EL_SCHLUESSEL3:        return GFX_SCHLUESSEL3;
2359     case EL_SCHLUESSEL4:        return GFX_SCHLUESSEL4;
2360     case EL_PFORTE1:            return GFX_PFORTE1;
2361     case EL_PFORTE2:            return GFX_PFORTE2;
2362     case EL_PFORTE3:            return GFX_PFORTE3;
2363     case EL_PFORTE4:            return GFX_PFORTE4;
2364     case EL_PFORTE1X:           return GFX_PFORTE1X;
2365     case EL_PFORTE2X:           return GFX_PFORTE2X;
2366     case EL_PFORTE3X:           return GFX_PFORTE3X;
2367     case EL_PFORTE4X:           return GFX_PFORTE4X;
2368     case EL_DYNAMIT_AUS:        return GFX_DYNAMIT_AUS;
2369     case EL_PACMAN:             return GFX_PACMAN;
2370     case EL_PACMAN_R:           return GFX_PACMAN_R;
2371     case EL_PACMAN_O:           return GFX_PACMAN_O;
2372     case EL_PACMAN_L:           return GFX_PACMAN_L;
2373     case EL_PACMAN_U:           return GFX_PACMAN_U;
2374     case EL_UNSICHTBAR:         return GFX_UNSICHTBAR;
2375     case EL_ERZ_EDEL:           return GFX_ERZ_EDEL;
2376     case EL_ERZ_DIAM:           return GFX_ERZ_DIAM;
2377     case EL_BIRNE_AUS:          return GFX_BIRNE_AUS;
2378     case EL_BIRNE_EIN:          return GFX_BIRNE_EIN;
2379     case EL_ZEIT_VOLL:          return GFX_ZEIT_VOLL;
2380     case EL_ZEIT_LEER:          return GFX_ZEIT_LEER;
2381     case EL_MAUER_LEBT:         return GFX_MAUER_LEBT;
2382     case EL_MAUER_X:            return GFX_MAUER_X;
2383     case EL_MAUER_Y:            return GFX_MAUER_Y;
2384     case EL_MAUER_XY:           return GFX_MAUER_XY;
2385     case EL_EDELSTEIN_BD:       return GFX_EDELSTEIN_BD;
2386     case EL_EDELSTEIN_GELB:     return GFX_EDELSTEIN_GELB;
2387     case EL_EDELSTEIN_ROT:      return GFX_EDELSTEIN_ROT;
2388     case EL_EDELSTEIN_LILA:     return GFX_EDELSTEIN_LILA;
2389     case EL_ERZ_EDEL_BD:        return GFX_ERZ_EDEL_BD;
2390     case EL_ERZ_EDEL_GELB:      return GFX_ERZ_EDEL_GELB;
2391     case EL_ERZ_EDEL_ROT:       return GFX_ERZ_EDEL_ROT;
2392     case EL_ERZ_EDEL_LILA:      return GFX_ERZ_EDEL_LILA;
2393     case EL_MAMPFER2:           return GFX_MAMPFER2;
2394     case EL_SIEB2_INAKTIV:      return GFX_SIEB2_INAKTIV;
2395     case EL_SIEB2_LEER:         return GFX_SIEB2_LEER;
2396     case EL_SIEB2_VOLL:         return GFX_SIEB2_VOLL;
2397     case EL_SIEB2_TOT:          return GFX_SIEB2_TOT;
2398     case EL_DYNABOMB:           return GFX_DYNABOMB;
2399     case EL_DYNABOMB_NR:        return GFX_DYNABOMB_NR;
2400     case EL_DYNABOMB_SZ:        return GFX_DYNABOMB_SZ;
2401     case EL_DYNABOMB_XL:        return GFX_DYNABOMB_XL;
2402     case EL_SOKOBAN_OBJEKT:     return GFX_SOKOBAN_OBJEKT;
2403     case EL_SOKOBAN_FELD_LEER:  return GFX_SOKOBAN_FELD_LEER;
2404     case EL_SOKOBAN_FELD_VOLL:  return GFX_SOKOBAN_FELD_VOLL;
2405     case EL_MAULWURF:           return GFX_MAULWURF;
2406     case EL_PINGUIN:            return GFX_PINGUIN;
2407     case EL_SCHWEIN:            return GFX_SCHWEIN;
2408     case EL_DRACHE:             return GFX_DRACHE;
2409     case EL_SONDE:              return GFX_SONDE;
2410     case EL_PFEIL_L:            return GFX_PFEIL_L;
2411     case EL_PFEIL_R:            return GFX_PFEIL_R;
2412     case EL_PFEIL_O:            return GFX_PFEIL_O;
2413     case EL_PFEIL_U:            return GFX_PFEIL_U;
2414     case EL_SPEED_PILL:         return GFX_SPEED_PILL;
2415     case EL_SP_TERMINAL_ACTIVE: return GFX_SP_TERMINAL;
2416     case EL_SP_BUG_ACTIVE:      return GFX_SP_BUG_ACTIVE;
2417     case EL_SP_ZONK:            return GFX_SP_ZONK;
2418       /* ^^^^^^^^^^ non-standard position in supaplex graphic set! */
2419     case EL_INVISIBLE_STEEL:    return GFX_INVISIBLE_STEEL;
2420     case EL_BLACK_ORB:          return GFX_BLACK_ORB;
2421     case EL_EM_GATE_1:          return GFX_EM_GATE_1;
2422     case EL_EM_GATE_2:          return GFX_EM_GATE_2;
2423     case EL_EM_GATE_3:          return GFX_EM_GATE_3;
2424     case EL_EM_GATE_4:          return GFX_EM_GATE_4;
2425     case EL_EM_GATE_1X:         return GFX_EM_GATE_1X;
2426     case EL_EM_GATE_2X:         return GFX_EM_GATE_2X;
2427     case EL_EM_GATE_3X:         return GFX_EM_GATE_3X;
2428     case EL_EM_GATE_4X:         return GFX_EM_GATE_4X;
2429     case EL_EM_KEY_1_FILE:      return GFX_EM_KEY_1;
2430     case EL_EM_KEY_2_FILE:      return GFX_EM_KEY_2;
2431     case EL_EM_KEY_3_FILE:      return GFX_EM_KEY_3;
2432     case EL_EM_KEY_4_FILE:      return GFX_EM_KEY_4;
2433     case EL_EM_KEY_1:           return GFX_EM_KEY_1;
2434     case EL_EM_KEY_2:           return GFX_EM_KEY_2;
2435     case EL_EM_KEY_3:           return GFX_EM_KEY_3;
2436     case EL_EM_KEY_4:           return GFX_EM_KEY_4;
2437
2438     default:
2439     {
2440       if (IS_CHAR(element))
2441         return GFX_CHAR_START + (element - EL_CHAR_START);
2442       else if (element >= EL_SP_START && element <= EL_SP_END)
2443       {
2444         int nr_element = element - EL_SP_START;
2445         int gfx_per_line = 8;
2446         int nr_graphic =
2447           (nr_element / gfx_per_line) * MORE_PER_LINE +
2448           (nr_element % gfx_per_line);
2449
2450         return GFX_START_ROCKSMORE + nr_graphic;
2451       }
2452       else
2453         return -1;
2454     }
2455   }
2456 }