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