1 /***********************************************************
2 * Rocks'n'Diamonds -- McDuffin Strikes Back! *
3 *----------------------------------------------------------*
4 * (c) 1995-98 Artsoft Entertainment *
8 * phone: ++49 +521 290471 *
9 * email: aeglos@valinor.owl.de *
10 *----------------------------------------------------------*
12 ***********************************************************/
17 #include <machine/joystick.h>
31 extern boolean wait_for_vsync;
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
43 #define NUM_TOOL_BUTTONS 7
45 /* forward declaration for internal use */
46 static int getGraphicAnimationPhase(int, int, int);
47 static void UnmapToolButtons();
48 static void HandleToolButtons(struct GadgetInfo *);
50 static struct GadgetInfo *tool_gadget[NUM_TOOL_BUTTONS];
51 static int request_gadget_id = -1;
53 void SetDrawtoField(int mode)
55 if (mode == DRAW_BUFFERED && setup.soft_scrolling)
66 drawto_field = fieldbuffer;
68 else /* DRAW_DIRECT, DRAW_BACKBUFFER */
79 drawto_field = (mode == DRAW_DIRECT ? window : backbuffer);
86 Drawable buffer = (drawto_field == window ? backbuffer : drawto_field);
88 if (setup.direct_draw && game_status == PLAYING)
89 redraw_mask &= ~REDRAW_MAIN;
91 if (redraw_mask & REDRAW_TILES && redraw_tiles > REDRAWTILES_THRESHOLD)
92 redraw_mask |= REDRAW_FIELD;
94 if (redraw_mask & REDRAW_FIELD)
95 redraw_mask &= ~REDRAW_TILES;
100 /* synchronize X11 graphics at this point; if we would synchronize the
101 display immediately after the buffer switching (after the XFlush),
102 this could mean that we have to wait for the graphics to complete,
103 although we could go on doing calculations for the next frame */
105 XSync(display, FALSE);
107 if (redraw_mask & REDRAW_ALL)
109 XCopyArea(display, backbuffer, window, gc,
110 0, 0, WIN_XSIZE, WIN_YSIZE,
115 if (redraw_mask & REDRAW_FIELD)
117 if (game_status != PLAYING || redraw_mask & REDRAW_FROM_BACKBUFFER)
119 XCopyArea(display, backbuffer, window, gc,
120 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
125 int fx = FX, fy = FY;
127 if (setup.soft_scrolling)
129 fx += (ScreenMovDir & (MV_LEFT | MV_RIGHT) ? ScreenGfxPos : 0);
130 fy += (ScreenMovDir & (MV_UP | MV_DOWN) ? ScreenGfxPos : 0);
133 if (setup.soft_scrolling ||
134 ABS(ScreenMovPos) + ScrollStepSize == TILEX ||
135 ABS(ScreenMovPos) == ScrollStepSize ||
136 redraw_tiles > REDRAWTILES_THRESHOLD)
138 XCopyArea(display, buffer, window, gc, fx, fy, SXSIZE, SYSIZE, SX, SY);
142 printf("redrawing all (ScreenGfxPos == %d) because %s\n",
144 (setup.soft_scrolling ?
145 "setup.soft_scrolling" :
146 ABS(ScreenGfxPos) + ScrollStepSize == TILEX ?
147 "ABS(ScreenGfxPos) + ScrollStepSize == TILEX" :
148 ABS(ScreenGfxPos) == ScrollStepSize ?
149 "ABS(ScreenGfxPos) == ScrollStepSize" :
150 "redraw_tiles > REDRAWTILES_THRESHOLD"));
155 redraw_mask &= ~REDRAW_MAIN;
158 if (redraw_mask & REDRAW_DOORS)
160 if (redraw_mask & REDRAW_DOOR_1)
161 XCopyArea(display, backbuffer, window, gc,
162 DX, DY, DXSIZE, DYSIZE,
164 if (redraw_mask & REDRAW_DOOR_2)
166 if ((redraw_mask & REDRAW_DOOR_2) == REDRAW_DOOR_2)
167 XCopyArea(display,backbuffer,window,gc,
168 VX,VY, VXSIZE,VYSIZE,
172 if (redraw_mask & REDRAW_VIDEO_1)
173 XCopyArea(display,backbuffer,window,gc,
174 VX+VIDEO_DISPLAY1_XPOS,VY+VIDEO_DISPLAY1_YPOS,
175 VIDEO_DISPLAY_XSIZE,VIDEO_DISPLAY_YSIZE,
176 VX+VIDEO_DISPLAY1_XPOS,VY+VIDEO_DISPLAY1_YPOS);
177 if (redraw_mask & REDRAW_VIDEO_2)
178 XCopyArea(display,backbuffer,window,gc,
179 VX+VIDEO_DISPLAY2_XPOS,VY+VIDEO_DISPLAY2_YPOS,
180 VIDEO_DISPLAY_XSIZE,VIDEO_DISPLAY_YSIZE,
181 VX+VIDEO_DISPLAY2_XPOS,VY+VIDEO_DISPLAY2_YPOS);
182 if (redraw_mask & REDRAW_VIDEO_3)
183 XCopyArea(display,backbuffer,window,gc,
184 VX+VIDEO_CONTROL_XPOS,VY+VIDEO_CONTROL_YPOS,
185 VIDEO_CONTROL_XSIZE,VIDEO_CONTROL_YSIZE,
186 VX+VIDEO_CONTROL_XPOS,VY+VIDEO_CONTROL_YPOS);
189 if (redraw_mask & REDRAW_DOOR_3)
190 XCopyArea(display, backbuffer, window, gc,
191 EX, EY, EXSIZE, EYSIZE,
193 redraw_mask &= ~REDRAW_DOORS;
196 if (redraw_mask & REDRAW_MICROLEVEL)
198 XCopyArea(display,backbuffer,window,gc,
199 MICROLEV_XPOS, MICROLEV_YPOS, MICROLEV_XSIZE, MICROLEV_YSIZE,
200 MICROLEV_XPOS, MICROLEV_YPOS);
201 XCopyArea(display,backbuffer,window,gc,
202 SX, MICROLABEL_YPOS, SXSIZE, FONT4_YSIZE,
203 SX, MICROLABEL_YPOS);
204 redraw_mask &= ~REDRAW_MICROLEVEL;
207 if (redraw_mask & REDRAW_TILES)
209 for(x=0; x<SCR_FIELDX; x++)
210 for(y=0; y<SCR_FIELDY; y++)
211 if (redraw[redraw_x1 + x][redraw_y1 + y])
212 XCopyArea(display, buffer, window, gc,
213 FX + x * TILEX, FX + y * TILEY, TILEX, TILEY,
214 SX + x * TILEX, SY + y * TILEY);
219 for(x=0; x<MAX_BUF_XSIZE; x++)
220 for(y=0; y<MAX_BUF_YSIZE; y++)
229 long fading_delay = 300;
231 if (setup.fading && (redraw_mask & REDRAW_FIELD))
238 XFillRectangle(display,window,gc,
239 REAL_SX,REAL_SY,FULL_SXSIZE,FULL_SYSIZE);
242 for(i=0;i<2*FULL_SYSIZE;i++)
244 for(y=0;y<FULL_SYSIZE;y++)
246 XCopyArea(display,backbuffer,window,gc,
247 REAL_SX,REAL_SY+i, FULL_SXSIZE,1, REAL_SX,REAL_SY+i);
255 for(i=1;i<FULL_SYSIZE;i+=2)
256 XCopyArea(display,backbuffer,window,gc,
257 REAL_SX,REAL_SY+i, FULL_SXSIZE,1, REAL_SX,REAL_SY+i);
263 XSetClipOrigin(display,clip_gc[PIX_FADEMASK],0,0);
264 XCopyArea(display,backbuffer,window,clip_gc[PIX_FADEMASK],
265 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE, REAL_SX,REAL_SY);
269 XSetClipOrigin(display,clip_gc[PIX_FADEMASK],-1,-1);
270 XCopyArea(display,backbuffer,window,clip_gc[PIX_FADEMASK],
271 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE, REAL_SX,REAL_SY);
275 XSetClipOrigin(display,clip_gc[PIX_FADEMASK],0,-1);
276 XCopyArea(display,backbuffer,window,clip_gc[PIX_FADEMASK],
277 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE, REAL_SX,REAL_SY);
281 XSetClipOrigin(display,clip_gc[PIX_FADEMASK],-1,0);
282 XCopyArea(display,backbuffer,window,clip_gc[PIX_FADEMASK],
283 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE, REAL_SX,REAL_SY);
287 redraw_mask &= ~REDRAW_MAIN;
296 XFillRectangle(display, backbuffer, gc,
297 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
299 if (setup.soft_scrolling && game_status == PLAYING)
301 XFillRectangle(display, fieldbuffer, gc, 0, 0, FXSIZE, FYSIZE);
302 SetDrawtoField(DRAW_BUFFERED);
305 SetDrawtoField(DRAW_BACKBUFFER);
307 if (setup.direct_draw && game_status == PLAYING)
309 XFillRectangle(display, window, gc,
310 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
311 SetDrawtoField(DRAW_DIRECT);
314 redraw_mask |= REDRAW_FIELD;
317 int getFontWidth(int font_size, int font_type)
319 return (font_size == FS_BIG ? FONT1_XSIZE :
320 font_type == FC_SPECIAL1 ? FONT3_XSIZE :
321 font_type == FC_SPECIAL2 ? FONT4_XSIZE :
322 font_type == FC_SPECIAL3 ? FONT5_XSIZE :
326 int getFontHeight(int font_size, int font_type)
328 return (font_size == FS_BIG ? FONT1_YSIZE :
329 font_type == FC_SPECIAL1 ? FONT3_YSIZE :
330 font_type == FC_SPECIAL2 ? FONT4_YSIZE :
331 font_type == FC_SPECIAL3 ? FONT5_YSIZE :
335 void DrawTextFCentered(int y, int font_type, char *format, ...)
337 char buffer[FULL_SXSIZE / FONT5_XSIZE + 10];
338 int font_width = getFontWidth(FS_SMALL, font_type);
341 va_start(ap, format);
342 vsprintf(buffer, format, ap);
345 DrawText(SX + (SXSIZE - strlen(buffer) * font_width) / 2, SY + y,
346 buffer, FS_SMALL, font_type);
349 void DrawTextF(int x, int y, int font_type, char *format, ...)
351 char buffer[FULL_SXSIZE / FONT5_XSIZE + 10];
354 va_start(ap, format);
355 vsprintf(buffer, format, ap);
358 DrawText(SX + x, SY + y, buffer, FS_SMALL, font_type);
361 void DrawText(int x, int y, char *text, int font_size, int font_type)
363 DrawTextExt(drawto, gc, x, y, text, font_size, font_type);
366 redraw_mask |= REDRAW_FIELD;
368 redraw_mask |= REDRAW_DOOR_1;
371 void DrawTextExt(Drawable d, GC gc, int x, int y,
372 char *text, int font_size, int font_type)
374 int font_width, font_height, font_start;
376 boolean print_inverse = FALSE;
378 if (font_size != FS_SMALL && font_size != FS_BIG)
379 font_size = FS_SMALL;
380 if (font_type < FC_RED || font_type > FC_SPECIAL3)
383 font_width = getFontWidth(font_size, font_type);
384 font_height = getFontHeight(font_size, font_type);
386 font_pixmap = (font_size == FS_BIG ? PIX_BIGFONT : PIX_SMALLFONT);
387 font_start = (font_type * (font_size == FS_BIG ? FONT1_YSIZE : FONT2_YSIZE) *
388 FONT_LINES_PER_FONT);
390 if (font_type == FC_SPECIAL3)
391 font_start += (FONT4_YSIZE - FONT2_YSIZE) * FONT_LINES_PER_FONT;
397 if (c == '~' && font_size == FS_SMALL)
399 print_inverse = TRUE;
403 if (c >= 'a' && c <= 'z')
405 else if (c == 'ä' || c == 'Ä')
407 else if (c == 'ö' || c == 'Ö')
409 else if (c == 'ü' || c == 'Ü')
412 if (c >= 32 && c <= 95)
414 int src_x = ((c - 32) % FONT_CHARS_PER_LINE) * font_width;
415 int src_y = ((c - 32) / FONT_CHARS_PER_LINE) * font_height + font_start;
416 int dest_x = x, dest_y = y;
420 XCopyArea(display, pix[font_pixmap], d, gc,
421 FONT_CHARS_PER_LINE * font_width,
422 3 * font_height + font_start,
423 font_width, font_height, x, y);
425 XSetClipOrigin(display, clip_gc[font_pixmap],
426 dest_x - src_x, dest_y - src_y);
427 XCopyArea(display, pix[font_pixmap], d, clip_gc[font_pixmap],
428 0, 0, font_width, font_height, dest_x, dest_y);
431 XCopyArea(display, pix[font_pixmap], d, gc,
432 src_x, src_y, font_width, font_height, dest_x, dest_y);
439 void DrawAllPlayers()
443 for(i=0; i<MAX_PLAYERS; i++)
444 if (stored_player[i].active)
445 DrawPlayer(&stored_player[i]);
448 void DrawPlayerField(int x, int y)
450 if (!IS_PLAYER(x, y))
453 DrawPlayer(PLAYERINFO(x, y));
456 void DrawPlayer(struct PlayerInfo *player)
458 int jx = player->jx, jy = player->jy;
459 int last_jx = player->last_jx, last_jy = player->last_jy;
460 int next_jx = jx + (jx - last_jx), next_jy = jy + (jy - last_jy);
461 int sx = SCREENX(jx), sy = SCREENY(jy);
462 int sxx = 0, syy = 0;
463 int element = Feld[jx][jy], last_element = Feld[last_jx][last_jy];
465 boolean player_is_moving = (last_jx != jx || last_jy != jy ? TRUE : FALSE);
467 if (!player->active || !IN_SCR_FIELD(SCREENX(last_jx), SCREENY(last_jy)))
471 if (!IN_LEV_FIELD(jx,jy))
473 printf("DrawPlayerField(): x = %d, y = %d\n",jx,jy);
474 printf("DrawPlayerField(): sx = %d, sy = %d\n",sx,sy);
475 printf("DrawPlayerField(): This should never happen!\n");
480 if (element == EL_EXPLODING)
483 /* draw things in the field the player is leaving, if needed */
485 if (player_is_moving)
487 if (Store[last_jx][last_jy] && IS_DRAWABLE(last_element))
489 DrawLevelElement(last_jx, last_jy, Store[last_jx][last_jy]);
490 DrawLevelFieldThruMask(last_jx, last_jy);
492 else if (last_element == EL_DYNAMITE_ACTIVE)
493 DrawDynamite(last_jx, last_jy);
495 DrawLevelField(last_jx, last_jy);
497 if (player->Pushing && IN_SCR_FIELD(SCREENX(next_jx), SCREENY(next_jy)))
501 if (Feld[next_jx][next_jy] == EL_SOKOBAN_FELD_VOLL)
502 DrawLevelElement(next_jx, next_jy, EL_SOKOBAN_FELD_LEER);
504 DrawLevelElement(next_jx, next_jy, EL_LEERRAUM);
507 DrawLevelField(next_jx, next_jy);
511 if (!IN_SCR_FIELD(sx, sy))
514 if (setup.direct_draw)
515 SetDrawtoField(DRAW_BUFFERED);
517 /* draw things behind the player, if needed */
520 DrawLevelElement(jx, jy, Store[jx][jy]);
521 else if (!IS_ACTIVE_BOMB(element))
522 DrawLevelField(jx, jy);
524 /* draw player himself */
526 if (game.emulation == EMU_SUPAPLEX)
528 static int last_dir = MV_LEFT;
529 int action = (player->programmed_action ? player->programmed_action :
531 boolean action_moving =
533 ((action & (MV_LEFT | MV_RIGHT | MV_UP | MV_DOWN)) &&
534 !(action & ~(MV_LEFT | MV_RIGHT | MV_UP | MV_DOWN))));
536 graphic = GFX_SP_MURPHY;
540 if (player->MovDir == MV_LEFT)
541 graphic = GFX_MURPHY_PUSH_LEFT;
542 else if (player->MovDir == MV_RIGHT)
543 graphic = GFX_MURPHY_PUSH_RIGHT;
544 else if (player->MovDir & (MV_UP | MV_DOWN) && last_dir == MV_LEFT)
545 graphic = GFX_MURPHY_PUSH_LEFT;
546 else if (player->MovDir & (MV_UP | MV_DOWN) && last_dir == MV_RIGHT)
547 graphic = GFX_MURPHY_PUSH_RIGHT;
549 else if (player->snapped)
551 if (player->MovDir == MV_LEFT)
552 graphic = GFX_MURPHY_SNAP_LEFT;
553 else if (player->MovDir == MV_RIGHT)
554 graphic = GFX_MURPHY_SNAP_RIGHT;
555 else if (player->MovDir == MV_UP)
556 graphic = GFX_MURPHY_SNAP_UP;
557 else if (player->MovDir == MV_DOWN)
558 graphic = GFX_MURPHY_SNAP_DOWN;
560 else if (action_moving)
562 if (player->MovDir == MV_LEFT)
563 graphic = GFX_MURPHY_GO_LEFT;
564 else if (player->MovDir == MV_RIGHT)
565 graphic = GFX_MURPHY_GO_RIGHT;
566 else if (player->MovDir & (MV_UP | MV_DOWN) && last_dir == MV_LEFT)
567 graphic = GFX_MURPHY_GO_LEFT;
568 else if (player->MovDir & (MV_UP | MV_DOWN) && last_dir == MV_RIGHT)
569 graphic = GFX_MURPHY_GO_RIGHT;
571 graphic += getGraphicAnimationPhase(3, 2, ANIM_OSCILLATE);
574 if (player->MovDir == MV_LEFT || player->MovDir == MV_RIGHT)
575 last_dir = player->MovDir;
579 if (player->MovDir == MV_LEFT)
581 (player->Pushing ? GFX_SPIELER1_PUSH_LEFT : GFX_SPIELER1_LEFT);
582 else if (player->MovDir == MV_RIGHT)
584 (player->Pushing ? GFX_SPIELER1_PUSH_RIGHT : GFX_SPIELER1_RIGHT);
585 else if (player->MovDir == MV_UP)
586 graphic = GFX_SPIELER1_UP;
587 else /* MV_DOWN || MV_NO_MOVING */
588 graphic = GFX_SPIELER1_DOWN;
590 graphic += player->index_nr * 3 * HEROES_PER_LINE;
591 graphic += player->Frame;
596 if (player->MovDir == MV_LEFT || player->MovDir == MV_RIGHT)
597 sxx = player->GfxPos;
599 syy = player->GfxPos;
602 if (!setup.soft_scrolling && ScreenMovPos)
605 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, NO_CUTTING);
607 if (player->Pushing && player->GfxPos)
609 int px = SCREENX(next_jx), py = SCREENY(next_jy);
611 if (element == EL_SOKOBAN_FELD_LEER ||
612 Feld[next_jx][next_jy] == EL_SOKOBAN_FELD_VOLL)
613 DrawGraphicShiftedThruMask(px, py, sxx, syy, GFX_SOKOBAN_OBJEKT,
617 int element = Feld[next_jx][next_jy];
618 int graphic = el2gfx(element);
620 if ((element == EL_FELSBROCKEN || element == EL_SP_ZONK) && sxx)
622 int phase = (player->GfxPos / (TILEX / 4));
624 if (player->MovDir == MV_LEFT)
627 graphic += (phase + 4) % 4;
630 DrawGraphicShifted(px, py, sxx, syy, graphic, NO_CUTTING, NO_MASKING);
634 /* draw things in front of player (active dynamite or dynabombs) */
636 if (IS_ACTIVE_BOMB(element))
638 graphic = el2gfx(element);
640 if (element == EL_DYNAMITE_ACTIVE)
642 if ((phase = (96 - MovDelay[jx][jy]) / 12) > 6)
647 if ((phase = ((96 - MovDelay[jx][jy]) / 6) % 8) > 3)
651 if (game.emulation == EMU_SUPAPLEX)
652 DrawGraphic(sx, sy, GFX_SP_DISK_RED);
654 DrawGraphicThruMask(sx, sy, graphic + phase);
657 if (player_is_moving && last_element == EL_EXPLODING)
659 int phase = Frame[last_jx][last_jy];
663 DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy),
664 GFX_EXPLOSION + ((phase - 1) / delay - 1));
667 /* draw elements that stay over the player */
668 /* handle the field the player is leaving ... */
669 if (player_is_moving && IS_OVER_PLAYER(last_element))
670 DrawLevelField(last_jx, last_jy);
671 /* ... and the field the player is entering */
672 if (IS_OVER_PLAYER(element))
673 DrawLevelField(jx, jy);
675 if (setup.direct_draw)
677 int dest_x = SX + SCREENX(MIN(jx, last_jx)) * TILEX;
678 int dest_y = SY + SCREENY(MIN(jy, last_jy)) * TILEY;
679 int x_size = TILEX * (1 + ABS(jx - last_jx));
680 int y_size = TILEY * (1 + ABS(jy - last_jy));
682 XCopyArea(display, drawto_field, window, gc,
683 dest_x, dest_y, x_size, y_size, dest_x, dest_y);
684 SetDrawtoField(DRAW_DIRECT);
687 MarkTileDirty(sx,sy);
690 static int getGraphicAnimationPhase(int frames, int delay, int mode)
694 if (mode == ANIM_OSCILLATE)
696 int max_anim_frames = 2 * frames - 2;
697 phase = (FrameCounter % (delay * max_anim_frames)) / delay;
698 phase = (phase < frames ? phase : max_anim_frames - phase);
701 phase = (FrameCounter % (delay * frames)) / delay;
703 if (mode == ANIM_REVERSE)
709 void DrawGraphicAnimationExt(int x, int y, int graphic,
710 int frames, int delay, int mode, int mask_mode)
712 int phase = getGraphicAnimationPhase(frames, delay, mode);
714 if (!(FrameCounter % delay) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
716 if (mask_mode == USE_MASKING)
717 DrawGraphicThruMask(SCREENX(x), SCREENY(y), graphic + phase);
719 DrawGraphic(SCREENX(x), SCREENY(y), graphic + phase);
723 void DrawGraphicAnimation(int x, int y, int graphic,
724 int frames, int delay, int mode)
726 DrawGraphicAnimationExt(x, y, graphic, frames, delay, mode, NO_MASKING);
729 void DrawGraphicAnimationThruMask(int x, int y, int graphic,
730 int frames, int delay, int mode)
732 DrawGraphicAnimationExt(x, y, graphic, frames, delay, mode, USE_MASKING);
735 void getGraphicSource(int graphic, int *pixmap_nr, int *x, int *y)
737 if (graphic >= GFX_START_ROCKSSCREEN && graphic <= GFX_END_ROCKSSCREEN)
739 graphic -= GFX_START_ROCKSSCREEN;
740 *pixmap_nr = PIX_BACK;
741 *x = SX + (graphic % GFX_PER_LINE) * TILEX;
742 *y = SY + (graphic / GFX_PER_LINE) * TILEY;
744 else if (graphic >= GFX_START_ROCKSHEROES && graphic <= GFX_END_ROCKSHEROES)
746 graphic -= GFX_START_ROCKSHEROES;
747 *pixmap_nr = PIX_HEROES;
748 *x = (graphic % HEROES_PER_LINE) * TILEX;
749 *y = (graphic / HEROES_PER_LINE) * TILEY;
751 else if (graphic >= GFX_START_ROCKSSP && graphic <= GFX_END_ROCKSSP)
753 graphic -= GFX_START_ROCKSSP;
755 *x = (graphic % SP_PER_LINE) * TILEX;
756 *y = (graphic / SP_PER_LINE) * TILEY;
758 else if (graphic >= GFX_START_ROCKSDC && graphic <= GFX_END_ROCKSDC)
760 graphic -= GFX_START_ROCKSDC;
762 *x = (graphic % DC_PER_LINE) * TILEX;
763 *y = (graphic / DC_PER_LINE) * TILEY;
765 else if (graphic >= GFX_START_ROCKSFONT && graphic <= GFX_END_ROCKSFONT)
767 graphic -= GFX_START_ROCKSFONT;
768 *pixmap_nr = PIX_BIGFONT;
769 *x = (graphic % FONT_CHARS_PER_LINE) * TILEX;
770 *y = ((graphic / FONT_CHARS_PER_LINE) * TILEY +
771 FC_SPECIAL1 * FONT_LINES_PER_FONT * TILEY);
781 void DrawGraphic(int x, int y, int graphic)
784 if (!IN_SCR_FIELD(x,y))
786 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
787 printf("DrawGraphic(): This should never happen!\n");
792 DrawGraphicExt(drawto_field, gc, FX + x*TILEX, FY + y*TILEY, graphic);
796 void DrawGraphicExt(Drawable d, GC gc, int x, int y, int graphic)
801 getGraphicSource(graphic, &pixmap_nr, &src_x, &src_y);
802 XCopyArea(display, pix[pixmap_nr], d, gc,
803 src_x, src_y, TILEX, TILEY, x, y);
806 void DrawGraphicThruMask(int x, int y, int graphic)
809 if (!IN_SCR_FIELD(x,y))
811 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
812 printf("DrawGraphicThruMask(): This should never happen!\n");
817 DrawGraphicThruMaskExt(drawto_field, FX + x*TILEX, FY + y*TILEY, graphic);
821 void DrawGraphicThruMaskExt(Drawable d, int dest_x, int dest_y, int graphic)
829 if (graphic == GFX_LEERRAUM)
832 getGraphicSource(graphic, &pixmap_nr, &src_x, &src_y);
833 src_pixmap = pix[pixmap_nr];
834 drawing_gc = clip_gc[pixmap_nr];
836 if (tile_clipmask[tile] != None)
838 XSetClipMask(display, tile_clip_gc, tile_clipmask[tile]);
839 XSetClipOrigin(display, tile_clip_gc, dest_x, dest_y);
840 XCopyArea(display, src_pixmap, d, tile_clip_gc,
841 src_x, src_y, TILEX, TILEY, dest_x, dest_y);
846 printf("DrawGraphicThruMask(): tile '%d' needs clipping!\n", tile);
849 XSetClipOrigin(display, drawing_gc, dest_x-src_x, dest_y-src_y);
850 XCopyArea(display, src_pixmap, d, drawing_gc,
851 src_x, src_y, TILEX, TILEY, dest_x, dest_y);
855 void DrawMiniGraphic(int x, int y, int graphic)
857 DrawMiniGraphicExt(drawto,gc, SX + x*MINI_TILEX, SY + y*MINI_TILEY, graphic);
858 MarkTileDirty(x/2, y/2);
861 void getMiniGraphicSource(int graphic, Pixmap *pixmap, int *x, int *y)
863 if (graphic >= GFX_START_ROCKSSCREEN && graphic <= GFX_END_ROCKSSCREEN)
865 graphic -= GFX_START_ROCKSSCREEN;
866 *pixmap = pix[PIX_BACK];
867 *x = MINI_GFX_STARTX + (graphic % MINI_GFX_PER_LINE) * MINI_TILEX;
868 *y = MINI_GFX_STARTY + (graphic / MINI_GFX_PER_LINE) * MINI_TILEY;
870 else if (graphic >= GFX_START_ROCKSSP && graphic <= GFX_END_ROCKSSP)
872 graphic -= GFX_START_ROCKSSP;
873 graphic -= ((graphic / SP_PER_LINE) * SP_PER_LINE) / 2;
874 *pixmap = pix[PIX_SP];
875 *x = MINI_SP_STARTX + (graphic % MINI_SP_PER_LINE) * MINI_TILEX;
876 *y = MINI_SP_STARTY + (graphic / MINI_SP_PER_LINE) * MINI_TILEY;
878 else if (graphic >= GFX_START_ROCKSDC && graphic <= GFX_END_ROCKSDC)
880 graphic -= GFX_START_ROCKSDC;
881 *pixmap = pix[PIX_DC];
882 *x = MINI_DC_STARTX + (graphic % MINI_DC_PER_LINE) * MINI_TILEX;
883 *y = MINI_DC_STARTY + (graphic / MINI_DC_PER_LINE) * MINI_TILEY;
885 else if (graphic >= GFX_START_ROCKSFONT && graphic <= GFX_END_ROCKSFONT)
887 graphic -= GFX_START_ROCKSFONT;
888 *pixmap = pix[PIX_SMALLFONT];
889 *x = (graphic % FONT_CHARS_PER_LINE) * FONT4_XSIZE;
890 *y = ((graphic / FONT_CHARS_PER_LINE) * FONT4_YSIZE +
891 FC_SPECIAL2 * FONT2_YSIZE * FONT_LINES_PER_FONT);
895 *pixmap = pix[PIX_SP];
901 void DrawMiniGraphicExt(Drawable d, GC gc, int x, int y, int graphic)
906 getMiniGraphicSource(graphic, &pixmap, &src_x, &src_y);
907 XCopyArea(display, pixmap, d, gc,
908 src_x, src_y, MINI_TILEX, MINI_TILEY, x, y);
911 void DrawGraphicShifted(int x,int y, int dx,int dy, int graphic,
912 int cut_mode, int mask_mode)
914 int width = TILEX, height = TILEY;
916 int src_x, src_y, dest_x, dest_y;
924 DrawGraphic(x, y, graphic);
928 if (dx || dy) /* Verschiebung der Grafik? */
930 if (x < BX1) /* Element kommt von links ins Bild */
937 else if (x > BX2) /* Element kommt von rechts ins Bild */
943 else if (x==BX1 && dx < 0) /* Element verläßt links das Bild */
949 else if (x==BX2 && dx > 0) /* Element verläßt rechts das Bild */
951 else if (dx) /* allg. Bewegung in x-Richtung */
952 MarkTileDirty(x + SIGN(dx), y);
954 if (y < BY1) /* Element kommt von oben ins Bild */
956 if (cut_mode==CUT_BELOW) /* Element oberhalb des Bildes */
964 else if (y > BY2) /* Element kommt von unten ins Bild */
970 else if (y==BY1 && dy < 0) /* Element verläßt oben das Bild */
976 else if (dy > 0 && cut_mode == CUT_ABOVE)
978 if (y == BY2) /* Element unterhalb des Bildes */
984 MarkTileDirty(x, y + 1);
985 } /* Element verläßt unten das Bild */
986 else if (dy > 0 && (y == BY2 || cut_mode == CUT_BELOW))
988 else if (dy) /* allg. Bewegung in y-Richtung */
989 MarkTileDirty(x, y + SIGN(dy));
992 getGraphicSource(graphic, &pixmap_nr, &src_x, &src_y);
993 src_pixmap = pix[pixmap_nr];
994 drawing_gc = clip_gc[pixmap_nr];
999 dest_x = FX + x * TILEX + dx;
1000 dest_y = FY + y * TILEY + dy;
1003 if (!IN_SCR_FIELD(x,y))
1005 printf("DrawGraphicShifted(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
1006 printf("DrawGraphicShifted(): This should never happen!\n");
1011 if (mask_mode == USE_MASKING)
1013 if (tile_clipmask[tile] != None)
1015 XSetClipMask(display, tile_clip_gc, tile_clipmask[tile]);
1016 XSetClipOrigin(display, tile_clip_gc, dest_x, dest_y);
1017 XCopyArea(display, src_pixmap, drawto_field, tile_clip_gc,
1018 src_x, src_y, TILEX, TILEY, dest_x, dest_y);
1023 printf("DrawGraphicShifted(): tile '%d' needs clipping!\n", tile);
1026 XSetClipOrigin(display, drawing_gc, dest_x - src_x, dest_y - src_y);
1027 XCopyArea(display, src_pixmap, drawto_field, drawing_gc,
1028 src_x, src_y, width, height, dest_x, dest_y);
1032 XCopyArea(display, src_pixmap, drawto_field, gc,
1033 src_x, src_y, width, height, dest_x, dest_y);
1038 void DrawGraphicShiftedThruMask(int x,int y, int dx,int dy, int graphic,
1041 DrawGraphicShifted(x,y, dx,dy, graphic, cut_mode, USE_MASKING);
1044 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
1045 int cut_mode, int mask_mode)
1047 int ux = LEVELX(x), uy = LEVELY(y);
1048 int graphic = el2gfx(element);
1049 int phase8 = ABS(MovPos[ux][uy]) / (TILEX / 8);
1050 int phase4 = phase8 / 2;
1051 int phase2 = phase8 / 4;
1052 int dir = MovDir[ux][uy];
1054 if (element == EL_PACMAN || element == EL_KAEFER || element == EL_FLIEGER)
1056 graphic += 4 * !phase2;
1060 else if (dir == MV_LEFT)
1062 else if (dir == MV_DOWN)
1065 else if (element == EL_SP_SNIKSNAK)
1068 graphic = GFX_SP_SNIKSNAK_LEFT;
1069 else if (dir == MV_RIGHT)
1070 graphic = GFX_SP_SNIKSNAK_RIGHT;
1071 else if (dir == MV_UP)
1072 graphic = GFX_SP_SNIKSNAK_UP;
1074 graphic = GFX_SP_SNIKSNAK_DOWN;
1076 graphic += (phase8 < 4 ? phase8 : 7 - phase8);
1078 else if (element == EL_SP_ELECTRON)
1080 graphic = GFX2_SP_ELECTRON + getGraphicAnimationPhase(8, 2, ANIM_NORMAL);
1082 else if (element == EL_MAULWURF || element == EL_PINGUIN ||
1083 element == EL_SCHWEIN || element == EL_DRACHE)
1086 graphic = (element == EL_MAULWURF ? GFX_MAULWURF_LEFT :
1087 element == EL_PINGUIN ? GFX_PINGUIN_LEFT :
1088 element == EL_SCHWEIN ? GFX_SCHWEIN_LEFT : GFX_DRACHE_LEFT);
1089 else if (dir == MV_RIGHT)
1090 graphic = (element == EL_MAULWURF ? GFX_MAULWURF_RIGHT :
1091 element == EL_PINGUIN ? GFX_PINGUIN_RIGHT :
1092 element == EL_SCHWEIN ? GFX_SCHWEIN_RIGHT : GFX_DRACHE_RIGHT);
1093 else if (dir == MV_UP)
1094 graphic = (element == EL_MAULWURF ? GFX_MAULWURF_UP :
1095 element == EL_PINGUIN ? GFX_PINGUIN_UP :
1096 element == EL_SCHWEIN ? GFX_SCHWEIN_UP : GFX_DRACHE_UP);
1098 graphic = (element == EL_MAULWURF ? GFX_MAULWURF_DOWN :
1099 element == EL_PINGUIN ? GFX_PINGUIN_DOWN :
1100 element == EL_SCHWEIN ? GFX_SCHWEIN_DOWN : GFX_DRACHE_DOWN);
1104 else if (element == EL_SONDE)
1106 graphic = GFX_SONDE_START + getGraphicAnimationPhase(8, 2, ANIM_NORMAL);
1108 else if (element == EL_SALZSAEURE)
1110 graphic = GFX_GEBLUBBER + getGraphicAnimationPhase(4, 10, ANIM_NORMAL);
1112 else if (element == EL_BUTTERFLY || element == EL_FIREFLY)
1116 else if ((element == EL_FELSBROCKEN || element == EL_SP_ZONK ||
1117 IS_GEM(element)) && !cut_mode)
1119 if (uy >= lev_fieldy-1 || !IS_BELT(Feld[ux][uy+1]))
1121 if (element == EL_FELSBROCKEN || element == EL_SP_ZONK)
1124 graphic += (4 - phase4) % 4;
1125 else if (dir == MV_RIGHT)
1128 graphic += phase2 * 2;
1130 else if (element != EL_SP_INFOTRON)
1134 else if (element == EL_SIEB_LEER || element == EL_SIEB2_LEER ||
1135 element == EL_SIEB_VOLL || element == EL_SIEB2_VOLL)
1137 graphic += 3 + getGraphicAnimationPhase(4, 4, ANIM_REVERSE);
1139 else if (IS_AMOEBOID(element))
1141 graphic = (element == EL_AMOEBE_TOT ? GFX_AMOEBE_TOT : GFX_AMOEBE_LEBT);
1142 graphic += (x + 2 * y + 4) % 4;
1144 else if (element == EL_MAUER_LEBT)
1146 boolean links_massiv = FALSE, rechts_massiv = FALSE;
1148 if (!IN_LEV_FIELD(ux-1, uy) || IS_MAUER(Feld[ux-1][uy]))
1149 links_massiv = TRUE;
1150 if (!IN_LEV_FIELD(ux+1, uy) || IS_MAUER(Feld[ux+1][uy]))
1151 rechts_massiv = TRUE;
1153 if (links_massiv && rechts_massiv)
1154 graphic = GFX_MAUERWERK;
1155 else if (links_massiv)
1156 graphic = GFX_MAUER_R;
1157 else if (rechts_massiv)
1158 graphic = GFX_MAUER_L;
1160 else if ((element == EL_INVISIBLE_STEEL ||
1161 element == EL_UNSICHTBAR ||
1162 element == EL_SAND_INVISIBLE) && game.light_time_left)
1164 graphic = (element == EL_INVISIBLE_STEEL ? GFX_INVISIBLE_STEEL_ON :
1165 element == EL_UNSICHTBAR ? GFX_UNSICHTBAR_ON :
1166 GFX_SAND_INVISIBLE_ON);
1170 DrawGraphicShifted(x, y, dx, dy, graphic, cut_mode, mask_mode);
1171 else if (mask_mode == USE_MASKING)
1172 DrawGraphicThruMask(x, y, graphic);
1174 DrawGraphic(x, y, graphic);
1177 void DrawLevelElementExt(int x, int y, int dx, int dy, int element,
1178 int cut_mode, int mask_mode)
1180 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1181 DrawScreenElementExt(SCREENX(x), SCREENY(y), dx, dy, element,
1182 cut_mode, mask_mode);
1185 void DrawScreenElementShifted(int x, int y, int dx, int dy, int element,
1188 DrawScreenElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1191 void DrawLevelElementShifted(int x, int y, int dx, int dy, int element,
1194 DrawLevelElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1197 void DrawScreenElementThruMask(int x, int y, int element)
1199 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1202 void DrawLevelElementThruMask(int x, int y, int element)
1204 DrawLevelElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1207 void DrawLevelFieldThruMask(int x, int y)
1209 DrawLevelElementExt(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
1212 void ErdreichAnbroeckeln(int x, int y)
1214 int i, width, height, cx,cy;
1215 int ux = LEVELX(x), uy = LEVELY(y);
1216 int element, graphic;
1218 static int xy[4][2] =
1226 if (!IN_LEV_FIELD(ux, uy))
1229 element = Feld[ux][uy];
1231 if (element == EL_ERDREICH || element == EL_LANDMINE)
1233 if (!IN_SCR_FIELD(x, y))
1236 graphic = GFX_ERDENRAND;
1242 uxx = ux + xy[i][0];
1243 uyy = uy + xy[i][1];
1244 if (!IN_LEV_FIELD(uxx, uyy))
1247 element = Feld[uxx][uyy];
1249 if (element == EL_ERDREICH || element == EL_LANDMINE)
1252 if (i == 1 || i == 2)
1256 cx = (i == 2 ? TILEX - snip : 0);
1264 cy = (i == 3 ? TILEY - snip : 0);
1267 XCopyArea(display, pix[PIX_BACK], drawto_field, gc,
1268 SX + (graphic % GFX_PER_LINE) * TILEX + cx,
1269 SY + (graphic / GFX_PER_LINE) * TILEY + cy,
1270 width, height, FX + x * TILEX + cx, FY + y * TILEY + cy);
1273 MarkTileDirty(x, y);
1277 graphic = GFX_ERDENRAND;
1281 int xx, yy, uxx, uyy;
1285 uxx = ux + xy[i][0];
1286 uyy = uy + xy[i][1];
1288 if (!IN_LEV_FIELD(uxx, uyy) ||
1289 (Feld[uxx][uyy] != EL_ERDREICH && Feld[uxx][uyy] != EL_LANDMINE) ||
1290 !IN_SCR_FIELD(xx, yy))
1293 if (i == 1 || i == 2)
1297 cx = (i == 1 ? TILEX - snip : 0);
1305 cy = (i==0 ? TILEY-snip : 0);
1308 XCopyArea(display, pix[PIX_BACK], drawto_field, gc,
1309 SX + (graphic % GFX_PER_LINE) * TILEX + cx,
1310 SY + (graphic / GFX_PER_LINE) * TILEY + cy,
1311 width, height, FX + xx * TILEX + cx, FY + yy * TILEY + cy);
1313 MarkTileDirty(xx, yy);
1318 void DrawScreenElement(int x, int y, int element)
1320 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
1321 ErdreichAnbroeckeln(x, y);
1324 void DrawLevelElement(int x, int y, int element)
1326 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1327 DrawScreenElement(SCREENX(x), SCREENY(y), element);
1330 void DrawScreenField(int x, int y)
1332 int ux = LEVELX(x), uy = LEVELY(y);
1335 if (!IN_LEV_FIELD(ux, uy))
1337 if (ux < -1 || ux > lev_fieldx || uy < -1 || uy > lev_fieldy)
1338 element = EL_LEERRAUM;
1340 element = BorderElement;
1342 DrawScreenElement(x, y, element);
1346 element = Feld[ux][uy];
1348 if (IS_MOVING(ux, uy))
1350 int horiz_move = (MovDir[ux][uy] == MV_LEFT || MovDir[ux][uy] == MV_RIGHT);
1351 boolean cut_mode = NO_CUTTING;
1353 if (Store[ux][uy] == EL_MORAST_LEER ||
1354 Store[ux][uy] == EL_SIEB_LEER ||
1355 Store[ux][uy] == EL_SIEB2_LEER ||
1356 Store[ux][uy] == EL_AMOEBE_NASS)
1357 cut_mode = CUT_ABOVE;
1358 else if (Store[ux][uy] == EL_MORAST_VOLL ||
1359 Store[ux][uy] == EL_SIEB_VOLL ||
1360 Store[ux][uy] == EL_SIEB2_VOLL)
1361 cut_mode = CUT_BELOW;
1363 if (cut_mode == CUT_ABOVE)
1364 DrawScreenElementShifted(x, y, 0, 0, Store[ux][uy], NO_CUTTING);
1366 DrawScreenElement(x, y, EL_LEERRAUM);
1369 DrawScreenElementShifted(x, y, MovPos[ux][uy], 0, element, NO_CUTTING);
1371 DrawScreenElementShifted(x, y, 0, MovPos[ux][uy], element, cut_mode);
1373 if (Store[ux][uy] == EL_SALZSAEURE)
1374 DrawLevelElementThruMask(ux, uy + 1, EL_SALZSAEURE);
1376 else if (IS_BLOCKED(ux, uy))
1381 boolean cut_mode = NO_CUTTING;
1383 Blocked2Moving(ux, uy, &oldx, &oldy);
1386 horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
1387 MovDir[oldx][oldy] == MV_RIGHT);
1389 if (Store[oldx][oldy] == EL_MORAST_LEER ||
1390 Store[oldx][oldy] == EL_SIEB_LEER ||
1391 Store[oldx][oldy] == EL_SIEB2_LEER ||
1392 Store[oldx][oldy] == EL_AMOEBE_NASS)
1393 cut_mode = CUT_ABOVE;
1395 DrawScreenElement(x, y, EL_LEERRAUM);
1396 element = Feld[oldx][oldy];
1399 DrawScreenElementShifted(sx,sy, MovPos[oldx][oldy],0,element,NO_CUTTING);
1401 DrawScreenElementShifted(sx,sy, 0,MovPos[oldx][oldy],element,cut_mode);
1403 else if (IS_DRAWABLE(element))
1404 DrawScreenElement(x, y, element);
1406 DrawScreenElement(x, y, EL_LEERRAUM);
1409 void DrawLevelField(int x, int y)
1411 if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1412 DrawScreenField(SCREENX(x), SCREENY(y));
1413 else if (IS_MOVING(x, y))
1417 Moving2Blocked(x, y, &newx, &newy);
1418 if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
1419 DrawScreenField(SCREENX(newx), SCREENY(newy));
1421 else if (IS_BLOCKED(x, y))
1425 Blocked2Moving(x, y, &oldx, &oldy);
1426 if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
1427 DrawScreenField(SCREENX(oldx), SCREENY(oldy));
1431 void DrawMiniElement(int x, int y, int element)
1437 DrawMiniGraphic(x, y, -1);
1441 graphic = el2gfx(element);
1442 DrawMiniGraphic(x, y, graphic);
1445 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
1447 int x = sx + scroll_x, y = sy + scroll_y;
1449 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
1450 DrawMiniElement(sx, sy, EL_LEERRAUM);
1451 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
1452 DrawMiniElement(sx, sy, Feld[x][y]);
1455 int steel_type, steel_position;
1458 { GFX_VSTEEL_UPPER_LEFT, GFX_ISTEEL_UPPER_LEFT },
1459 { GFX_VSTEEL_UPPER_RIGHT, GFX_ISTEEL_UPPER_RIGHT },
1460 { GFX_VSTEEL_LOWER_LEFT, GFX_ISTEEL_LOWER_LEFT },
1461 { GFX_VSTEEL_LOWER_RIGHT, GFX_ISTEEL_LOWER_RIGHT },
1462 { GFX_VSTEEL_VERTICAL, GFX_ISTEEL_VERTICAL },
1463 { GFX_VSTEEL_HORIZONTAL, GFX_ISTEEL_HORIZONTAL }
1466 steel_type = (BorderElement == EL_BETON ? 0 : 1);
1467 steel_position = (x == -1 && y == -1 ? 0 :
1468 x == lev_fieldx && y == -1 ? 1 :
1469 x == -1 && y == lev_fieldy ? 2 :
1470 x == lev_fieldx && y == lev_fieldy ? 3 :
1471 x == -1 || x == lev_fieldx ? 4 :
1472 y == -1 || y == lev_fieldy ? 5 : -1);
1474 if (steel_position != -1)
1475 DrawMiniGraphic(sx, sy, border[steel_position][steel_type]);
1479 void DrawMicroElement(int xpos, int ypos, int element)
1483 if (element == EL_LEERRAUM)
1486 graphic = el2gfx(element);
1488 if (graphic >= GFX_START_ROCKSSP && graphic <= GFX_END_ROCKSSP)
1490 graphic -= GFX_START_ROCKSSP;
1491 graphic -= ((graphic / SP_PER_LINE) * SP_PER_LINE) / 2;
1492 XCopyArea(display, pix[PIX_SP], drawto, gc,
1493 MICRO_SP_STARTX + (graphic % MICRO_SP_PER_LINE) * MICRO_TILEX,
1494 MICRO_SP_STARTY + (graphic / MICRO_SP_PER_LINE) * MICRO_TILEY,
1495 MICRO_TILEX, MICRO_TILEY, xpos, ypos);
1497 else if (graphic >= GFX_START_ROCKSDC && graphic <= GFX_END_ROCKSDC)
1499 graphic -= GFX_START_ROCKSDC;
1500 XCopyArea(display, pix[PIX_DC], drawto, gc,
1501 MICRO_DC_STARTX + (graphic % MICRO_DC_PER_LINE) * MICRO_TILEX,
1502 MICRO_DC_STARTY + (graphic / MICRO_DC_PER_LINE) * MICRO_TILEY,
1503 MICRO_TILEX, MICRO_TILEY, xpos, ypos);
1506 XCopyArea(display, pix[PIX_BACK], drawto, gc,
1507 MICRO_GFX_STARTX + (graphic % MICRO_GFX_PER_LINE) * MICRO_TILEX,
1508 MICRO_GFX_STARTY + (graphic / MICRO_GFX_PER_LINE) * MICRO_TILEY,
1509 MICRO_TILEX, MICRO_TILEY, xpos, ypos);
1518 for(x=BX1; x<=BX2; x++)
1519 for(y=BY1; y<=BY2; y++)
1520 DrawScreenField(x, y);
1522 redraw_mask |= REDRAW_FIELD;
1525 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
1529 for(x=0; x<size_x; x++)
1530 for(y=0; y<size_y; y++)
1531 DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
1533 redraw_mask |= REDRAW_FIELD;
1536 static void DrawMicroLevelExt(int xpos, int ypos, int from_x, int from_y)
1540 XFillRectangle(display, drawto, gc,
1541 xpos, ypos, MICROLEV_XSIZE, MICROLEV_YSIZE);
1543 if (lev_fieldx < STD_LEV_FIELDX)
1544 xpos += (STD_LEV_FIELDX - lev_fieldx) / 2 * MICRO_TILEX;
1545 if (lev_fieldy < STD_LEV_FIELDY)
1546 ypos += (STD_LEV_FIELDY - lev_fieldy) / 2 * MICRO_TILEY;
1548 xpos += MICRO_TILEX;
1549 ypos += MICRO_TILEY;
1551 for(x=-1; x<=STD_LEV_FIELDX; x++)
1553 for(y=-1; y<=STD_LEV_FIELDY; y++)
1555 int lx = from_x + x, ly = from_y + y;
1557 if (lx >= 0 && lx < lev_fieldx && ly >= 0 && ly < lev_fieldy)
1558 DrawMicroElement(xpos + x * MICRO_TILEX, ypos + y * MICRO_TILEY,
1560 else if (lx >= -1 && lx < lev_fieldx+1 && ly >= -1 && ly < lev_fieldy+1)
1561 DrawMicroElement(xpos + x * MICRO_TILEX, ypos + y * MICRO_TILEY,
1566 redraw_mask |= REDRAW_MICROLEVEL;
1569 #define MICROLABEL_EMPTY 0
1570 #define MICROLABEL_LEVEL_NAME 1
1571 #define MICROLABEL_CREATED_BY 2
1572 #define MICROLABEL_LEVEL_AUTHOR 3
1573 #define MICROLABEL_IMPORTED_FROM 4
1574 #define MICROLABEL_LEVEL_IMPORT_INFO 5
1576 #define MAX_MICROLABEL_SIZE (SXSIZE / FONT4_XSIZE)
1578 static void DrawMicroLevelLabelExt(int mode)
1580 char label_text[MAX_MICROLABEL_SIZE + 1];
1582 XFillRectangle(display, drawto,gc,
1583 SX, MICROLABEL_YPOS, SXSIZE, FONT4_YSIZE);
1585 strncpy(label_text, (mode == MICROLABEL_LEVEL_NAME ? level.name :
1586 mode == MICROLABEL_CREATED_BY ? "created by" :
1587 mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
1588 mode == MICROLABEL_IMPORTED_FROM ? "imported from" :
1589 mode == MICROLABEL_LEVEL_IMPORT_INFO ?
1590 leveldir[leveldir_nr].imported_from : ""),
1591 MAX_MICROLABEL_SIZE);
1592 label_text[MAX_MICROLABEL_SIZE] = '\0';
1594 if (strlen(label_text) > 0)
1596 int lxpos = SX + (SXSIZE - strlen(label_text) * FONT4_XSIZE) / 2;
1597 int lypos = MICROLABEL_YPOS;
1599 DrawText(lxpos, lypos, label_text, FS_SMALL, FC_SPECIAL2);
1602 redraw_mask |= REDRAW_MICROLEVEL;
1605 void DrawMicroLevel(int xpos, int ypos, boolean restart)
1607 static unsigned long scroll_delay = 0;
1608 static unsigned long label_delay = 0;
1609 static int from_x, from_y, scroll_direction;
1610 static int label_state, label_counter;
1614 from_x = from_y = 0;
1615 scroll_direction = MV_RIGHT;
1619 DrawMicroLevelExt(xpos, ypos, from_x, from_y);
1620 DrawMicroLevelLabelExt(label_state);
1622 /* initialize delay counters */
1623 DelayReached(&scroll_delay, 0);
1624 DelayReached(&label_delay, 0);
1629 /* scroll micro level, if needed */
1630 if ((lev_fieldx > STD_LEV_FIELDX || lev_fieldy > STD_LEV_FIELDY) &&
1631 DelayReached(&scroll_delay, MICROLEVEL_SCROLL_DELAY))
1633 switch (scroll_direction)
1639 scroll_direction = MV_UP;
1643 if (from_x < lev_fieldx - STD_LEV_FIELDX)
1646 scroll_direction = MV_DOWN;
1653 scroll_direction = MV_RIGHT;
1657 if (from_y < lev_fieldy - STD_LEV_FIELDY)
1660 scroll_direction = MV_LEFT;
1667 DrawMicroLevelExt(xpos, ypos, from_x, from_y);
1670 /* redraw micro level label, if needed */
1671 if (strcmp(level.name, NAMELESS_LEVEL_NAME) != 0 &&
1672 strcmp(level.author, ANONYMOUS_NAME) != 0 &&
1673 strcmp(level.author, leveldir[leveldir_nr].name) != 0 &&
1674 DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
1676 int max_label_counter = 23;
1678 if (leveldir[leveldir_nr].imported_from != NULL)
1679 max_label_counter += 14;
1681 label_counter = (label_counter + 1) % max_label_counter;
1682 label_state = (label_counter >= 0 && label_counter <= 7 ?
1683 MICROLABEL_LEVEL_NAME :
1684 label_counter >= 9 && label_counter <= 12 ?
1685 MICROLABEL_CREATED_BY :
1686 label_counter >= 14 && label_counter <= 21 ?
1687 MICROLABEL_LEVEL_AUTHOR :
1688 label_counter >= 23 && label_counter <= 26 ?
1689 MICROLABEL_IMPORTED_FROM :
1690 label_counter >= 28 && label_counter <= 35 ?
1691 MICROLABEL_LEVEL_IMPORT_INFO : MICROLABEL_EMPTY);
1692 DrawMicroLevelLabelExt(label_state);
1696 int REQ_in_range(int x, int y)
1698 if (y > DY+249 && y < DY+278)
1700 if (x > DX+1 && x < DX+48)
1702 else if (x > DX+51 && x < DX+98)
1708 boolean Request(char *text, unsigned int req_state)
1710 int mx, my, ty, result = -1;
1711 unsigned int old_door_state;
1714 /* pause network game while waiting for request to answer */
1715 if (options.network &&
1716 game_status == PLAYING &&
1717 req_state & REQUEST_WAIT_FOR)
1718 SendToServer_PausePlaying();
1721 old_door_state = GetDoorState();
1725 CloseDoor(DOOR_CLOSE_1);
1727 /* save old door content */
1728 XCopyArea(display, pix[PIX_DB_DOOR], pix[PIX_DB_DOOR], gc,
1729 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
1730 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
1732 /* clear door drawing field */
1733 XFillRectangle(display, drawto, gc, DX, DY, DXSIZE, DYSIZE);
1735 /* write text for request */
1736 for(ty=0; ty<13; ty++)
1744 for(tl=0,tx=0; tx<7; tl++,tx++)
1747 if (!tc || tc == 32)
1758 DrawTextExt(drawto, gc,
1759 DX + 51 - (tl * 14)/2, DY + 8 + ty * 16,
1760 txt, FS_SMALL, FC_YELLOW);
1761 text += tl + (tc == 32 ? 1 : 0);
1764 if (req_state & REQ_ASK)
1766 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
1767 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
1769 else if (req_state & REQ_CONFIRM)
1771 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
1773 else if (req_state & REQ_PLAYER)
1775 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
1776 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
1777 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
1778 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
1781 /* copy request gadgets to door backbuffer */
1782 XCopyArea(display, drawto, pix[PIX_DB_DOOR], gc,
1783 DX, DY, DXSIZE, DYSIZE,
1784 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
1786 OpenDoor(DOOR_OPEN_1);
1792 if (!(req_state & REQUEST_WAIT_FOR))
1795 if (game_status != MAINMENU)
1798 button_status = MB_RELEASED;
1800 request_gadget_id = -1;
1804 if (XPending(display))
1808 XNextEvent(display, &event);
1816 if (event.type == MotionNotify)
1823 if (!XQueryPointer(display, window, &root, &child,
1824 &root_x, &root_y, &win_x, &win_y, &mask))
1830 motion_status = TRUE;
1831 mx = ((XMotionEvent *) &event)->x;
1832 my = ((XMotionEvent *) &event)->y;
1836 motion_status = FALSE;
1837 mx = ((XButtonEvent *) &event)->x;
1838 my = ((XButtonEvent *) &event)->y;
1839 if (event.type==ButtonPress)
1840 button_status = ((XButtonEvent *) &event)->button;
1842 button_status = MB_RELEASED;
1845 /* this sets 'request_gadget_id' */
1846 HandleGadgets(mx, my, button_status);
1848 switch(request_gadget_id)
1850 case TOOL_CTRL_ID_YES:
1853 case TOOL_CTRL_ID_NO:
1856 case TOOL_CTRL_ID_CONFIRM:
1857 result = TRUE | FALSE;
1860 case TOOL_CTRL_ID_PLAYER_1:
1863 case TOOL_CTRL_ID_PLAYER_2:
1866 case TOOL_CTRL_ID_PLAYER_3:
1869 case TOOL_CTRL_ID_PLAYER_4:
1881 switch(XLookupKeysym((XKeyEvent *)&event,
1882 ((XKeyEvent *)&event)->state))
1895 if (req_state & REQ_PLAYER)
1900 key_joystick_mapping = 0;
1904 HandleOtherEvents(&event);
1908 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
1910 int joy = AnyJoystick();
1912 if (joy & JOY_BUTTON_1)
1914 else if (joy & JOY_BUTTON_2)
1920 /* don't eat all CPU time */
1924 if (game_status != MAINMENU)
1929 if (!(req_state & REQ_STAY_OPEN))
1931 CloseDoor(DOOR_CLOSE_1);
1933 if (!(req_state & REQ_STAY_CLOSED) && (old_door_state & DOOR_OPEN_1))
1935 XCopyArea(display,pix[PIX_DB_DOOR],pix[PIX_DB_DOOR],gc,
1936 DOOR_GFX_PAGEX2,DOOR_GFX_PAGEY1, DXSIZE,DYSIZE,
1937 DOOR_GFX_PAGEX1,DOOR_GFX_PAGEY1);
1938 OpenDoor(DOOR_OPEN_1);
1945 /* continue network game after request */
1946 if (options.network &&
1947 game_status == PLAYING &&
1948 req_state & REQUEST_WAIT_FOR)
1949 SendToServer_ContinuePlaying();
1955 unsigned int OpenDoor(unsigned int door_state)
1957 unsigned int new_door_state;
1959 if (door_state & DOOR_COPY_BACK)
1961 XCopyArea(display, pix[PIX_DB_DOOR], pix[PIX_DB_DOOR], gc,
1962 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE + VYSIZE,
1963 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
1964 door_state &= ~DOOR_COPY_BACK;
1967 new_door_state = MoveDoor(door_state);
1969 return(new_door_state);
1972 unsigned int CloseDoor(unsigned int door_state)
1974 unsigned int new_door_state;
1976 XCopyArea(display, backbuffer, pix[PIX_DB_DOOR], gc,
1977 DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
1978 XCopyArea(display, backbuffer, pix[PIX_DB_DOOR], gc,
1979 VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
1981 new_door_state = MoveDoor(door_state);
1983 return(new_door_state);
1986 unsigned int GetDoorState()
1988 return(MoveDoor(DOOR_GET_STATE));
1991 unsigned int MoveDoor(unsigned int door_state)
1993 static int door1 = DOOR_OPEN_1;
1994 static int door2 = DOOR_CLOSE_2;
1995 static unsigned long door_delay = 0;
1996 int x, start, stepsize = 2;
1997 unsigned long door_delay_value = stepsize * 5;
1999 if (door_state == DOOR_GET_STATE)
2000 return(door1 | door2);
2002 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
2003 door_state &= ~DOOR_OPEN_1;
2004 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
2005 door_state &= ~DOOR_CLOSE_1;
2006 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
2007 door_state &= ~DOOR_OPEN_2;
2008 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
2009 door_state &= ~DOOR_CLOSE_2;
2011 if (setup.quick_doors)
2014 door_delay_value = 0;
2015 StopSound(SND_OEFFNEN);
2018 if (door_state & DOOR_ACTION)
2020 if (!(door_state & DOOR_NO_DELAY))
2021 PlaySoundStereo(SND_OEFFNEN, PSND_MAX_RIGHT);
2023 start = ((door_state & DOOR_NO_DELAY) ? DXSIZE : 0);
2025 for(x=start; x<=DXSIZE; x+=stepsize)
2027 WaitUntilDelayReached(&door_delay, door_delay_value);
2029 if (door_state & DOOR_ACTION_1)
2031 int i = (door_state & DOOR_OPEN_1 ? DXSIZE-x : x);
2032 int j = (DXSIZE - i) / 3;
2034 XCopyArea(display, pix[PIX_DB_DOOR], drawto, gc,
2035 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + i/2,
2036 DXSIZE,DYSIZE - i/2, DX, DY);
2038 XFillRectangle(display, drawto, gc, DX, DY + DYSIZE - i/2, DXSIZE,i/2);
2040 XSetClipOrigin(display, clip_gc[PIX_DOOR],
2041 DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2042 XCopyArea(display, pix[PIX_DOOR], drawto,clip_gc[PIX_DOOR],
2043 DXSIZE, DOOR_GFX_PAGEY1, i, 77, DX + DXSIZE - i, DY + j);
2044 XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
2045 DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63, DX + DXSIZE - i,
2047 XSetClipOrigin(display, clip_gc[PIX_DOOR],
2048 DX - DXSIZE + i, DY - (DOOR_GFX_PAGEY1 + j));
2049 XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
2050 DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j, DX, DY);
2051 XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
2052 DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63, DX, DY + 140 - j);
2054 XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
2055 DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
2057 XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
2058 DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
2060 XSetClipOrigin(display, clip_gc[PIX_DOOR],
2061 DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2062 XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
2063 DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
2064 DX + DXSIZE - i, DY + 77 + j);
2065 XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
2066 DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
2067 DX + DXSIZE - i, DY + 203 + j);
2069 redraw_mask |= REDRAW_DOOR_1;
2072 if (door_state & DOOR_ACTION_2)
2074 int i = (door_state & DOOR_OPEN_2 ? VXSIZE - x : x);
2075 int j = (VXSIZE - i) / 3;
2077 XCopyArea(display, pix[PIX_DB_DOOR], drawto, gc,
2078 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + i/2,
2079 VXSIZE, VYSIZE - i/2, VX, VY);
2081 XFillRectangle(display, drawto, gc, VX, VY + VYSIZE-i/2, VXSIZE, i/2);
2083 XSetClipOrigin(display, clip_gc[PIX_DOOR],
2084 VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2085 XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
2086 VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2, VX + VXSIZE-i, VY+j);
2087 XSetClipOrigin(display, clip_gc[PIX_DOOR],
2088 VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
2089 XCopyArea(display, pix[PIX_DOOR], drawto,clip_gc[PIX_DOOR],
2090 VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j, VX, VY);
2092 XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
2093 VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2, i, VYSIZE / 2,
2094 VX, VY + VYSIZE / 2 - j);
2095 XSetClipOrigin(display, clip_gc[PIX_DOOR],
2096 VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2097 XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
2098 VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2, i, VYSIZE / 2 - j,
2099 VX + VXSIZE - i, VY + VYSIZE / 2 + j);
2101 redraw_mask |= REDRAW_DOOR_2;
2106 if (game_status == MAINMENU)
2111 if (setup.quick_doors)
2112 StopSound(SND_OEFFNEN);
2114 if (door_state & DOOR_ACTION_1)
2115 door1 = door_state & DOOR_ACTION_1;
2116 if (door_state & DOOR_ACTION_2)
2117 door2 = door_state & DOOR_ACTION_2;
2119 return (door1 | door2);
2122 void DrawSpecialEditorDoor()
2124 /* draw bigger toolbox window */
2125 XCopyArea(display, pix[PIX_DOOR], drawto, gc,
2126 DOOR_GFX_PAGEX7, 0, 108, 56, EX - 4, EY - 12);
2128 redraw_mask |= REDRAW_ALL;
2131 void UndrawSpecialEditorDoor()
2133 /* draw normal tape recorder window */
2134 XCopyArea(display, pix[PIX_BACK], drawto, gc,
2135 562, 344, 108, 56, EX - 4, EY - 12);
2137 redraw_mask |= REDRAW_ALL;
2140 int ReadPixel(Drawable d, int x, int y)
2142 XImage *pixel_image;
2143 unsigned long pixel_value;
2145 pixel_image = XGetImage(display, d, x, y, 1, 1, AllPlanes, ZPixmap);
2146 pixel_value = XGetPixel(pixel_image, 0, 0);
2148 XDestroyImage(pixel_image);
2153 /* ---------- new tool button stuff ---------------------------------------- */
2155 /* graphic position values for tool buttons */
2156 #define TOOL_BUTTON_YES_XPOS 2
2157 #define TOOL_BUTTON_YES_YPOS 250
2158 #define TOOL_BUTTON_YES_GFX_YPOS 0
2159 #define TOOL_BUTTON_YES_XSIZE 46
2160 #define TOOL_BUTTON_YES_YSIZE 28
2161 #define TOOL_BUTTON_NO_XPOS 52
2162 #define TOOL_BUTTON_NO_YPOS TOOL_BUTTON_YES_YPOS
2163 #define TOOL_BUTTON_NO_GFX_YPOS TOOL_BUTTON_YES_GFX_YPOS
2164 #define TOOL_BUTTON_NO_XSIZE TOOL_BUTTON_YES_XSIZE
2165 #define TOOL_BUTTON_NO_YSIZE TOOL_BUTTON_YES_YSIZE
2166 #define TOOL_BUTTON_CONFIRM_XPOS TOOL_BUTTON_YES_XPOS
2167 #define TOOL_BUTTON_CONFIRM_YPOS TOOL_BUTTON_YES_YPOS
2168 #define TOOL_BUTTON_CONFIRM_GFX_YPOS 30
2169 #define TOOL_BUTTON_CONFIRM_XSIZE 96
2170 #define TOOL_BUTTON_CONFIRM_YSIZE TOOL_BUTTON_YES_YSIZE
2171 #define TOOL_BUTTON_PLAYER_XSIZE 30
2172 #define TOOL_BUTTON_PLAYER_YSIZE 30
2173 #define TOOL_BUTTON_PLAYER_GFX_XPOS 5
2174 #define TOOL_BUTTON_PLAYER_GFX_YPOS 185
2175 #define TOOL_BUTTON_PLAYER_XPOS (5 + TOOL_BUTTON_PLAYER_XSIZE / 2)
2176 #define TOOL_BUTTON_PLAYER_YPOS (215 - TOOL_BUTTON_PLAYER_YSIZE / 2)
2177 #define TOOL_BUTTON_PLAYER1_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2178 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2179 #define TOOL_BUTTON_PLAYER2_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2180 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2181 #define TOOL_BUTTON_PLAYER3_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2182 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2183 #define TOOL_BUTTON_PLAYER4_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2184 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2185 #define TOOL_BUTTON_PLAYER1_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2186 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2187 #define TOOL_BUTTON_PLAYER2_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2188 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2189 #define TOOL_BUTTON_PLAYER3_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2190 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2191 #define TOOL_BUTTON_PLAYER4_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2192 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2201 } toolbutton_info[NUM_TOOL_BUTTONS] =
2204 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_GFX_YPOS,
2205 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_YPOS,
2206 TOOL_BUTTON_YES_XSIZE, TOOL_BUTTON_YES_YSIZE,
2211 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_GFX_YPOS,
2212 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_YPOS,
2213 TOOL_BUTTON_NO_XSIZE, TOOL_BUTTON_NO_YSIZE,
2218 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_GFX_YPOS,
2219 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_YPOS,
2220 TOOL_BUTTON_CONFIRM_XSIZE, TOOL_BUTTON_CONFIRM_YSIZE,
2221 TOOL_CTRL_ID_CONFIRM,
2225 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2226 TOOL_BUTTON_PLAYER1_XPOS, TOOL_BUTTON_PLAYER1_YPOS,
2227 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2228 TOOL_CTRL_ID_PLAYER_1,
2232 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2233 TOOL_BUTTON_PLAYER2_XPOS, TOOL_BUTTON_PLAYER2_YPOS,
2234 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2235 TOOL_CTRL_ID_PLAYER_2,
2239 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2240 TOOL_BUTTON_PLAYER3_XPOS, TOOL_BUTTON_PLAYER3_YPOS,
2241 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2242 TOOL_CTRL_ID_PLAYER_3,
2246 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2247 TOOL_BUTTON_PLAYER4_XPOS, TOOL_BUTTON_PLAYER4_YPOS,
2248 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2249 TOOL_CTRL_ID_PLAYER_4,
2254 static void DoNotDisplayInfoText(void *ptr)
2259 void CreateToolButtons()
2263 for (i=0; i<NUM_TOOL_BUTTONS; i++)
2265 Pixmap gd_pixmap = pix[PIX_DOOR];
2266 Pixmap deco_pixmap = None;
2267 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
2268 struct GadgetInfo *gi;
2269 unsigned long event_mask;
2270 int gd_xoffset, gd_yoffset;
2271 int gd_x1, gd_x2, gd_y;
2274 event_mask = GD_EVENT_RELEASED;
2276 gd_xoffset = toolbutton_info[i].xpos;
2277 gd_yoffset = toolbutton_info[i].ypos;
2278 gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
2279 gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
2280 gd_y = DOOR_GFX_PAGEY1 + gd_yoffset;
2282 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
2284 getMiniGraphicSource(GFX_SPIELER1 + id - TOOL_CTRL_ID_PLAYER_1,
2285 &deco_pixmap, &deco_x, &deco_y);
2286 deco_xpos = (toolbutton_info[i].width - MINI_TILEX) / 2;
2287 deco_ypos = (toolbutton_info[i].height - MINI_TILEY) / 2;
2290 gi = CreateGadget(GDI_CUSTOM_ID, id,
2291 GDI_INFO_TEXT, toolbutton_info[i].infotext,
2292 GDI_X, DX + toolbutton_info[i].x,
2293 GDI_Y, DY + toolbutton_info[i].y,
2294 GDI_WIDTH, toolbutton_info[i].width,
2295 GDI_HEIGHT, toolbutton_info[i].height,
2296 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
2297 GDI_STATE, GD_BUTTON_UNPRESSED,
2298 GDI_DESIGN_UNPRESSED, gd_pixmap, gd_x1, gd_y,
2299 GDI_DESIGN_PRESSED, gd_pixmap, gd_x2, gd_y,
2300 GDI_DECORATION_DESIGN, deco_pixmap, deco_x, deco_y,
2301 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
2302 GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
2303 GDI_DECORATION_SHIFTING, 1, 1,
2304 GDI_EVENT_MASK, event_mask,
2305 GDI_CALLBACK_ACTION, HandleToolButtons,
2306 GDI_CALLBACK_INFO, DoNotDisplayInfoText,
2310 Error(ERR_EXIT, "cannot create gadget");
2312 tool_gadget[id] = gi;
2316 static void UnmapToolButtons()
2320 for (i=0; i<NUM_TOOL_BUTTONS; i++)
2321 UnmapGadget(tool_gadget[i]);
2324 static void HandleToolButtons(struct GadgetInfo *gi)
2326 request_gadget_id = gi->custom_id;
2329 int el2gfx(int element)
2333 case EL_LEERRAUM: return -1;
2334 case EL_ERDREICH: return GFX_ERDREICH;
2335 case EL_MAUERWERK: return GFX_MAUERWERK;
2336 case EL_FELSBODEN: return GFX_FELSBODEN;
2337 case EL_FELSBROCKEN: return GFX_FELSBROCKEN;
2338 case EL_SCHLUESSEL: return GFX_SCHLUESSEL;
2339 case EL_EDELSTEIN: return GFX_EDELSTEIN;
2340 case EL_AUSGANG_ZU: return GFX_AUSGANG_ZU;
2341 case EL_AUSGANG_ACT: return GFX_AUSGANG_ACT;
2342 case EL_AUSGANG_AUF: return GFX_AUSGANG_AUF;
2343 case EL_SPIELFIGUR: return GFX_SPIELFIGUR;
2344 case EL_SPIELER1: return GFX_SPIELER1;
2345 case EL_SPIELER2: return GFX_SPIELER2;
2346 case EL_SPIELER3: return GFX_SPIELER3;
2347 case EL_SPIELER4: return GFX_SPIELER4;
2348 case EL_KAEFER: return GFX_KAEFER;
2349 case EL_KAEFER_R: return GFX_KAEFER_R;
2350 case EL_KAEFER_O: return GFX_KAEFER_O;
2351 case EL_KAEFER_L: return GFX_KAEFER_L;
2352 case EL_KAEFER_U: return GFX_KAEFER_U;
2353 case EL_FLIEGER: return GFX_FLIEGER;
2354 case EL_FLIEGER_R: return GFX_FLIEGER_R;
2355 case EL_FLIEGER_O: return GFX_FLIEGER_O;
2356 case EL_FLIEGER_L: return GFX_FLIEGER_L;
2357 case EL_FLIEGER_U: return GFX_FLIEGER_U;
2358 case EL_BUTTERFLY: return GFX_BUTTERFLY;
2359 case EL_BUTTERFLY_R: return GFX_BUTTERFLY_R;
2360 case EL_BUTTERFLY_O: return GFX_BUTTERFLY_O;
2361 case EL_BUTTERFLY_L: return GFX_BUTTERFLY_L;
2362 case EL_BUTTERFLY_U: return GFX_BUTTERFLY_U;
2363 case EL_FIREFLY: return GFX_FIREFLY;
2364 case EL_FIREFLY_R: return GFX_FIREFLY_R;
2365 case EL_FIREFLY_O: return GFX_FIREFLY_O;
2366 case EL_FIREFLY_L: return GFX_FIREFLY_L;
2367 case EL_FIREFLY_U: return GFX_FIREFLY_U;
2368 case EL_MAMPFER: return GFX_MAMPFER;
2369 case EL_ROBOT: return GFX_ROBOT;
2370 case EL_BETON: return GFX_BETON;
2371 case EL_DIAMANT: return GFX_DIAMANT;
2372 case EL_MORAST_LEER: return GFX_MORAST_LEER;
2373 case EL_MORAST_VOLL: return GFX_MORAST_VOLL;
2374 case EL_TROPFEN: return GFX_TROPFEN;
2375 case EL_BOMBE: return GFX_BOMBE;
2376 case EL_SIEB_INAKTIV: return GFX_SIEB_INAKTIV;
2377 case EL_SIEB_LEER: return GFX_SIEB_LEER;
2378 case EL_SIEB_VOLL: return GFX_SIEB_VOLL;
2379 case EL_SIEB_TOT: return GFX_SIEB_TOT;
2380 case EL_SALZSAEURE: return GFX_SALZSAEURE;
2381 case EL_AMOEBE_TOT: return GFX_AMOEBE_TOT;
2382 case EL_AMOEBE_NASS: return GFX_AMOEBE_NASS;
2383 case EL_AMOEBE_NORM: return GFX_AMOEBE_NORM;
2384 case EL_AMOEBE_VOLL: return GFX_AMOEBE_VOLL;
2385 case EL_AMOEBE_BD: return GFX_AMOEBE_BD;
2386 case EL_AMOEBA2DIAM: return GFX_AMOEBA2DIAM;
2387 case EL_KOKOSNUSS: return GFX_KOKOSNUSS;
2388 case EL_LIFE: return GFX_LIFE;
2389 case EL_LIFE_ASYNC: return GFX_LIFE_ASYNC;
2390 case EL_DYNAMITE_ACTIVE: return GFX_DYNAMIT;
2391 case EL_BADEWANNE: return GFX_BADEWANNE;
2392 case EL_BADEWANNE1: return GFX_BADEWANNE1;
2393 case EL_BADEWANNE2: return GFX_BADEWANNE2;
2394 case EL_BADEWANNE3: return GFX_BADEWANNE3;
2395 case EL_BADEWANNE4: return GFX_BADEWANNE4;
2396 case EL_BADEWANNE5: return GFX_BADEWANNE5;
2397 case EL_ABLENK_AUS: return GFX_ABLENK_AUS;
2398 case EL_ABLENK_EIN: return GFX_ABLENK_EIN;
2399 case EL_SCHLUESSEL1: return GFX_SCHLUESSEL1;
2400 case EL_SCHLUESSEL2: return GFX_SCHLUESSEL2;
2401 case EL_SCHLUESSEL3: return GFX_SCHLUESSEL3;
2402 case EL_SCHLUESSEL4: return GFX_SCHLUESSEL4;
2403 case EL_PFORTE1: return GFX_PFORTE1;
2404 case EL_PFORTE2: return GFX_PFORTE2;
2405 case EL_PFORTE3: return GFX_PFORTE3;
2406 case EL_PFORTE4: return GFX_PFORTE4;
2407 case EL_PFORTE1X: return GFX_PFORTE1X;
2408 case EL_PFORTE2X: return GFX_PFORTE2X;
2409 case EL_PFORTE3X: return GFX_PFORTE3X;
2410 case EL_PFORTE4X: return GFX_PFORTE4X;
2411 case EL_DYNAMITE_INACTIVE: return GFX_DYNAMIT_AUS;
2412 case EL_PACMAN: return GFX_PACMAN;
2413 case EL_PACMAN_R: return GFX_PACMAN_R;
2414 case EL_PACMAN_O: return GFX_PACMAN_O;
2415 case EL_PACMAN_L: return GFX_PACMAN_L;
2416 case EL_PACMAN_U: return GFX_PACMAN_U;
2417 case EL_UNSICHTBAR: return GFX_UNSICHTBAR;
2418 case EL_ERZ_EDEL: return GFX_ERZ_EDEL;
2419 case EL_ERZ_DIAM: return GFX_ERZ_DIAM;
2420 case EL_BIRNE_AUS: return GFX_BIRNE_AUS;
2421 case EL_BIRNE_EIN: return GFX_BIRNE_EIN;
2422 case EL_ZEIT_VOLL: return GFX_ZEIT_VOLL;
2423 case EL_ZEIT_LEER: return GFX_ZEIT_LEER;
2424 case EL_MAUER_LEBT: return GFX_MAUER_LEBT;
2425 case EL_MAUER_X: return GFX_MAUER_X;
2426 case EL_MAUER_Y: return GFX_MAUER_Y;
2427 case EL_MAUER_XY: return GFX_MAUER_XY;
2428 case EL_EDELSTEIN_BD: return GFX_EDELSTEIN_BD;
2429 case EL_EDELSTEIN_GELB: return GFX_EDELSTEIN_GELB;
2430 case EL_EDELSTEIN_ROT: return GFX_EDELSTEIN_ROT;
2431 case EL_EDELSTEIN_LILA: return GFX_EDELSTEIN_LILA;
2432 case EL_ERZ_EDEL_BD: return GFX_ERZ_EDEL_BD;
2433 case EL_ERZ_EDEL_GELB: return GFX_ERZ_EDEL_GELB;
2434 case EL_ERZ_EDEL_ROT: return GFX_ERZ_EDEL_ROT;
2435 case EL_ERZ_EDEL_LILA: return GFX_ERZ_EDEL_LILA;
2436 case EL_MAMPFER2: return GFX_MAMPFER2;
2437 case EL_SIEB2_INAKTIV: return GFX_SIEB2_INAKTIV;
2438 case EL_SIEB2_LEER: return GFX_SIEB2_LEER;
2439 case EL_SIEB2_VOLL: return GFX_SIEB2_VOLL;
2440 case EL_SIEB2_TOT: return GFX_SIEB2_TOT;
2441 case EL_DYNABOMB_ACTIVE_1: return GFX_DYNABOMB;
2442 case EL_DYNABOMB_ACTIVE_2: return GFX_DYNABOMB;
2443 case EL_DYNABOMB_ACTIVE_3: return GFX_DYNABOMB;
2444 case EL_DYNABOMB_ACTIVE_4: return GFX_DYNABOMB;
2445 case EL_DYNABOMB_NR: return GFX_DYNABOMB_NR;
2446 case EL_DYNABOMB_SZ: return GFX_DYNABOMB_SZ;
2447 case EL_DYNABOMB_XL: return GFX_DYNABOMB_XL;
2448 case EL_SOKOBAN_OBJEKT: return GFX_SOKOBAN_OBJEKT;
2449 case EL_SOKOBAN_FELD_LEER: return GFX_SOKOBAN_FELD_LEER;
2450 case EL_SOKOBAN_FELD_VOLL: return GFX_SOKOBAN_FELD_VOLL;
2451 case EL_MAULWURF: return GFX_MAULWURF;
2452 case EL_PINGUIN: return GFX_PINGUIN;
2453 case EL_SCHWEIN: return GFX_SCHWEIN;
2454 case EL_DRACHE: return GFX_DRACHE;
2455 case EL_SONDE: return GFX_SONDE;
2456 case EL_PFEIL_L: return GFX_PFEIL_L;
2457 case EL_PFEIL_R: return GFX_PFEIL_R;
2458 case EL_PFEIL_O: return GFX_PFEIL_O;
2459 case EL_PFEIL_U: return GFX_PFEIL_U;
2460 case EL_SPEED_PILL: return GFX_SPEED_PILL;
2461 case EL_SP_TERMINAL_ACTIVE: return GFX_SP_TERMINAL;
2462 case EL_SP_BUG_ACTIVE: return GFX_SP_BUG_ACTIVE;
2463 case EL_SP_ZONK: return GFX_SP_ZONK;
2464 /* ^^^^^^^^^^ non-standard position in supaplex graphic set! */
2465 case EL_INVISIBLE_STEEL: return GFX_INVISIBLE_STEEL;
2466 case EL_BLACK_ORB: return GFX_BLACK_ORB;
2467 case EL_EM_GATE_1: return GFX_EM_GATE_1;
2468 case EL_EM_GATE_2: return GFX_EM_GATE_2;
2469 case EL_EM_GATE_3: return GFX_EM_GATE_3;
2470 case EL_EM_GATE_4: return GFX_EM_GATE_4;
2471 case EL_EM_GATE_1X: return GFX_EM_GATE_1X;
2472 case EL_EM_GATE_2X: return GFX_EM_GATE_2X;
2473 case EL_EM_GATE_3X: return GFX_EM_GATE_3X;
2474 case EL_EM_GATE_4X: return GFX_EM_GATE_4X;
2475 case EL_EM_KEY_1_FILE: return GFX_EM_KEY_1;
2476 case EL_EM_KEY_2_FILE: return GFX_EM_KEY_2;
2477 case EL_EM_KEY_3_FILE: return GFX_EM_KEY_3;
2478 case EL_EM_KEY_4_FILE: return GFX_EM_KEY_4;
2479 case EL_EM_KEY_1: return GFX_EM_KEY_1;
2480 case EL_EM_KEY_2: return GFX_EM_KEY_2;
2481 case EL_EM_KEY_3: return GFX_EM_KEY_3;
2482 case EL_EM_KEY_4: return GFX_EM_KEY_4;
2483 case EL_PEARL: return GFX_PEARL;
2484 case EL_CRYSTAL: return GFX_CRYSTAL;
2485 case EL_WALL_PEARL: return GFX_WALL_PEARL;
2486 case EL_WALL_CRYSTAL: return GFX_WALL_CRYSTAL;
2487 case EL_DOOR_WHITE: return GFX_DOOR_WHITE;
2488 case EL_DOOR_WHITE_GRAY: return GFX_DOOR_WHITE_GRAY;
2489 case EL_KEY_WHITE: return GFX_KEY_WHITE;
2490 case EL_FORCE_FIELD: return GFX_FORCE_FIELD;
2491 case EL_EXTRA_TIME: return GFX_EXTRA_TIME;
2492 case EL_SWITCHGATE_OPEN: return GFX_SWITCHGATE_OPEN;
2493 case EL_SWITCHGATE_CLOSED: return GFX_SWITCHGATE_CLOSED;
2494 case EL_SWITCHGATE_SWITCH_1:return GFX_SWITCHGATE_SWITCH_1;
2495 case EL_SWITCHGATE_SWITCH_2:return GFX_SWITCHGATE_SWITCH_2;
2496 case EL_TIME_GATE: return GFX_TIME_GATE;
2497 case EL_TIME_GATE_WHEEL: return GFX_TIME_GATE_WHEEL;
2498 case EL_BELT1_LEFT: return GFX_BELT1_LEFT;
2499 case EL_BELT1_MIDDLE: return GFX_BELT1_MIDDLE;
2500 case EL_BELT1_RIGHT: return GFX_BELT1_RIGHT;
2501 case EL_BELT1_SWITCH_L: return GFX_BELT1_SWITCH_L;
2502 case EL_BELT1_SWITCH_M: return GFX_BELT1_SWITCH_M;
2503 case EL_BELT1_SWITCH_R: return GFX_BELT1_SWITCH_R;
2504 case EL_BELT2_LEFT: return GFX_BELT2_LEFT;
2505 case EL_BELT2_MIDDLE: return GFX_BELT2_MIDDLE;
2506 case EL_BELT2_RIGHT: return GFX_BELT2_RIGHT;
2507 case EL_BELT2_SWITCH_L: return GFX_BELT2_SWITCH_L;
2508 case EL_BELT2_SWITCH_M: return GFX_BELT2_SWITCH_M;
2509 case EL_BELT2_SWITCH_R: return GFX_BELT2_SWITCH_R;
2510 case EL_BELT3_LEFT: return GFX_BELT3_LEFT;
2511 case EL_BELT3_MIDDLE: return GFX_BELT3_MIDDLE;
2512 case EL_BELT3_RIGHT: return GFX_BELT3_RIGHT;
2513 case EL_BELT3_SWITCH_L: return GFX_BELT3_SWITCH_L;
2514 case EL_BELT3_SWITCH_M: return GFX_BELT3_SWITCH_M;
2515 case EL_BELT3_SWITCH_R: return GFX_BELT3_SWITCH_R;
2516 case EL_BELT4_LEFT: return GFX_BELT4_LEFT;
2517 case EL_BELT4_MIDDLE: return GFX_BELT4_MIDDLE;
2518 case EL_BELT4_RIGHT: return GFX_BELT4_RIGHT;
2519 case EL_BELT4_SWITCH_L: return GFX_BELT4_SWITCH_L;
2520 case EL_BELT4_SWITCH_M: return GFX_BELT4_SWITCH_M;
2521 case EL_BELT4_SWITCH_R: return GFX_BELT4_SWITCH_R;
2522 case EL_LANDMINE: return GFX_LANDMINE;
2523 case EL_ENVELOPE: return GFX_ENVELOPE;
2524 case EL_LIGHT_SWITCH_OFF: return GFX_LIGHT_SWITCH_OFF;
2525 case EL_LIGHT_SWITCH_ON: return GFX_LIGHT_SWITCH_ON;
2526 case EL_SIGN_EXCLAMATION: return GFX_SIGN_EXCLAMATION;
2527 case EL_SIGN_RADIOACTIVITY: return GFX_SIGN_RADIOACTIVITY;
2528 case EL_SIGN_STOP: return GFX_SIGN_STOP;
2529 case EL_SIGN_WHEELCHAIR: return GFX_SIGN_WHEELCHAIR;
2530 case EL_SIGN_PARKING: return GFX_SIGN_PARKING;
2531 case EL_SIGN_ONEWAY: return GFX_SIGN_ONEWAY;
2532 case EL_SIGN_HEART: return GFX_SIGN_HEART;
2533 case EL_SIGN_TRIANGLE: return GFX_SIGN_TRIANGLE;
2534 case EL_SIGN_ROUND: return GFX_SIGN_ROUND;
2535 case EL_SIGN_EXIT: return GFX_SIGN_EXIT;
2536 case EL_SIGN_YINYANG: return GFX_SIGN_YINYANG;
2537 case EL_SIGN_OTHER: return GFX_SIGN_OTHER;
2538 case EL_MOLE_LEFT: return GFX_MOLE_LEFT;
2539 case EL_MOLE_RIGHT: return GFX_MOLE_RIGHT;
2540 case EL_MOLE_UP: return GFX_MOLE_UP;
2541 case EL_MOLE_DOWN: return GFX_MOLE_DOWN;
2542 case EL_STEEL_SLANTED: return GFX_STEEL_SLANTED;
2543 case EL_SAND_INVISIBLE: return GFX_SAND_INVISIBLE;
2547 if (IS_CHAR(element))
2548 return GFX_CHAR_START + (element - EL_CHAR_START);
2549 else if (element >= EL_SP_START && element <= EL_SP_END)
2551 int nr_element = element - EL_SP_START;
2552 int gfx_per_line = 8;
2554 (nr_element / gfx_per_line) * SP_PER_LINE +
2555 (nr_element % gfx_per_line);
2557 return GFX_START_ROCKSSP + nr_graphic;