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 (element == EL_FELSBROCKEN || element == EL_SP_ZONK)
1122 graphic += (4 - phase4) % 4;
1123 else if (dir == MV_RIGHT)
1126 graphic += phase2 * 2;
1128 else if (element != EL_SP_INFOTRON)
1131 else if (element == EL_SIEB_LEER || element == EL_SIEB2_LEER ||
1132 element == EL_SIEB_VOLL || element == EL_SIEB2_VOLL)
1134 graphic += 3 + getGraphicAnimationPhase(4, 4, ANIM_REVERSE);
1136 else if (IS_AMOEBOID(element))
1138 graphic = (element == EL_AMOEBE_TOT ? GFX_AMOEBE_TOT : GFX_AMOEBE_LEBT);
1139 graphic += (x + 2 * y + 4) % 4;
1141 else if (element == EL_MAUER_LEBT)
1143 boolean links_massiv = FALSE, rechts_massiv = FALSE;
1145 if (!IN_LEV_FIELD(ux-1, uy) || IS_MAUER(Feld[ux-1][uy]))
1146 links_massiv = TRUE;
1147 if (!IN_LEV_FIELD(ux+1, uy) || IS_MAUER(Feld[ux+1][uy]))
1148 rechts_massiv = TRUE;
1150 if (links_massiv && rechts_massiv)
1151 graphic = GFX_MAUERWERK;
1152 else if (links_massiv)
1153 graphic = GFX_MAUER_R;
1154 else if (rechts_massiv)
1155 graphic = GFX_MAUER_L;
1159 DrawGraphicShifted(x, y, dx, dy, graphic, cut_mode, mask_mode);
1160 else if (mask_mode == USE_MASKING)
1161 DrawGraphicThruMask(x, y, graphic);
1163 DrawGraphic(x, y, graphic);
1166 void DrawLevelElementExt(int x, int y, int dx, int dy, int element,
1167 int cut_mode, int mask_mode)
1169 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1170 DrawScreenElementExt(SCREENX(x), SCREENY(y), dx, dy, element,
1171 cut_mode, mask_mode);
1174 void DrawScreenElementShifted(int x, int y, int dx, int dy, int element,
1177 DrawScreenElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1180 void DrawLevelElementShifted(int x, int y, int dx, int dy, int element,
1183 DrawLevelElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1186 void DrawScreenElementThruMask(int x, int y, int element)
1188 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1191 void DrawLevelElementThruMask(int x, int y, int element)
1193 DrawLevelElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1196 void DrawLevelFieldThruMask(int x, int y)
1198 DrawLevelElementExt(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
1201 void ErdreichAnbroeckeln(int x, int y)
1203 int i, width, height, cx,cy;
1204 int ux = LEVELX(x), uy = LEVELY(y);
1205 int element, graphic;
1207 static int xy[4][2] =
1215 if (!IN_LEV_FIELD(ux, uy))
1218 element = Feld[ux][uy];
1220 if (element == EL_ERDREICH)
1222 if (!IN_SCR_FIELD(x, y))
1225 graphic = GFX_ERDENRAND;
1231 uxx = ux + xy[i][0];
1232 uyy = uy + xy[i][1];
1233 if (!IN_LEV_FIELD(uxx, uyy))
1236 element = Feld[uxx][uyy];
1238 if (element == EL_ERDREICH)
1241 if (i == 1 || i == 2)
1245 cx = (i == 2 ? TILEX - snip : 0);
1253 cy = (i == 3 ? TILEY - snip : 0);
1256 XCopyArea(display, pix[PIX_BACK], drawto_field, gc,
1257 SX + (graphic % GFX_PER_LINE) * TILEX + cx,
1258 SY + (graphic / GFX_PER_LINE) * TILEY + cy,
1259 width, height, FX + x * TILEX + cx, FY + y * TILEY + cy);
1262 MarkTileDirty(x, y);
1266 graphic = GFX_ERDENRAND;
1270 int xx, yy, uxx, uyy;
1274 uxx = ux + xy[i][0];
1275 uyy = uy + xy[i][1];
1277 if (!IN_LEV_FIELD(uxx, uyy) || Feld[uxx][uyy] != EL_ERDREICH ||
1278 !IN_SCR_FIELD(xx, yy))
1281 if (i == 1 || i == 2)
1285 cx = (i == 1 ? TILEX - snip : 0);
1293 cy = (i==0 ? TILEY-snip : 0);
1296 XCopyArea(display, pix[PIX_BACK], drawto_field, gc,
1297 SX + (graphic % GFX_PER_LINE) * TILEX + cx,
1298 SY + (graphic / GFX_PER_LINE) * TILEY + cy,
1299 width, height, FX + xx * TILEX + cx, FY + yy * TILEY + cy);
1301 MarkTileDirty(xx, yy);
1306 void DrawScreenElement(int x, int y, int element)
1308 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
1309 ErdreichAnbroeckeln(x, y);
1312 void DrawLevelElement(int x, int y, int element)
1314 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1315 DrawScreenElement(SCREENX(x), SCREENY(y), element);
1318 void DrawScreenField(int x, int y)
1320 int ux = LEVELX(x), uy = LEVELY(y);
1323 if (!IN_LEV_FIELD(ux, uy))
1325 if (ux < -1 || ux > lev_fieldx || uy < -1 || uy > lev_fieldy)
1326 element = EL_LEERRAUM;
1328 element = BorderElement;
1330 DrawScreenElement(x, y, element);
1334 element = Feld[ux][uy];
1336 if (IS_MOVING(ux, uy))
1338 int horiz_move = (MovDir[ux][uy] == MV_LEFT || MovDir[ux][uy] == MV_RIGHT);
1339 boolean cut_mode = NO_CUTTING;
1341 if (Store[ux][uy] == EL_MORAST_LEER ||
1342 Store[ux][uy] == EL_SIEB_LEER ||
1343 Store[ux][uy] == EL_SIEB2_LEER ||
1344 Store[ux][uy] == EL_AMOEBE_NASS)
1345 cut_mode = CUT_ABOVE;
1346 else if (Store[ux][uy] == EL_MORAST_VOLL ||
1347 Store[ux][uy] == EL_SIEB_VOLL ||
1348 Store[ux][uy] == EL_SIEB2_VOLL)
1349 cut_mode = CUT_BELOW;
1351 if (cut_mode == CUT_ABOVE)
1352 DrawScreenElementShifted(x, y, 0, 0, Store[ux][uy], NO_CUTTING);
1354 DrawScreenElement(x, y, EL_LEERRAUM);
1357 DrawScreenElementShifted(x, y, MovPos[ux][uy], 0, element, NO_CUTTING);
1359 DrawScreenElementShifted(x, y, 0, MovPos[ux][uy], element, cut_mode);
1361 if (Store[ux][uy] == EL_SALZSAEURE)
1362 DrawLevelElementThruMask(ux, uy + 1, EL_SALZSAEURE);
1364 else if (IS_BLOCKED(ux, uy))
1369 boolean cut_mode = NO_CUTTING;
1371 Blocked2Moving(ux, uy, &oldx, &oldy);
1374 horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
1375 MovDir[oldx][oldy] == MV_RIGHT);
1377 if (Store[oldx][oldy] == EL_MORAST_LEER ||
1378 Store[oldx][oldy] == EL_SIEB_LEER ||
1379 Store[oldx][oldy] == EL_SIEB2_LEER ||
1380 Store[oldx][oldy] == EL_AMOEBE_NASS)
1381 cut_mode = CUT_ABOVE;
1383 DrawScreenElement(x, y, EL_LEERRAUM);
1384 element = Feld[oldx][oldy];
1387 DrawScreenElementShifted(sx,sy, MovPos[oldx][oldy],0,element,NO_CUTTING);
1389 DrawScreenElementShifted(sx,sy, 0,MovPos[oldx][oldy],element,cut_mode);
1391 else if (IS_DRAWABLE(element))
1392 DrawScreenElement(x, y, element);
1394 DrawScreenElement(x, y, EL_LEERRAUM);
1397 void DrawLevelField(int x, int y)
1399 if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1400 DrawScreenField(SCREENX(x), SCREENY(y));
1401 else if (IS_MOVING(x, y))
1405 Moving2Blocked(x, y, &newx, &newy);
1406 if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
1407 DrawScreenField(SCREENX(newx), SCREENY(newy));
1409 else if (IS_BLOCKED(x, y))
1413 Blocked2Moving(x, y, &oldx, &oldy);
1414 if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
1415 DrawScreenField(SCREENX(oldx), SCREENY(oldy));
1419 void DrawMiniElement(int x, int y, int element)
1425 DrawMiniGraphic(x, y, -1);
1429 graphic = el2gfx(element);
1430 DrawMiniGraphic(x, y, graphic);
1433 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
1435 int x = sx + scroll_x, y = sy + scroll_y;
1437 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
1438 DrawMiniElement(sx, sy, EL_LEERRAUM);
1439 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
1440 DrawMiniElement(sx, sy, Feld[x][y]);
1443 int steel_type, steel_position;
1446 { GFX_VSTEEL_UPPER_LEFT, GFX_ISTEEL_UPPER_LEFT },
1447 { GFX_VSTEEL_UPPER_RIGHT, GFX_ISTEEL_UPPER_RIGHT },
1448 { GFX_VSTEEL_LOWER_LEFT, GFX_ISTEEL_LOWER_LEFT },
1449 { GFX_VSTEEL_LOWER_RIGHT, GFX_ISTEEL_LOWER_RIGHT },
1450 { GFX_VSTEEL_VERTICAL, GFX_ISTEEL_VERTICAL },
1451 { GFX_VSTEEL_HORIZONTAL, GFX_ISTEEL_HORIZONTAL }
1454 steel_type = (BorderElement == EL_BETON ? 0 : 1);
1455 steel_position = (x == -1 && y == -1 ? 0 :
1456 x == lev_fieldx && y == -1 ? 1 :
1457 x == -1 && y == lev_fieldy ? 2 :
1458 x == lev_fieldx && y == lev_fieldy ? 3 :
1459 x == -1 || x == lev_fieldx ? 4 :
1460 y == -1 || y == lev_fieldy ? 5 : -1);
1462 if (steel_position != -1)
1463 DrawMiniGraphic(sx, sy, border[steel_position][steel_type]);
1467 void DrawMicroElement(int xpos, int ypos, int element)
1471 if (element == EL_LEERRAUM)
1474 graphic = el2gfx(element);
1476 if (graphic >= GFX_START_ROCKSSP && graphic <= GFX_END_ROCKSSP)
1478 graphic -= GFX_START_ROCKSSP;
1479 graphic -= ((graphic / SP_PER_LINE) * SP_PER_LINE) / 2;
1480 XCopyArea(display, pix[PIX_SP], drawto, gc,
1481 MICRO_SP_STARTX + (graphic % MICRO_SP_PER_LINE) *MICRO_TILEX,
1482 MICRO_SP_STARTY + (graphic / MICRO_SP_PER_LINE) *MICRO_TILEY,
1483 MICRO_TILEX, MICRO_TILEY, xpos, ypos);
1485 else if (graphic >= GFX_START_ROCKSDC && graphic <= GFX_END_ROCKSDC)
1487 graphic -= GFX_START_ROCKSDC;
1488 graphic -= ((graphic / DC_PER_LINE) * DC_PER_LINE) / 2;
1489 XCopyArea(display, pix[PIX_DC], drawto, gc,
1490 MICRO_DC_STARTX + (graphic % MICRO_DC_PER_LINE) *MICRO_TILEX,
1491 MICRO_DC_STARTY + (graphic / MICRO_DC_PER_LINE) *MICRO_TILEY,
1492 MICRO_TILEX, MICRO_TILEY, xpos, ypos);
1495 XCopyArea(display, pix[PIX_BACK], drawto, gc,
1496 MICRO_GFX_STARTX + (graphic % MICRO_GFX_PER_LINE) * MICRO_TILEX,
1497 MICRO_GFX_STARTY + (graphic / MICRO_GFX_PER_LINE) * MICRO_TILEY,
1498 MICRO_TILEX, MICRO_TILEY, xpos, ypos);
1507 for(x=BX1; x<=BX2; x++)
1508 for(y=BY1; y<=BY2; y++)
1509 DrawScreenField(x, y);
1511 redraw_mask |= REDRAW_FIELD;
1514 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
1518 for(x=0; x<size_x; x++)
1519 for(y=0; y<size_y; y++)
1520 DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
1522 redraw_mask |= REDRAW_FIELD;
1525 static void DrawMicroLevelExt(int xpos, int ypos, int from_x, int from_y)
1529 XFillRectangle(display, drawto, gc,
1530 xpos, ypos, MICROLEV_XSIZE, MICROLEV_YSIZE);
1532 if (lev_fieldx < STD_LEV_FIELDX)
1533 xpos += (STD_LEV_FIELDX - lev_fieldx) / 2 * MICRO_TILEX;
1534 if (lev_fieldy < STD_LEV_FIELDY)
1535 ypos += (STD_LEV_FIELDY - lev_fieldy) / 2 * MICRO_TILEY;
1537 xpos += MICRO_TILEX;
1538 ypos += MICRO_TILEY;
1540 for(x=-1; x<=STD_LEV_FIELDX; x++)
1542 for(y=-1; y<=STD_LEV_FIELDY; y++)
1544 int lx = from_x + x, ly = from_y + y;
1546 if (lx >= 0 && lx < lev_fieldx && ly >= 0 && ly < lev_fieldy)
1547 DrawMicroElement(xpos + x * MICRO_TILEX, ypos + y * MICRO_TILEY,
1549 else if (lx >= -1 && lx < lev_fieldx+1 && ly >= -1 && ly < lev_fieldy+1)
1550 DrawMicroElement(xpos + x * MICRO_TILEX, ypos + y * MICRO_TILEY,
1555 redraw_mask |= REDRAW_MICROLEVEL;
1558 #define MICROLABEL_EMPTY 0
1559 #define MICROLABEL_LEVEL_NAME 1
1560 #define MICROLABEL_CREATED_BY 2
1561 #define MICROLABEL_LEVEL_AUTHOR 3
1562 #define MICROLABEL_IMPORTED_FROM 4
1563 #define MICROLABEL_LEVEL_IMPORT_INFO 5
1565 #define MAX_MICROLABEL_SIZE (SXSIZE / FONT4_XSIZE)
1567 static void DrawMicroLevelLabelExt(int mode)
1569 char label_text[MAX_MICROLABEL_SIZE + 1];
1571 XFillRectangle(display, drawto,gc,
1572 SX, MICROLABEL_YPOS, SXSIZE, FONT4_YSIZE);
1574 strncpy(label_text, (mode == MICROLABEL_LEVEL_NAME ? level.name :
1575 mode == MICROLABEL_CREATED_BY ? "created by" :
1576 mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
1577 mode == MICROLABEL_IMPORTED_FROM ? "imported from" :
1578 mode == MICROLABEL_LEVEL_IMPORT_INFO ?
1579 leveldir[leveldir_nr].imported_from : ""),
1580 MAX_MICROLABEL_SIZE);
1581 label_text[MAX_MICROLABEL_SIZE] = '\0';
1583 if (strlen(label_text) > 0)
1585 int lxpos = SX + (SXSIZE - strlen(label_text) * FONT4_XSIZE) / 2;
1586 int lypos = MICROLABEL_YPOS;
1588 DrawText(lxpos, lypos, label_text, FS_SMALL, FC_SPECIAL2);
1591 redraw_mask |= REDRAW_MICROLEVEL;
1594 void DrawMicroLevel(int xpos, int ypos, boolean restart)
1596 static unsigned long scroll_delay = 0;
1597 static unsigned long label_delay = 0;
1598 static int from_x, from_y, scroll_direction;
1599 static int label_state, label_counter;
1603 from_x = from_y = 0;
1604 scroll_direction = MV_RIGHT;
1608 DrawMicroLevelExt(xpos, ypos, from_x, from_y);
1609 DrawMicroLevelLabelExt(label_state);
1611 /* initialize delay counters */
1612 DelayReached(&scroll_delay, 0);
1613 DelayReached(&label_delay, 0);
1618 /* scroll micro level, if needed */
1619 if ((lev_fieldx > STD_LEV_FIELDX || lev_fieldy > STD_LEV_FIELDY) &&
1620 DelayReached(&scroll_delay, MICROLEVEL_SCROLL_DELAY))
1622 switch (scroll_direction)
1628 scroll_direction = MV_UP;
1632 if (from_x < lev_fieldx - STD_LEV_FIELDX)
1635 scroll_direction = MV_DOWN;
1642 scroll_direction = MV_RIGHT;
1646 if (from_y < lev_fieldy - STD_LEV_FIELDY)
1649 scroll_direction = MV_LEFT;
1656 DrawMicroLevelExt(xpos, ypos, from_x, from_y);
1659 /* redraw micro level label, if needed */
1660 if (strcmp(level.name, NAMELESS_LEVEL_NAME) != 0 &&
1661 strcmp(level.author, ANONYMOUS_NAME) != 0 &&
1662 strcmp(level.author, leveldir[leveldir_nr].name) != 0 &&
1663 DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
1665 int max_label_counter = 23;
1667 if (leveldir[leveldir_nr].imported_from != NULL)
1668 max_label_counter += 14;
1670 label_counter = (label_counter + 1) % max_label_counter;
1671 label_state = (label_counter >= 0 && label_counter <= 7 ?
1672 MICROLABEL_LEVEL_NAME :
1673 label_counter >= 9 && label_counter <= 12 ?
1674 MICROLABEL_CREATED_BY :
1675 label_counter >= 14 && label_counter <= 21 ?
1676 MICROLABEL_LEVEL_AUTHOR :
1677 label_counter >= 23 && label_counter <= 26 ?
1678 MICROLABEL_IMPORTED_FROM :
1679 label_counter >= 28 && label_counter <= 35 ?
1680 MICROLABEL_LEVEL_IMPORT_INFO : MICROLABEL_EMPTY);
1681 DrawMicroLevelLabelExt(label_state);
1685 int REQ_in_range(int x, int y)
1687 if (y > DY+249 && y < DY+278)
1689 if (x > DX+1 && x < DX+48)
1691 else if (x > DX+51 && x < DX+98)
1697 boolean Request(char *text, unsigned int req_state)
1699 int mx, my, ty, result = -1;
1700 unsigned int old_door_state;
1703 /* pause network game while waiting for request to answer */
1704 if (options.network &&
1705 game_status == PLAYING &&
1706 req_state & REQUEST_WAIT_FOR)
1707 SendToServer_PausePlaying();
1710 old_door_state = GetDoorState();
1714 CloseDoor(DOOR_CLOSE_1);
1716 /* save old door content */
1717 XCopyArea(display, pix[PIX_DB_DOOR], pix[PIX_DB_DOOR], gc,
1718 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
1719 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
1721 /* clear door drawing field */
1722 XFillRectangle(display, drawto, gc, DX, DY, DXSIZE, DYSIZE);
1724 /* write text for request */
1725 for(ty=0; ty<13; ty++)
1733 for(tl=0,tx=0; tx<7; tl++,tx++)
1736 if (!tc || tc == 32)
1747 DrawTextExt(drawto, gc,
1748 DX + 51 - (tl * 14)/2, DY + 8 + ty * 16,
1749 txt, FS_SMALL, FC_YELLOW);
1750 text += tl + (tc == 32 ? 1 : 0);
1753 if (req_state & REQ_ASK)
1755 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
1756 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
1758 else if (req_state & REQ_CONFIRM)
1760 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
1762 else if (req_state & REQ_PLAYER)
1764 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
1765 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
1766 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
1767 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
1770 /* copy request gadgets to door backbuffer */
1771 XCopyArea(display, drawto, pix[PIX_DB_DOOR], gc,
1772 DX, DY, DXSIZE, DYSIZE,
1773 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
1775 OpenDoor(DOOR_OPEN_1);
1781 if (!(req_state & REQUEST_WAIT_FOR))
1784 if (game_status != MAINMENU)
1787 button_status = MB_RELEASED;
1789 request_gadget_id = -1;
1793 if (XPending(display))
1797 XNextEvent(display, &event);
1805 if (event.type == MotionNotify)
1812 if (!XQueryPointer(display, window, &root, &child,
1813 &root_x, &root_y, &win_x, &win_y, &mask))
1819 motion_status = TRUE;
1820 mx = ((XMotionEvent *) &event)->x;
1821 my = ((XMotionEvent *) &event)->y;
1825 motion_status = FALSE;
1826 mx = ((XButtonEvent *) &event)->x;
1827 my = ((XButtonEvent *) &event)->y;
1828 if (event.type==ButtonPress)
1829 button_status = ((XButtonEvent *) &event)->button;
1831 button_status = MB_RELEASED;
1834 /* this sets 'request_gadget_id' */
1835 HandleGadgets(mx, my, button_status);
1837 switch(request_gadget_id)
1839 case TOOL_CTRL_ID_YES:
1842 case TOOL_CTRL_ID_NO:
1845 case TOOL_CTRL_ID_CONFIRM:
1846 result = TRUE | FALSE;
1849 case TOOL_CTRL_ID_PLAYER_1:
1852 case TOOL_CTRL_ID_PLAYER_2:
1855 case TOOL_CTRL_ID_PLAYER_3:
1858 case TOOL_CTRL_ID_PLAYER_4:
1870 switch(XLookupKeysym((XKeyEvent *)&event,
1871 ((XKeyEvent *)&event)->state))
1884 if (req_state & REQ_PLAYER)
1889 key_joystick_mapping = 0;
1893 HandleOtherEvents(&event);
1897 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
1899 int joy = AnyJoystick();
1901 if (joy & JOY_BUTTON_1)
1903 else if (joy & JOY_BUTTON_2)
1909 /* don't eat all CPU time */
1913 if (game_status != MAINMENU)
1918 if (!(req_state & REQ_STAY_OPEN))
1920 CloseDoor(DOOR_CLOSE_1);
1922 if (!(req_state & REQ_STAY_CLOSED) && (old_door_state & DOOR_OPEN_1))
1924 XCopyArea(display,pix[PIX_DB_DOOR],pix[PIX_DB_DOOR],gc,
1925 DOOR_GFX_PAGEX2,DOOR_GFX_PAGEY1, DXSIZE,DYSIZE,
1926 DOOR_GFX_PAGEX1,DOOR_GFX_PAGEY1);
1927 OpenDoor(DOOR_OPEN_1);
1934 /* continue network game after request */
1935 if (options.network &&
1936 game_status == PLAYING &&
1937 req_state & REQUEST_WAIT_FOR)
1938 SendToServer_ContinuePlaying();
1944 unsigned int OpenDoor(unsigned int door_state)
1946 unsigned int new_door_state;
1948 if (door_state & DOOR_COPY_BACK)
1950 XCopyArea(display, pix[PIX_DB_DOOR], pix[PIX_DB_DOOR], gc,
1951 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE + VYSIZE,
1952 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
1953 door_state &= ~DOOR_COPY_BACK;
1956 new_door_state = MoveDoor(door_state);
1958 return(new_door_state);
1961 unsigned int CloseDoor(unsigned int door_state)
1963 unsigned int new_door_state;
1965 XCopyArea(display, backbuffer, pix[PIX_DB_DOOR], gc,
1966 DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
1967 XCopyArea(display, backbuffer, pix[PIX_DB_DOOR], gc,
1968 VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
1970 new_door_state = MoveDoor(door_state);
1972 return(new_door_state);
1975 unsigned int GetDoorState()
1977 return(MoveDoor(DOOR_GET_STATE));
1980 unsigned int MoveDoor(unsigned int door_state)
1982 static int door1 = DOOR_OPEN_1;
1983 static int door2 = DOOR_CLOSE_2;
1984 static unsigned long door_delay = 0;
1985 int x, start, stepsize = 2;
1986 unsigned long door_delay_value = stepsize * 5;
1988 if (door_state == DOOR_GET_STATE)
1989 return(door1 | door2);
1991 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
1992 door_state &= ~DOOR_OPEN_1;
1993 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
1994 door_state &= ~DOOR_CLOSE_1;
1995 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
1996 door_state &= ~DOOR_OPEN_2;
1997 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
1998 door_state &= ~DOOR_CLOSE_2;
2000 if (setup.quick_doors)
2003 door_delay_value = 0;
2004 StopSound(SND_OEFFNEN);
2007 if (door_state & DOOR_ACTION)
2009 if (!(door_state & DOOR_NO_DELAY))
2010 PlaySoundStereo(SND_OEFFNEN, PSND_MAX_RIGHT);
2012 start = ((door_state & DOOR_NO_DELAY) ? DXSIZE : 0);
2014 for(x=start; x<=DXSIZE; x+=stepsize)
2016 WaitUntilDelayReached(&door_delay, door_delay_value);
2018 if (door_state & DOOR_ACTION_1)
2020 int i = (door_state & DOOR_OPEN_1 ? DXSIZE-x : x);
2021 int j = (DXSIZE - i) / 3;
2023 XCopyArea(display, pix[PIX_DB_DOOR], drawto, gc,
2024 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + i/2,
2025 DXSIZE,DYSIZE - i/2, DX, DY);
2027 XFillRectangle(display, drawto, gc, DX, DY + DYSIZE - i/2, DXSIZE,i/2);
2029 XSetClipOrigin(display, clip_gc[PIX_DOOR],
2030 DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2031 XCopyArea(display, pix[PIX_DOOR], drawto,clip_gc[PIX_DOOR],
2032 DXSIZE, DOOR_GFX_PAGEY1, i, 77, DX + DXSIZE - i, DY + j);
2033 XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
2034 DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63, DX + DXSIZE - i,
2036 XSetClipOrigin(display, clip_gc[PIX_DOOR],
2037 DX - DXSIZE + i, DY - (DOOR_GFX_PAGEY1 + j));
2038 XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
2039 DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j, DX, DY);
2040 XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
2041 DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63, DX, DY + 140 - j);
2043 XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
2044 DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
2046 XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
2047 DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
2049 XSetClipOrigin(display, clip_gc[PIX_DOOR],
2050 DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2051 XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
2052 DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
2053 DX + DXSIZE - i, DY + 77 + j);
2054 XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
2055 DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
2056 DX + DXSIZE - i, DY + 203 + j);
2058 redraw_mask |= REDRAW_DOOR_1;
2061 if (door_state & DOOR_ACTION_2)
2063 int i = (door_state & DOOR_OPEN_2 ? VXSIZE - x : x);
2064 int j = (VXSIZE - i) / 3;
2066 XCopyArea(display, pix[PIX_DB_DOOR], drawto, gc,
2067 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + i/2,
2068 VXSIZE, VYSIZE - i/2, VX, VY);
2070 XFillRectangle(display, drawto, gc, VX, VY + VYSIZE-i/2, VXSIZE, i/2);
2072 XSetClipOrigin(display, clip_gc[PIX_DOOR],
2073 VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2074 XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
2075 VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2, VX + VXSIZE-i, VY+j);
2076 XSetClipOrigin(display, clip_gc[PIX_DOOR],
2077 VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
2078 XCopyArea(display, pix[PIX_DOOR], drawto,clip_gc[PIX_DOOR],
2079 VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j, VX, VY);
2081 XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
2082 VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2, i, VYSIZE / 2,
2083 VX, VY + VYSIZE / 2 - j);
2084 XSetClipOrigin(display, clip_gc[PIX_DOOR],
2085 VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2086 XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
2087 VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2, i, VYSIZE / 2 - j,
2088 VX + VXSIZE - i, VY + VYSIZE / 2 + j);
2090 redraw_mask |= REDRAW_DOOR_2;
2095 if (game_status == MAINMENU)
2100 if (setup.quick_doors)
2101 StopSound(SND_OEFFNEN);
2103 if (door_state & DOOR_ACTION_1)
2104 door1 = door_state & DOOR_ACTION_1;
2105 if (door_state & DOOR_ACTION_2)
2106 door2 = door_state & DOOR_ACTION_2;
2108 return (door1 | door2);
2111 void DrawSpecialEditorDoor()
2113 /* draw bigger toolbox window */
2114 XCopyArea(display, pix[PIX_DOOR], drawto, gc,
2115 DOOR_GFX_PAGEX7, 0, 108, 56, EX - 4, EY - 12);
2117 redraw_mask |= REDRAW_ALL;
2120 void UndrawSpecialEditorDoor()
2122 /* draw normal tape recorder window */
2123 XCopyArea(display, pix[PIX_BACK], drawto, gc,
2124 562, 344, 108, 56, EX - 4, EY - 12);
2126 redraw_mask |= REDRAW_ALL;
2129 int ReadPixel(Drawable d, int x, int y)
2131 XImage *pixel_image;
2132 unsigned long pixel_value;
2134 pixel_image = XGetImage(display, d, x, y, 1, 1, AllPlanes, ZPixmap);
2135 pixel_value = XGetPixel(pixel_image, 0, 0);
2137 XDestroyImage(pixel_image);
2142 /* ---------- new tool button stuff ---------------------------------------- */
2144 /* graphic position values for tool buttons */
2145 #define TOOL_BUTTON_YES_XPOS 2
2146 #define TOOL_BUTTON_YES_YPOS 250
2147 #define TOOL_BUTTON_YES_GFX_YPOS 0
2148 #define TOOL_BUTTON_YES_XSIZE 46
2149 #define TOOL_BUTTON_YES_YSIZE 28
2150 #define TOOL_BUTTON_NO_XPOS 52
2151 #define TOOL_BUTTON_NO_YPOS TOOL_BUTTON_YES_YPOS
2152 #define TOOL_BUTTON_NO_GFX_YPOS TOOL_BUTTON_YES_GFX_YPOS
2153 #define TOOL_BUTTON_NO_XSIZE TOOL_BUTTON_YES_XSIZE
2154 #define TOOL_BUTTON_NO_YSIZE TOOL_BUTTON_YES_YSIZE
2155 #define TOOL_BUTTON_CONFIRM_XPOS TOOL_BUTTON_YES_XPOS
2156 #define TOOL_BUTTON_CONFIRM_YPOS TOOL_BUTTON_YES_YPOS
2157 #define TOOL_BUTTON_CONFIRM_GFX_YPOS 30
2158 #define TOOL_BUTTON_CONFIRM_XSIZE 96
2159 #define TOOL_BUTTON_CONFIRM_YSIZE TOOL_BUTTON_YES_YSIZE
2160 #define TOOL_BUTTON_PLAYER_XSIZE 30
2161 #define TOOL_BUTTON_PLAYER_YSIZE 30
2162 #define TOOL_BUTTON_PLAYER_GFX_XPOS 5
2163 #define TOOL_BUTTON_PLAYER_GFX_YPOS 185
2164 #define TOOL_BUTTON_PLAYER_XPOS (5 + TOOL_BUTTON_PLAYER_XSIZE / 2)
2165 #define TOOL_BUTTON_PLAYER_YPOS (215 - TOOL_BUTTON_PLAYER_YSIZE / 2)
2166 #define TOOL_BUTTON_PLAYER1_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2167 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2168 #define TOOL_BUTTON_PLAYER2_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2169 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2170 #define TOOL_BUTTON_PLAYER3_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2171 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2172 #define TOOL_BUTTON_PLAYER4_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2173 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2174 #define TOOL_BUTTON_PLAYER1_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2175 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2176 #define TOOL_BUTTON_PLAYER2_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2177 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2178 #define TOOL_BUTTON_PLAYER3_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2179 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2180 #define TOOL_BUTTON_PLAYER4_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2181 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2190 } toolbutton_info[NUM_TOOL_BUTTONS] =
2193 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_GFX_YPOS,
2194 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_YPOS,
2195 TOOL_BUTTON_YES_XSIZE, TOOL_BUTTON_YES_YSIZE,
2200 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_GFX_YPOS,
2201 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_YPOS,
2202 TOOL_BUTTON_NO_XSIZE, TOOL_BUTTON_NO_YSIZE,
2207 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_GFX_YPOS,
2208 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_YPOS,
2209 TOOL_BUTTON_CONFIRM_XSIZE, TOOL_BUTTON_CONFIRM_YSIZE,
2210 TOOL_CTRL_ID_CONFIRM,
2214 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2215 TOOL_BUTTON_PLAYER1_XPOS, TOOL_BUTTON_PLAYER1_YPOS,
2216 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2217 TOOL_CTRL_ID_PLAYER_1,
2221 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2222 TOOL_BUTTON_PLAYER2_XPOS, TOOL_BUTTON_PLAYER2_YPOS,
2223 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2224 TOOL_CTRL_ID_PLAYER_2,
2228 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2229 TOOL_BUTTON_PLAYER3_XPOS, TOOL_BUTTON_PLAYER3_YPOS,
2230 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2231 TOOL_CTRL_ID_PLAYER_3,
2235 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2236 TOOL_BUTTON_PLAYER4_XPOS, TOOL_BUTTON_PLAYER4_YPOS,
2237 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2238 TOOL_CTRL_ID_PLAYER_4,
2243 static void DoNotDisplayInfoText(void *ptr)
2248 void CreateToolButtons()
2252 for (i=0; i<NUM_TOOL_BUTTONS; i++)
2254 Pixmap gd_pixmap = pix[PIX_DOOR];
2255 Pixmap deco_pixmap = None;
2256 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
2257 struct GadgetInfo *gi;
2258 unsigned long event_mask;
2259 int gd_xoffset, gd_yoffset;
2260 int gd_x1, gd_x2, gd_y;
2263 event_mask = GD_EVENT_RELEASED;
2265 gd_xoffset = toolbutton_info[i].xpos;
2266 gd_yoffset = toolbutton_info[i].ypos;
2267 gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
2268 gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
2269 gd_y = DOOR_GFX_PAGEY1 + gd_yoffset;
2271 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
2273 getMiniGraphicSource(GFX_SPIELER1 + id - TOOL_CTRL_ID_PLAYER_1,
2274 &deco_pixmap, &deco_x, &deco_y);
2275 deco_xpos = (toolbutton_info[i].width - MINI_TILEX) / 2;
2276 deco_ypos = (toolbutton_info[i].height - MINI_TILEY) / 2;
2279 gi = CreateGadget(GDI_CUSTOM_ID, id,
2280 GDI_INFO_TEXT, toolbutton_info[i].infotext,
2281 GDI_X, DX + toolbutton_info[i].x,
2282 GDI_Y, DY + toolbutton_info[i].y,
2283 GDI_WIDTH, toolbutton_info[i].width,
2284 GDI_HEIGHT, toolbutton_info[i].height,
2285 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
2286 GDI_STATE, GD_BUTTON_UNPRESSED,
2287 GDI_DESIGN_UNPRESSED, gd_pixmap, gd_x1, gd_y,
2288 GDI_DESIGN_PRESSED, gd_pixmap, gd_x2, gd_y,
2289 GDI_DECORATION_DESIGN, deco_pixmap, deco_x, deco_y,
2290 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
2291 GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
2292 GDI_DECORATION_SHIFTING, 1, 1,
2293 GDI_EVENT_MASK, event_mask,
2294 GDI_CALLBACK_ACTION, HandleToolButtons,
2295 GDI_CALLBACK_INFO, DoNotDisplayInfoText,
2299 Error(ERR_EXIT, "cannot create gadget");
2301 tool_gadget[id] = gi;
2305 static void UnmapToolButtons()
2309 for (i=0; i<NUM_TOOL_BUTTONS; i++)
2310 UnmapGadget(tool_gadget[i]);
2313 static void HandleToolButtons(struct GadgetInfo *gi)
2315 request_gadget_id = gi->custom_id;
2318 int el2gfx(int element)
2322 case EL_LEERRAUM: return -1;
2323 case EL_ERDREICH: return GFX_ERDREICH;
2324 case EL_MAUERWERK: return GFX_MAUERWERK;
2325 case EL_FELSBODEN: return GFX_FELSBODEN;
2326 case EL_FELSBROCKEN: return GFX_FELSBROCKEN;
2327 case EL_SCHLUESSEL: return GFX_SCHLUESSEL;
2328 case EL_EDELSTEIN: return GFX_EDELSTEIN;
2329 case EL_AUSGANG_ZU: return GFX_AUSGANG_ZU;
2330 case EL_AUSGANG_ACT: return GFX_AUSGANG_ACT;
2331 case EL_AUSGANG_AUF: return GFX_AUSGANG_AUF;
2332 case EL_SPIELFIGUR: return GFX_SPIELFIGUR;
2333 case EL_SPIELER1: return GFX_SPIELER1;
2334 case EL_SPIELER2: return GFX_SPIELER2;
2335 case EL_SPIELER3: return GFX_SPIELER3;
2336 case EL_SPIELER4: return GFX_SPIELER4;
2337 case EL_KAEFER: return GFX_KAEFER;
2338 case EL_KAEFER_R: return GFX_KAEFER_R;
2339 case EL_KAEFER_O: return GFX_KAEFER_O;
2340 case EL_KAEFER_L: return GFX_KAEFER_L;
2341 case EL_KAEFER_U: return GFX_KAEFER_U;
2342 case EL_FLIEGER: return GFX_FLIEGER;
2343 case EL_FLIEGER_R: return GFX_FLIEGER_R;
2344 case EL_FLIEGER_O: return GFX_FLIEGER_O;
2345 case EL_FLIEGER_L: return GFX_FLIEGER_L;
2346 case EL_FLIEGER_U: return GFX_FLIEGER_U;
2347 case EL_BUTTERFLY: return GFX_BUTTERFLY;
2348 case EL_BUTTERFLY_R: return GFX_BUTTERFLY_R;
2349 case EL_BUTTERFLY_O: return GFX_BUTTERFLY_O;
2350 case EL_BUTTERFLY_L: return GFX_BUTTERFLY_L;
2351 case EL_BUTTERFLY_U: return GFX_BUTTERFLY_U;
2352 case EL_FIREFLY: return GFX_FIREFLY;
2353 case EL_FIREFLY_R: return GFX_FIREFLY_R;
2354 case EL_FIREFLY_O: return GFX_FIREFLY_O;
2355 case EL_FIREFLY_L: return GFX_FIREFLY_L;
2356 case EL_FIREFLY_U: return GFX_FIREFLY_U;
2357 case EL_MAMPFER: return GFX_MAMPFER;
2358 case EL_ROBOT: return GFX_ROBOT;
2359 case EL_BETON: return GFX_BETON;
2360 case EL_DIAMANT: return GFX_DIAMANT;
2361 case EL_MORAST_LEER: return GFX_MORAST_LEER;
2362 case EL_MORAST_VOLL: return GFX_MORAST_VOLL;
2363 case EL_TROPFEN: return GFX_TROPFEN;
2364 case EL_BOMBE: return GFX_BOMBE;
2365 case EL_SIEB_INAKTIV: return GFX_SIEB_INAKTIV;
2366 case EL_SIEB_LEER: return GFX_SIEB_LEER;
2367 case EL_SIEB_VOLL: return GFX_SIEB_VOLL;
2368 case EL_SIEB_TOT: return GFX_SIEB_TOT;
2369 case EL_SALZSAEURE: return GFX_SALZSAEURE;
2370 case EL_AMOEBE_TOT: return GFX_AMOEBE_TOT;
2371 case EL_AMOEBE_NASS: return GFX_AMOEBE_NASS;
2372 case EL_AMOEBE_NORM: return GFX_AMOEBE_NORM;
2373 case EL_AMOEBE_VOLL: return GFX_AMOEBE_VOLL;
2374 case EL_AMOEBE_BD: return GFX_AMOEBE_BD;
2375 case EL_AMOEBA2DIAM: return GFX_AMOEBA2DIAM;
2376 case EL_KOKOSNUSS: return GFX_KOKOSNUSS;
2377 case EL_LIFE: return GFX_LIFE;
2378 case EL_LIFE_ASYNC: return GFX_LIFE_ASYNC;
2379 case EL_DYNAMITE_ACTIVE: return GFX_DYNAMIT;
2380 case EL_BADEWANNE: return GFX_BADEWANNE;
2381 case EL_BADEWANNE1: return GFX_BADEWANNE1;
2382 case EL_BADEWANNE2: return GFX_BADEWANNE2;
2383 case EL_BADEWANNE3: return GFX_BADEWANNE3;
2384 case EL_BADEWANNE4: return GFX_BADEWANNE4;
2385 case EL_BADEWANNE5: return GFX_BADEWANNE5;
2386 case EL_ABLENK_AUS: return GFX_ABLENK_AUS;
2387 case EL_ABLENK_EIN: return GFX_ABLENK_EIN;
2388 case EL_SCHLUESSEL1: return GFX_SCHLUESSEL1;
2389 case EL_SCHLUESSEL2: return GFX_SCHLUESSEL2;
2390 case EL_SCHLUESSEL3: return GFX_SCHLUESSEL3;
2391 case EL_SCHLUESSEL4: return GFX_SCHLUESSEL4;
2392 case EL_PFORTE1: return GFX_PFORTE1;
2393 case EL_PFORTE2: return GFX_PFORTE2;
2394 case EL_PFORTE3: return GFX_PFORTE3;
2395 case EL_PFORTE4: return GFX_PFORTE4;
2396 case EL_PFORTE1X: return GFX_PFORTE1X;
2397 case EL_PFORTE2X: return GFX_PFORTE2X;
2398 case EL_PFORTE3X: return GFX_PFORTE3X;
2399 case EL_PFORTE4X: return GFX_PFORTE4X;
2400 case EL_DYNAMITE_INACTIVE: return GFX_DYNAMIT_AUS;
2401 case EL_PACMAN: return GFX_PACMAN;
2402 case EL_PACMAN_R: return GFX_PACMAN_R;
2403 case EL_PACMAN_O: return GFX_PACMAN_O;
2404 case EL_PACMAN_L: return GFX_PACMAN_L;
2405 case EL_PACMAN_U: return GFX_PACMAN_U;
2406 case EL_UNSICHTBAR: return GFX_UNSICHTBAR;
2407 case EL_ERZ_EDEL: return GFX_ERZ_EDEL;
2408 case EL_ERZ_DIAM: return GFX_ERZ_DIAM;
2409 case EL_BIRNE_AUS: return GFX_BIRNE_AUS;
2410 case EL_BIRNE_EIN: return GFX_BIRNE_EIN;
2411 case EL_ZEIT_VOLL: return GFX_ZEIT_VOLL;
2412 case EL_ZEIT_LEER: return GFX_ZEIT_LEER;
2413 case EL_MAUER_LEBT: return GFX_MAUER_LEBT;
2414 case EL_MAUER_X: return GFX_MAUER_X;
2415 case EL_MAUER_Y: return GFX_MAUER_Y;
2416 case EL_MAUER_XY: return GFX_MAUER_XY;
2417 case EL_EDELSTEIN_BD: return GFX_EDELSTEIN_BD;
2418 case EL_EDELSTEIN_GELB: return GFX_EDELSTEIN_GELB;
2419 case EL_EDELSTEIN_ROT: return GFX_EDELSTEIN_ROT;
2420 case EL_EDELSTEIN_LILA: return GFX_EDELSTEIN_LILA;
2421 case EL_ERZ_EDEL_BD: return GFX_ERZ_EDEL_BD;
2422 case EL_ERZ_EDEL_GELB: return GFX_ERZ_EDEL_GELB;
2423 case EL_ERZ_EDEL_ROT: return GFX_ERZ_EDEL_ROT;
2424 case EL_ERZ_EDEL_LILA: return GFX_ERZ_EDEL_LILA;
2425 case EL_MAMPFER2: return GFX_MAMPFER2;
2426 case EL_SIEB2_INAKTIV: return GFX_SIEB2_INAKTIV;
2427 case EL_SIEB2_LEER: return GFX_SIEB2_LEER;
2428 case EL_SIEB2_VOLL: return GFX_SIEB2_VOLL;
2429 case EL_SIEB2_TOT: return GFX_SIEB2_TOT;
2430 case EL_DYNABOMB_ACTIVE_1: return GFX_DYNABOMB;
2431 case EL_DYNABOMB_ACTIVE_2: return GFX_DYNABOMB;
2432 case EL_DYNABOMB_ACTIVE_3: return GFX_DYNABOMB;
2433 case EL_DYNABOMB_ACTIVE_4: return GFX_DYNABOMB;
2434 case EL_DYNABOMB_NR: return GFX_DYNABOMB_NR;
2435 case EL_DYNABOMB_SZ: return GFX_DYNABOMB_SZ;
2436 case EL_DYNABOMB_XL: return GFX_DYNABOMB_XL;
2437 case EL_SOKOBAN_OBJEKT: return GFX_SOKOBAN_OBJEKT;
2438 case EL_SOKOBAN_FELD_LEER: return GFX_SOKOBAN_FELD_LEER;
2439 case EL_SOKOBAN_FELD_VOLL: return GFX_SOKOBAN_FELD_VOLL;
2440 case EL_MAULWURF: return GFX_MAULWURF;
2441 case EL_PINGUIN: return GFX_PINGUIN;
2442 case EL_SCHWEIN: return GFX_SCHWEIN;
2443 case EL_DRACHE: return GFX_DRACHE;
2444 case EL_SONDE: return GFX_SONDE;
2445 case EL_PFEIL_L: return GFX_PFEIL_L;
2446 case EL_PFEIL_R: return GFX_PFEIL_R;
2447 case EL_PFEIL_O: return GFX_PFEIL_O;
2448 case EL_PFEIL_U: return GFX_PFEIL_U;
2449 case EL_SPEED_PILL: return GFX_SPEED_PILL;
2450 case EL_SP_TERMINAL_ACTIVE: return GFX_SP_TERMINAL;
2451 case EL_SP_BUG_ACTIVE: return GFX_SP_BUG_ACTIVE;
2452 case EL_SP_ZONK: return GFX_SP_ZONK;
2453 /* ^^^^^^^^^^ non-standard position in supaplex graphic set! */
2454 case EL_INVISIBLE_STEEL: return GFX_INVISIBLE_STEEL;
2455 case EL_BLACK_ORB: return GFX_BLACK_ORB;
2456 case EL_EM_GATE_1: return GFX_EM_GATE_1;
2457 case EL_EM_GATE_2: return GFX_EM_GATE_2;
2458 case EL_EM_GATE_3: return GFX_EM_GATE_3;
2459 case EL_EM_GATE_4: return GFX_EM_GATE_4;
2460 case EL_EM_GATE_1X: return GFX_EM_GATE_1X;
2461 case EL_EM_GATE_2X: return GFX_EM_GATE_2X;
2462 case EL_EM_GATE_3X: return GFX_EM_GATE_3X;
2463 case EL_EM_GATE_4X: return GFX_EM_GATE_4X;
2464 case EL_EM_KEY_1_FILE: return GFX_EM_KEY_1;
2465 case EL_EM_KEY_2_FILE: return GFX_EM_KEY_2;
2466 case EL_EM_KEY_3_FILE: return GFX_EM_KEY_3;
2467 case EL_EM_KEY_4_FILE: return GFX_EM_KEY_4;
2468 case EL_EM_KEY_1: return GFX_EM_KEY_1;
2469 case EL_EM_KEY_2: return GFX_EM_KEY_2;
2470 case EL_EM_KEY_3: return GFX_EM_KEY_3;
2471 case EL_EM_KEY_4: return GFX_EM_KEY_4;
2472 case EL_PEARL: return GFX_PEARL;
2473 case EL_CRYSTAL: return GFX_CRYSTAL;
2474 case EL_WALL_PEARL: return GFX_WALL_PEARL;
2475 case EL_WALL_CRYSTAL: return GFX_WALL_CRYSTAL;
2476 case EL_DOOR_WHITE: return GFX_DOOR_WHITE;
2477 case EL_DOOR_WHITE_GRAY: return GFX_DOOR_WHITE_GRAY;
2478 case EL_KEY_WHITE: return GFX_KEY_WHITE;
2479 case EL_FORCE_FIELD: return GFX_FORCE_FIELD;
2480 case EL_EXTRA_TIME: return GFX_EXTRA_TIME;
2481 case EL_SWITCHGATE_OPEN: return GFX_SWITCHGATE_OPEN;
2482 case EL_SWITCHGATE_CLOSED: return GFX_SWITCHGATE_CLOSED;
2483 case EL_SWITCHGATE_SWITCH_L:return GFX_SWITCHGATE_SWITCH_L;
2484 case EL_SWITCHGATE_SWITCH_R:return GFX_SWITCHGATE_SWITCH_R;
2485 case EL_TIME_GATE: return GFX_TIME_GATE;
2486 case EL_TIME_GATE_WHEEL: return GFX_TIME_GATE_WHEEL;
2487 case EL_BELT1_LEFT: return GFX_BELT1_LEFT;
2488 case EL_BELT1_MIDDLE: return GFX_BELT1_MIDDLE;
2489 case EL_BELT1_RIGHT: return GFX_BELT1_RIGHT;
2490 case EL_BELT1_SWITCH_L: return GFX_BELT1_SWITCH_L;
2491 case EL_BELT1_SWITCH_M: return GFX_BELT1_SWITCH_M;
2492 case EL_BELT1_SWITCH_R: return GFX_BELT1_SWITCH_R;
2493 case EL_BELT2_LEFT: return GFX_BELT2_LEFT;
2494 case EL_BELT2_MIDDLE: return GFX_BELT2_MIDDLE;
2495 case EL_BELT2_RIGHT: return GFX_BELT2_RIGHT;
2496 case EL_BELT2_SWITCH_L: return GFX_BELT2_SWITCH_L;
2497 case EL_BELT2_SWITCH_M: return GFX_BELT2_SWITCH_M;
2498 case EL_BELT2_SWITCH_R: return GFX_BELT2_SWITCH_R;
2499 case EL_BELT3_LEFT: return GFX_BELT3_LEFT;
2500 case EL_BELT3_MIDDLE: return GFX_BELT3_MIDDLE;
2501 case EL_BELT3_RIGHT: return GFX_BELT3_RIGHT;
2502 case EL_BELT3_SWITCH_L: return GFX_BELT3_SWITCH_L;
2503 case EL_BELT3_SWITCH_M: return GFX_BELT3_SWITCH_M;
2504 case EL_BELT3_SWITCH_R: return GFX_BELT3_SWITCH_R;
2505 case EL_BELT4_LEFT: return GFX_BELT4_LEFT;
2506 case EL_BELT4_MIDDLE: return GFX_BELT4_MIDDLE;
2507 case EL_BELT4_RIGHT: return GFX_BELT4_RIGHT;
2508 case EL_BELT4_SWITCH_L: return GFX_BELT4_SWITCH_L;
2509 case EL_BELT4_SWITCH_M: return GFX_BELT4_SWITCH_M;
2510 case EL_BELT4_SWITCH_R: return GFX_BELT4_SWITCH_R;
2511 case EL_LANDMINE: return GFX_LANDMINE;
2512 case EL_ENVELOPE: return GFX_ENVELOPE;
2513 case EL_LIGHT_SWITCH: return GFX_LIGHT_SWITCH;
2514 case EL_SIGN_EXCLAMATION: return GFX_SIGN_EXCLAMATION;
2515 case EL_SIGN_RADIOACTIVITY: return GFX_SIGN_RADIOACTIVITY;
2516 case EL_SIGN_STOP: return GFX_SIGN_STOP;
2517 case EL_SIGN_WHEELCHAIR: return GFX_SIGN_WHEELCHAIR;
2518 case EL_SIGN_PARKING: return GFX_SIGN_PARKING;
2519 case EL_SIGN_ONEWAY: return GFX_SIGN_ONEWAY;
2520 case EL_SIGN_HEART: return GFX_SIGN_HEART;
2521 case EL_SIGN_TRIANGLE: return GFX_SIGN_TRIANGLE;
2522 case EL_SIGN_ROUND: return GFX_SIGN_ROUND;
2523 case EL_SIGN_EXIT: return GFX_SIGN_EXIT;
2524 case EL_SIGN_YINYANG: return GFX_SIGN_YINYANG;
2525 case EL_SIGN_OTHER: return GFX_SIGN_OTHER;
2526 case EL_MOLE_LEFT: return GFX_MOLE_LEFT;
2527 case EL_MOLE_RIGHT: return GFX_MOLE_RIGHT;
2528 case EL_MOLE_UP: return GFX_MOLE_UP;
2529 case EL_MOLE_DOWN: return GFX_MOLE_DOWN;
2530 case EL_STEEL_SLANTED: return GFX_STEEL_SLANTED;
2531 case EL_SAND_INVISIBLE: return GFX_SAND_INVISIBLE;
2535 if (IS_CHAR(element))
2536 return GFX_CHAR_START + (element - EL_CHAR_START);
2537 else if (element >= EL_SP_START && element <= EL_SP_END)
2539 int nr_element = element - EL_SP_START;
2540 int gfx_per_line = 8;
2542 (nr_element / gfx_per_line) * SP_PER_LINE +
2543 (nr_element % gfx_per_line);
2545 return GFX_START_ROCKSSP + nr_graphic;