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