1 /***********************************************************
2 * Rocks'n'Diamonds -- McDuffin Strikes Back! *
3 *----------------------------------------------------------*
4 * (c) 1995-2002 Artsoft Entertainment *
6 * Detmolder Strasse 189 *
9 * e-mail: info@artsoft.org *
10 *----------------------------------------------------------*
12 ***********************************************************/
14 #include "libgame/libgame.h"
23 /* tool button identifiers */
24 #define TOOL_CTRL_ID_YES 0
25 #define TOOL_CTRL_ID_NO 1
26 #define TOOL_CTRL_ID_CONFIRM 2
27 #define TOOL_CTRL_ID_PLAYER_1 3
28 #define TOOL_CTRL_ID_PLAYER_2 4
29 #define TOOL_CTRL_ID_PLAYER_3 5
30 #define TOOL_CTRL_ID_PLAYER_4 6
32 #define NUM_TOOL_BUTTONS 7
34 /* forward declaration for internal use */
35 static void UnmapToolButtons();
36 static void HandleToolButtons(struct GadgetInfo *);
38 static struct GadgetInfo *tool_gadget[NUM_TOOL_BUTTONS];
39 static int request_gadget_id = -1;
41 void SetDrawtoField(int mode)
43 if (mode == DRAW_BUFFERED && setup.soft_scrolling)
54 drawto_field = fieldbuffer;
56 else /* DRAW_DIRECT, DRAW_BACKBUFFER */
67 drawto_field = (mode == DRAW_DIRECT ? window : backbuffer);
71 void RedrawPlayfield(boolean force_redraw, int x, int y, int width, int height)
73 if (game_status == PLAYING)
79 width = gfx.sxsize + 2 * TILEX;
80 height = gfx.sysize + 2 * TILEY;
83 if (force_redraw || setup.direct_draw)
86 int x1 = (x - SX) / TILEX, y1 = (y - SY) / TILEY;
87 int x2 = (x - SX + width) / TILEX, y2 = (y - SY + height) / TILEY;
89 if (setup.direct_draw)
90 SetDrawtoField(DRAW_BACKBUFFER);
92 for(xx=BX1; xx<=BX2; xx++)
93 for(yy=BY1; yy<=BY2; yy++)
94 if (xx >= x1 && xx <= x2 && yy >= y1 && yy <= y2)
95 DrawScreenField(xx, yy);
98 if (setup.direct_draw)
99 SetDrawtoField(DRAW_DIRECT);
102 if (setup.soft_scrolling)
104 int fx = FX, fy = FY;
106 fx += (ScreenMovDir & (MV_LEFT|MV_RIGHT) ? ScreenGfxPos : 0);
107 fy += (ScreenMovDir & (MV_UP|MV_DOWN) ? ScreenGfxPos : 0);
109 BlitBitmap(fieldbuffer, backbuffer, fx,fy, SXSIZE,SYSIZE, SX,SY);
113 BlitBitmap(drawto, window, x, y, width, height, x, y);
119 DrawBuffer *buffer = (drawto_field == window ? backbuffer : drawto_field);
121 if (setup.direct_draw && game_status == PLAYING)
122 redraw_mask &= ~REDRAW_MAIN;
124 if (redraw_mask & REDRAW_TILES && redraw_tiles > REDRAWTILES_THRESHOLD)
125 redraw_mask |= REDRAW_FIELD;
127 if (redraw_mask & REDRAW_FIELD)
128 redraw_mask &= ~REDRAW_TILES;
130 if (redraw_mask == REDRAW_NONE)
133 if (global.fps_slowdown && game_status == PLAYING)
135 static boolean last_frame_skipped = FALSE;
136 boolean skip_even_when_not_scrolling = TRUE;
137 boolean just_scrolling = (ScreenMovDir != 0);
138 boolean verbose = FALSE;
140 if (global.fps_slowdown_factor > 1 &&
141 (FrameCounter % global.fps_slowdown_factor) &&
142 (just_scrolling || skip_even_when_not_scrolling))
144 redraw_mask &= ~REDRAW_MAIN;
146 last_frame_skipped = TRUE;
149 printf("FRAME SKIPPED\n");
153 if (last_frame_skipped)
154 redraw_mask |= REDRAW_FIELD;
156 last_frame_skipped = FALSE;
159 printf("frame not skipped\n");
163 /* synchronize X11 graphics at this point; if we would synchronize the
164 display immediately after the buffer switching (after the XFlush),
165 this could mean that we have to wait for the graphics to complete,
166 although we could go on doing calculations for the next frame */
170 if (redraw_mask & REDRAW_ALL)
172 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
176 if (redraw_mask & REDRAW_FIELD)
178 if (game_status != PLAYING || redraw_mask & REDRAW_FROM_BACKBUFFER)
180 BlitBitmap(backbuffer, window,
181 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE, REAL_SX, REAL_SY);
185 int fx = FX, fy = FY;
187 if (setup.soft_scrolling)
189 fx += (ScreenMovDir & (MV_LEFT | MV_RIGHT) ? ScreenGfxPos : 0);
190 fy += (ScreenMovDir & (MV_UP | MV_DOWN) ? ScreenGfxPos : 0);
193 if (setup.soft_scrolling ||
194 ABS(ScreenMovPos) + ScrollStepSize == TILEX ||
195 ABS(ScreenMovPos) == ScrollStepSize ||
196 redraw_tiles > REDRAWTILES_THRESHOLD)
198 BlitBitmap(buffer, window, fx, fy, SXSIZE, SYSIZE, SX, SY);
202 printf("redrawing all (ScreenGfxPos == %d) because %s\n",
204 (setup.soft_scrolling ?
205 "setup.soft_scrolling" :
206 ABS(ScreenGfxPos) + ScrollStepSize == TILEX ?
207 "ABS(ScreenGfxPos) + ScrollStepSize == TILEX" :
208 ABS(ScreenGfxPos) == ScrollStepSize ?
209 "ABS(ScreenGfxPos) == ScrollStepSize" :
210 "redraw_tiles > REDRAWTILES_THRESHOLD"));
216 redraw_mask &= ~REDRAW_MAIN;
219 if (redraw_mask & REDRAW_DOORS)
221 if (redraw_mask & REDRAW_DOOR_1)
222 BlitBitmap(backbuffer, window, DX, DY, DXSIZE, DYSIZE, DX, DY);
223 if (redraw_mask & REDRAW_DOOR_2)
225 if ((redraw_mask & REDRAW_DOOR_2) == REDRAW_DOOR_2)
226 BlitBitmap(backbuffer, window, VX,VY, VXSIZE,VYSIZE, VX,VY);
229 if (redraw_mask & REDRAW_VIDEO_1)
230 BlitBitmap(backbuffer, window,
231 VX+VIDEO_DISPLAY1_XPOS,VY+VIDEO_DISPLAY1_YPOS,
232 VIDEO_DISPLAY_XSIZE,VIDEO_DISPLAY_YSIZE,
233 VX+VIDEO_DISPLAY1_XPOS,VY+VIDEO_DISPLAY1_YPOS);
234 if (redraw_mask & REDRAW_VIDEO_2)
235 BlitBitmap(backbuffer, window,
236 VX+VIDEO_DISPLAY2_XPOS,VY+VIDEO_DISPLAY2_YPOS,
237 VIDEO_DISPLAY_XSIZE,VIDEO_DISPLAY_YSIZE,
238 VX+VIDEO_DISPLAY2_XPOS,VY+VIDEO_DISPLAY2_YPOS);
239 if (redraw_mask & REDRAW_VIDEO_3)
240 BlitBitmap(backbuffer, window,
241 VX+VIDEO_CONTROL_XPOS,VY+VIDEO_CONTROL_YPOS,
242 VIDEO_CONTROL_XSIZE,VIDEO_CONTROL_YSIZE,
243 VX+VIDEO_CONTROL_XPOS,VY+VIDEO_CONTROL_YPOS);
247 if (redraw_mask & REDRAW_DOOR_3)
248 BlitBitmap(backbuffer, window, EX, EY, EXSIZE, EYSIZE, EX, EY);
250 redraw_mask &= ~REDRAW_DOORS;
253 if (redraw_mask & REDRAW_MICROLEVEL)
255 BlitBitmap(backbuffer, window, SX, SY + 10 * TILEY, SXSIZE, 7 * TILEY,
256 SX, SY + 10 * TILEY);
258 redraw_mask &= ~REDRAW_MICROLEVEL;
261 if (redraw_mask & REDRAW_TILES)
263 for(x=0; x<SCR_FIELDX; x++)
264 for(y=0; y<SCR_FIELDY; y++)
265 if (redraw[redraw_x1 + x][redraw_y1 + y])
266 BlitBitmap(buffer, window,
267 FX + x * TILEX, FX + y * TILEY, TILEX, TILEY,
268 SX + x * TILEX, SY + y * TILEY);
271 if (redraw_mask & REDRAW_FPS) /* display frames per second */
276 sprintf(info1, " (only every %d. frame)", global.fps_slowdown_factor);
277 if (!global.fps_slowdown)
280 sprintf(text, "%.1f fps%s", global.frames_per_second, info1);
281 DrawTextExt(window, SX, SY, text, FONT_TEXT_2, FONT_OPAQUE);
286 for(x=0; x<MAX_BUF_XSIZE; x++)
287 for(y=0; y<MAX_BUF_YSIZE; y++)
290 redraw_mask = REDRAW_NONE;
296 long fading_delay = 300;
298 if (setup.fading && (redraw_mask & REDRAW_FIELD))
305 ClearRectangle(window, REAL_SX,REAL_SY,FULL_SXSIZE,FULL_SYSIZE);
308 for(i=0;i<2*FULL_SYSIZE;i++)
310 for(y=0;y<FULL_SYSIZE;y++)
312 BlitBitmap(backbuffer, window,
313 REAL_SX,REAL_SY+i, FULL_SXSIZE,1, REAL_SX,REAL_SY+i);
321 for(i=1;i<FULL_SYSIZE;i+=2)
322 BlitBitmap(backbuffer, window,
323 REAL_SX,REAL_SY+i, FULL_SXSIZE,1, REAL_SX,REAL_SY+i);
329 SetClipOrigin(clip_gc[PIX_FADEMASK], 0, 0);
330 BlitBitmapMasked(backbuffer, window,
331 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
336 SetClipOrigin(clip_gc[PIX_FADEMASK], -1, -1);
337 BlitBitmapMasked(backbuffer, window,
338 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
343 SetClipOrigin(clip_gc[PIX_FADEMASK], 0, -1);
344 BlitBitmapMasked(backbuffer, window,
345 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
350 SetClipOrigin(clip_gc[PIX_FADEMASK], -1, 0);
351 BlitBitmapMasked(backbuffer, window,
352 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
357 redraw_mask &= ~REDRAW_MAIN;
364 void SetMainBackgroundImage(int graphic)
366 SetMainBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
367 graphic_info[graphic].bitmap ?
368 graphic_info[graphic].bitmap :
369 graphic_info[IMG_BACKGROUND].bitmap);
372 void SetDoorBackgroundImage(int graphic)
374 SetDoorBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
375 graphic_info[graphic].bitmap ?
376 graphic_info[graphic].bitmap :
377 graphic_info[IMG_BACKGROUND].bitmap);
380 void DrawBackground(int dest_x, int dest_y, int width, int height)
382 ClearRectangleOnBackground(backbuffer, dest_x, dest_y, width, height);
384 redraw_mask |= REDRAW_FIELD;
389 DrawBackground(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
391 if (setup.soft_scrolling && game_status == PLAYING)
393 ClearRectangle(fieldbuffer, 0, 0, FXSIZE, FYSIZE);
394 SetDrawtoField(DRAW_BUFFERED);
397 SetDrawtoField(DRAW_BACKBUFFER);
399 if (setup.direct_draw && game_status == PLAYING)
401 ClearRectangle(window, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
402 SetDrawtoField(DRAW_DIRECT);
406 void MarkTileDirty(int x, int y)
408 int xx = redraw_x1 + x;
409 int yy = redraw_y1 + y;
414 redraw[xx][yy] = TRUE;
415 redraw_mask |= REDRAW_TILES;
418 void SetBorderElement()
422 BorderElement = EL_EMPTY;
424 for(y=0; y<lev_fieldy && BorderElement == EL_EMPTY; y++)
426 for(x=0; x<lev_fieldx; x++)
428 if (!IS_INDESTRUCTIBLE(Feld[x][y]))
429 BorderElement = EL_STEELWALL;
431 if (y != 0 && y != lev_fieldy - 1 && x != lev_fieldx - 1)
437 void SetRandomAnimationValue(int x, int y)
439 gfx.anim_random_frame = GfxRandom[x][y];
442 inline int getGraphicAnimationFrame(int graphic, int sync_frame)
444 /* animation synchronized with global frame counter, not move position */
445 if (graphic_info[graphic].anim_global_sync || sync_frame < 0)
446 sync_frame = FrameCounter;
448 return getAnimationFrame(graphic_info[graphic].anim_frames,
449 graphic_info[graphic].anim_delay,
450 graphic_info[graphic].anim_mode,
451 graphic_info[graphic].anim_start_frame,
455 inline void DrawGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
456 int graphic, int sync_frame, int mask_mode)
458 int frame = getGraphicAnimationFrame(graphic, sync_frame);
460 if (mask_mode == USE_MASKING)
461 DrawGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
463 DrawGraphicExt(dst_bitmap, x, y, graphic, frame);
466 inline void DrawGraphicAnimation(int x, int y, int graphic)
468 int lx = LEVELX(x), ly = LEVELY(y);
470 if (!IN_SCR_FIELD(x, y))
473 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
474 graphic, GfxFrame[lx][ly], NO_MASKING);
478 void DrawLevelGraphicAnimation(int x, int y, int graphic)
480 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
483 void DrawLevelElementAnimation(int x, int y, int element)
485 DrawGraphicAnimation(SCREENX(x), SCREENY(y), el2img(element));
488 inline void DrawLevelGraphicAnimationIfNeeded(int x, int y, int graphic)
490 int sx = SCREENX(x), sy = SCREENY(y);
492 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
495 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
498 DrawGraphicAnimation(sx, sy, graphic);
501 void DrawLevelElementAnimationIfNeeded(int x, int y, int element)
503 int sx = SCREENX(x), sy = SCREENY(y);
506 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
509 graphic = el_act_dir2img(element, GfxAction[x][y], MovDir[x][y]);
511 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
514 DrawGraphicAnimation(sx, sy, graphic);
517 void DrawAllPlayers()
521 for(i=0; i<MAX_PLAYERS; i++)
522 if (stored_player[i].active)
523 DrawPlayer(&stored_player[i]);
526 void DrawPlayerField(int x, int y)
528 if (!IS_PLAYER(x, y))
531 DrawPlayer(PLAYERINFO(x, y));
534 void DrawPlayer(struct PlayerInfo *player)
536 int jx = player->jx, jy = player->jy;
537 int last_jx = player->last_jx, last_jy = player->last_jy;
538 int next_jx = jx + (jx - last_jx), next_jy = jy + (jy - last_jy);
539 int sx = SCREENX(jx), sy = SCREENY(jy);
540 int sxx = 0, syy = 0;
541 int element = Feld[jx][jy], last_element = Feld[last_jx][last_jy];
544 boolean player_is_moving = (last_jx != jx || last_jy != jy ? TRUE : FALSE);
546 if (!player->active || !IN_SCR_FIELD(SCREENX(last_jx), SCREENY(last_jy)))
550 if (!IN_LEV_FIELD(jx,jy))
552 printf("DrawPlayerField(): x = %d, y = %d\n",jx,jy);
553 printf("DrawPlayerField(): sx = %d, sy = %d\n",sx,sy);
554 printf("DrawPlayerField(): This should never happen!\n");
559 if (element == EL_EXPLOSION)
562 /* ----------------------------------------------------------------------- */
563 /* draw things in the field the player is leaving, if needed */
564 /* ----------------------------------------------------------------------- */
566 if (player_is_moving)
568 if (Store[last_jx][last_jy] && IS_DRAWABLE(last_element))
570 DrawLevelElement(last_jx, last_jy, Store[last_jx][last_jy]);
572 if (last_element == EL_DYNAMITE_ACTIVE ||
573 last_element == EL_SP_DISK_RED_ACTIVE)
574 DrawDynamite(last_jx, last_jy);
576 DrawLevelFieldThruMask(last_jx, last_jy);
578 else if (last_element == EL_DYNAMITE_ACTIVE ||
579 last_element == EL_SP_DISK_RED_ACTIVE)
580 DrawDynamite(last_jx, last_jy);
582 DrawLevelField(last_jx, last_jy);
584 if (player->Pushing && IN_SCR_FIELD(SCREENX(next_jx), SCREENY(next_jy)))
588 if (Feld[next_jx][next_jy] == EL_SOKOBAN_FIELD_FULL)
589 DrawLevelElement(next_jx, next_jy, EL_SOKOBAN_FIELD_EMPTY);
591 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
594 DrawLevelField(next_jx, next_jy);
598 if (!IN_SCR_FIELD(sx, sy))
601 if (setup.direct_draw)
602 SetDrawtoField(DRAW_BUFFERED);
604 /* ----------------------------------------------------------------------- */
605 /* draw things behind the player, if needed */
606 /* ----------------------------------------------------------------------- */
609 DrawLevelElement(jx, jy, Store[jx][jy]);
610 else if (IS_ACTIVE_BOMB(element))
611 DrawLevelElement(jx, jy, EL_EMPTY);
614 if (player_is_moving && GfxElement[jx][jy] != EL_UNDEFINED)
616 int old_element = GfxElement[jx][jy];
618 el_act_dir2img(old_element, ACTION_DIGGING, player->MovDir);
619 int frame = getGraphicAnimationFrame(old_graphic, player->Frame);
623 int width = TILEX, height = TILEY;
626 if (player->MovDir == MV_UP)
631 else if (player->MovDir == MV_DOWN)
634 height = TILEY - player->GfxPos;
636 else if (player->MovDir == MV_LEFT)
641 else if (player->MovDir == MV_RIGHT)
644 width = TILEX - player->GfxPos;
647 getGraphicSource(old_graphic, frame, &src_bitmap, &src_x, &src_y);
649 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
650 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
653 printf("::: %d, %d, %d, %d => %d, %d [%d]\n",
654 old_element, ACTION_DIGGING, player->MovDir, player->Frame,
659 DrawGraphic(sx, sy, old_graphic, frame);
664 GfxElement[jx][jy] = EL_UNDEFINED;
666 DrawLevelField(jx, jy);
670 /* ----------------------------------------------------------------------- */
671 /* draw player himself */
672 /* ----------------------------------------------------------------------- */
674 player->GfxAction = (player->Pushing ? ACTION_PUSHING :
675 player->is_digging ? ACTION_DIGGING :
676 player->is_moving ? ACTION_MOVING :
677 player->snapped ? ACTION_SNAPPING : ACTION_DEFAULT);
679 if (player->use_murphy_graphic)
681 static int last_horizontal_dir = MV_LEFT;
684 if (player->MovDir == MV_LEFT || player->MovDir == MV_RIGHT)
685 last_horizontal_dir = player->MovDir;
687 direction = (player->snapped ? player->MovDir : last_horizontal_dir);
689 graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, direction);
692 graphic = el_act_dir2img(player->element_nr, player->GfxAction,
695 frame = getGraphicAnimationFrame(graphic, player->Frame);
699 if (player->MovDir == MV_LEFT || player->MovDir == MV_RIGHT)
700 sxx = player->GfxPos;
702 syy = player->GfxPos;
705 if (!setup.soft_scrolling && ScreenMovPos)
708 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
710 if (SHIELD_ON(player))
712 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
713 IMG_SHIELD_NORMAL_ACTIVE);
714 int frame = getGraphicAnimationFrame(graphic, -1);
716 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
719 /* ----------------------------------------------------------------------- */
720 /* draw things the player is pushing, if needed */
721 /* ----------------------------------------------------------------------- */
723 if (player->Pushing && player_is_moving)
725 int px = SCREENX(next_jx), py = SCREENY(next_jy);
728 (element == EL_SOKOBAN_FIELD_EMPTY ||
729 Feld[next_jx][next_jy] == EL_SOKOBAN_FIELD_FULL))
730 DrawGraphicShiftedThruMask(px, py, sxx, syy, IMG_SOKOBAN_OBJECT, 0,
734 int element = Feld[next_jx][next_jy];
735 int graphic = el2img(element);
738 if ((sxx || syy) && IS_PUSHABLE(element))
740 graphic = el_act_dir2img(element, ACTION_MOVING, player->MovDir);
741 frame = getGraphicAnimationFrame(graphic, player->Frame);
744 DrawGraphicShifted(px, py, sxx, syy, graphic, frame,
745 NO_CUTTING, NO_MASKING);
749 /* ----------------------------------------------------------------------- */
750 /* draw things in front of player (active dynamite or dynabombs) */
751 /* ----------------------------------------------------------------------- */
753 if (IS_ACTIVE_BOMB(element))
755 graphic = el2img(element);
756 frame = getGraphicAnimationFrame(graphic, GfxFrame[jx][jy]);
758 if (game.emulation == EMU_SUPAPLEX)
759 DrawGraphic(sx, sy, IMG_SP_DISK_RED, frame);
761 DrawGraphicThruMask(sx, sy, graphic, frame);
764 if (player_is_moving && last_element == EL_EXPLOSION)
766 int stored = Store[last_jx][last_jy];
767 int graphic = (game.emulation != EMU_SUPAPLEX ? IMG_EXPLOSION :
768 stored == EL_SP_INFOTRON ? IMG_SP_EXPLOSION_INFOTRON :
770 int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
771 int phase = ExplodePhase[last_jx][last_jy] - 1;
772 int frame = getGraphicAnimationFrame(graphic, phase - delay);
775 DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy), graphic, frame);
778 /* ----------------------------------------------------------------------- */
779 /* draw elements that stay over the player */
780 /* ----------------------------------------------------------------------- */
782 /* handle the field the player is leaving ... */
783 if (player_is_moving && IS_OVER_PLAYER(last_element))
784 DrawLevelField(last_jx, last_jy);
786 /* ... and the field the player is entering */
787 if (IS_OVER_PLAYER(element))
788 DrawLevelField(jx, jy);
790 if (setup.direct_draw)
792 int dest_x = SX + SCREENX(MIN(jx, last_jx)) * TILEX;
793 int dest_y = SY + SCREENY(MIN(jy, last_jy)) * TILEY;
794 int x_size = TILEX * (1 + ABS(jx - last_jx));
795 int y_size = TILEY * (1 + ABS(jy - last_jy));
797 BlitBitmap(drawto_field, window,
798 dest_x, dest_y, x_size, y_size, dest_x, dest_y);
799 SetDrawtoField(DRAW_DIRECT);
802 MarkTileDirty(sx,sy);
805 void getGraphicSource(int graphic, int frame, Bitmap **bitmap, int *x, int *y)
807 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
808 int offset_x = graphic_info[graphic].offset_x;
809 int offset_y = graphic_info[graphic].offset_y;
810 int src_x = graphic_info[graphic].src_x + frame * offset_x;
811 int src_y = graphic_info[graphic].src_y + frame * offset_y;
813 *bitmap = src_bitmap;
818 void DrawGraphic(int x, int y, int graphic, int frame)
821 if (!IN_SCR_FIELD(x, y))
823 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
824 printf("DrawGraphic(): This should never happen!\n");
829 DrawGraphicExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic, frame);
834 void DrawOldGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic)
839 getOldGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
840 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
844 void DrawGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
851 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
853 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
854 int src_x = graphic_info[graphic].src_x;
855 int src_y = graphic_info[graphic].src_y;
856 int offset_x = graphic_info[graphic].offset_x;
857 int offset_y = graphic_info[graphic].offset_y;
859 src_x += frame * offset_x;
860 src_y += frame * offset_y;
863 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
866 void DrawGraphicThruMask(int x, int y, int graphic, int frame)
869 if (!IN_SCR_FIELD(x, y))
871 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
872 printf("DrawGraphicThruMask(): This should never happen!\n");
877 DrawGraphicThruMaskExt(drawto_field, FX + x * TILEX, FY + y *TILEY, graphic,
882 void DrawGraphicThruMaskExt(DrawBuffer *d, int dest_x, int dest_y, int graphic,
890 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
891 drawing_gc = src_bitmap->stored_clip_gc;
893 GC drawing_gc = src_bitmap->stored_clip_gc;
894 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
895 int src_x = graphic_info[graphic].src_x;
896 int src_y = graphic_info[graphic].src_y;
897 int offset_x = graphic_info[graphic].offset_x;
898 int offset_y = graphic_info[graphic].offset_y;
900 src_x += frame * offset_x;
901 src_y += frame * offset_y;
905 SetClipOrigin(src_bitmap, drawing_gc, dest_x - src_x, dest_y - src_y);
906 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX, TILEY, dest_x, dest_y);
909 void DrawMiniGraphic(int x, int y, int graphic)
911 DrawMiniGraphicExt(drawto, SX + x * MINI_TILEX,SY + y * MINI_TILEY, graphic);
912 MarkTileDirty(x / 2, y / 2);
915 void getMiniGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
917 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
919 int mini_starty = src_bitmap->height * 2 / 3;
920 int src_x = mini_startx + graphic_info[graphic].src_x / 2;
921 int src_y = mini_starty + graphic_info[graphic].src_y / 2;
924 /* !!! not needed anymore, because of automatically created mini graphics */
925 if (src_x + MINI_TILEX > src_bitmap->width ||
926 src_y + MINI_TILEY > src_bitmap->height)
928 /* graphic of desired size seems not to be contained in this image;
929 dirty workaround: get it from the middle of the normal sized image */
931 printf("::: using dirty workaround for %d (%d, %d)\n",
932 graphic, src_bitmap->width, src_bitmap->height);
934 getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
935 src_x += (TILEX / 2 - MINI_TILEX / 2);
936 src_y += (TILEY / 2 - MINI_TILEY / 2);
940 *bitmap = src_bitmap;
945 void DrawMiniGraphicExt(DrawBuffer *d, int x, int y, int graphic)
950 getMiniGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
951 BlitBitmap(src_bitmap, d, src_x, src_y, MINI_TILEX, MINI_TILEY, x, y);
954 void DrawGraphicShifted(int x,int y, int dx,int dy, int graphic, int frame,
955 int cut_mode, int mask_mode)
964 int width = TILEX, height = TILEY;
970 DrawGraphic(x, y, graphic, frame);
974 if (dx || dy) /* shifted graphic */
976 if (x < BX1) /* object enters playfield from the left */
983 else if (x > BX2) /* object enters playfield from the right */
989 else if (x==BX1 && dx < 0) /* object leaves playfield to the left */
995 else if (x==BX2 && dx > 0) /* object leaves playfield to the right */
997 else if (dx) /* general horizontal movement */
998 MarkTileDirty(x + SIGN(dx), y);
1000 if (y < BY1) /* object enters playfield from the top */
1002 if (cut_mode==CUT_BELOW) /* object completely above top border */
1010 else if (y > BY2) /* object enters playfield from the bottom */
1016 else if (y==BY1 && dy < 0) /* object leaves playfield to the top */
1022 else if (dy > 0 && cut_mode == CUT_ABOVE)
1024 if (y == BY2) /* object completely above bottom border */
1030 MarkTileDirty(x, y + 1);
1031 } /* object leaves playfield to the bottom */
1032 else if (dy > 0 && (y == BY2 || cut_mode == CUT_BELOW))
1034 else if (dy) /* general vertical movement */
1035 MarkTileDirty(x, y + SIGN(dy));
1038 src_bitmap = graphic_info[graphic].bitmap;
1039 src_x = graphic_info[graphic].src_x;
1040 src_y = graphic_info[graphic].src_y;
1041 offset_x = graphic_info[graphic].offset_x;
1042 offset_y = graphic_info[graphic].offset_y;
1044 drawing_gc = src_bitmap->stored_clip_gc;
1046 src_x += frame * offset_x;
1047 src_y += frame * offset_y;
1052 dest_x = FX + x * TILEX + dx;
1053 dest_y = FY + y * TILEY + dy;
1056 if (!IN_SCR_FIELD(x,y))
1058 printf("DrawGraphicShifted(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
1059 printf("DrawGraphicShifted(): This should never happen!\n");
1064 if (mask_mode == USE_MASKING)
1066 SetClipOrigin(src_bitmap, drawing_gc, dest_x - src_x, dest_y - src_y);
1067 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1071 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1077 void DrawGraphicShiftedThruMask(int x, int y, int dx, int dy, int graphic,
1078 int frame, int cut_mode)
1080 DrawGraphicShifted(x,y, dx,dy, graphic, frame, cut_mode, USE_MASKING);
1083 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
1084 int cut_mode, int mask_mode)
1086 int lx = LEVELX(x), ly = LEVELY(y);
1090 if (IN_LEV_FIELD(lx, ly))
1092 SetRandomAnimationValue(lx, ly);
1094 graphic = el_act_dir2img(element, GfxAction[lx][ly], MovDir[lx][ly]);
1095 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1097 else /* border element */
1099 graphic = el2img(element);
1100 frame = getGraphicAnimationFrame(graphic, -1);
1103 if (element == EL_EXPANDABLE_WALL)
1105 boolean left_stopped = FALSE, right_stopped = FALSE;
1107 if (!IN_LEV_FIELD(lx - 1, ly) || IS_MAUER(Feld[lx - 1][ly]))
1108 left_stopped = TRUE;
1109 if (!IN_LEV_FIELD(lx + 1, ly) || IS_MAUER(Feld[lx + 1][ly]))
1110 right_stopped = TRUE;
1112 if (left_stopped && right_stopped)
1114 else if (left_stopped)
1116 graphic = IMG_EXPANDABLE_WALL_GROWING_RIGHT;
1117 frame = graphic_info[graphic].anim_frames - 1;
1119 else if (right_stopped)
1121 graphic = IMG_EXPANDABLE_WALL_GROWING_LEFT;
1122 frame = graphic_info[graphic].anim_frames - 1;
1126 else if (IS_AMOEBOID(element) || element == EL_AMOEBA_DROPPING)
1128 graphic = (element == EL_BD_AMOEBA ? IMG_BD_AMOEBA_PART1 :
1129 element == EL_AMOEBA_WET ? IMG_AMOEBA_WET_PART1 :
1130 element == EL_AMOEBA_DRY ? IMG_AMOEBA_DRY_PART1 :
1131 element == EL_AMOEBA_FULL ? IMG_AMOEBA_FULL_PART1 :
1132 IMG_AMOEBA_DEAD_PART1);
1134 graphic += (x + 2 * y + 4) % 4;
1139 if (IS_AMOEBOID(element) || element == EL_AMOEBA_DROPPING)
1141 if (Feld[lx][ly] == EL_AMOEBA_DROPPING)
1142 printf("---> %d -> %d / %d [%d]\n",
1143 element, graphic, frame, GfxRandom[lx][ly]);
1148 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, mask_mode);
1149 else if (mask_mode == USE_MASKING)
1150 DrawGraphicThruMask(x, y, graphic, frame);
1152 DrawGraphic(x, y, graphic, frame);
1155 void DrawLevelElementExt(int x, int y, int dx, int dy, int element,
1156 int cut_mode, int mask_mode)
1158 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1159 DrawScreenElementExt(SCREENX(x), SCREENY(y), dx, dy, element,
1160 cut_mode, mask_mode);
1163 void DrawScreenElementShifted(int x, int y, int dx, int dy, int element,
1166 DrawScreenElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1169 void DrawLevelElementShifted(int x, int y, int dx, int dy, int element,
1172 DrawLevelElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1176 void DrawOldScreenElementThruMask(int x, int y, int element)
1178 DrawOldScreenElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1181 void DrawScreenElementThruMask(int x, int y, int element)
1183 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1187 void DrawLevelElementThruMask(int x, int y, int element)
1189 DrawLevelElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1192 void DrawLevelFieldThruMask(int x, int y)
1194 DrawLevelElementExt(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
1197 void DrawCrumbledSand(int x, int y)
1201 int i, width, height, cx,cy;
1202 int lx = LEVELX(x), ly = LEVELY(y);
1203 int element, graphic;
1205 static int xy[4][2] =
1213 if (!IN_LEV_FIELD(lx, ly))
1216 element = Feld[lx][ly];
1218 if (element == EL_SAND ||
1220 (element == EL_EMPTY_SPACE && GfxElement[lx][ly] == EL_SAND) ||
1222 element == EL_LANDMINE ||
1223 element == EL_TRAP ||
1224 element == EL_TRAP_ACTIVE)
1226 if (!IN_SCR_FIELD(x, y))
1229 graphic = IMG_SAND_CRUMBLED;
1231 src_bitmap = graphic_info[graphic].bitmap;
1232 src_x = graphic_info[graphic].src_x;
1233 src_y = graphic_info[graphic].src_y;
1239 lxx = lx + xy[i][0];
1240 lyy = ly + xy[i][1];
1241 if (!IN_LEV_FIELD(lxx, lyy))
1242 element = EL_STEELWALL;
1244 element = Feld[lxx][lyy];
1246 if (element == EL_SAND ||
1248 (element == EL_EMPTY_SPACE && GfxElement[lxx][lyy] == EL_SAND) ||
1250 element == EL_LANDMINE ||
1251 element == EL_TRAP ||
1252 element == EL_TRAP_ACTIVE)
1255 if (i == 1 || i == 2)
1259 cx = (i == 2 ? TILEX - snip : 0);
1267 cy = (i == 3 ? TILEY - snip : 0);
1270 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1271 width, height, FX + x * TILEX + cx, FY + y * TILEY + cy);
1274 MarkTileDirty(x, y);
1278 graphic = IMG_SAND_CRUMBLED;
1280 src_bitmap = graphic_info[graphic].bitmap;
1281 src_x = graphic_info[graphic].src_x;
1282 src_y = graphic_info[graphic].src_y;
1286 int xx, yy, lxx, lyy;
1290 lxx = lx + xy[i][0];
1291 lyy = ly + xy[i][1];
1293 if (!IN_LEV_FIELD(lxx, lyy) ||
1294 (Feld[lxx][lyy] != EL_SAND &&
1296 !(Feld[lxx][lyy] == EL_EMPTY_SPACE && GfxElement[lxx][lyy] == EL_SAND) &&
1298 Feld[lxx][lyy] != EL_LANDMINE &&
1299 Feld[lxx][lyy] != EL_TRAP &&
1300 Feld[lxx][lyy] != EL_TRAP_ACTIVE) ||
1301 !IN_SCR_FIELD(xx, yy))
1304 if (i == 1 || i == 2)
1308 cx = (i == 1 ? TILEX - snip : 0);
1316 cy = (i==0 ? TILEY-snip : 0);
1319 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1320 width, height, FX + xx * TILEX + cx, FY + yy * TILEY + cy);
1322 MarkTileDirty(xx, yy);
1327 static int getBorderElement(int x, int y)
1331 { EL_STEELWALL_TOPLEFT, EL_INVISIBLE_STEELWALL_TOPLEFT },
1332 { EL_STEELWALL_TOPRIGHT, EL_INVISIBLE_STEELWALL_TOPRIGHT },
1333 { EL_STEELWALL_BOTTOMLEFT, EL_INVISIBLE_STEELWALL_BOTTOMLEFT },
1334 { EL_STEELWALL_BOTTOMRIGHT, EL_INVISIBLE_STEELWALL_BOTTOMRIGHT },
1335 { EL_STEELWALL_VERTICAL, EL_INVISIBLE_STEELWALL_VERTICAL },
1336 { EL_STEELWALL_HORIZONTAL, EL_INVISIBLE_STEELWALL_HORIZONTAL },
1337 { EL_STEELWALL, EL_INVISIBLE_STEELWALL }
1339 int steel_type = (BorderElement == EL_STEELWALL ? 0 : 1);
1340 int steel_position = (x == -1 && y == -1 ? 0 :
1341 x == lev_fieldx && y == -1 ? 1 :
1342 x == -1 && y == lev_fieldy ? 2 :
1343 x == lev_fieldx && y == lev_fieldy ? 3 :
1344 x == -1 || x == lev_fieldx ? 4 :
1345 y == -1 || y == lev_fieldy ? 5 : 6);
1347 return border[steel_position][steel_type];
1350 void DrawScreenElement(int x, int y, int element)
1352 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
1353 DrawCrumbledSand(x, y);
1356 void DrawLevelElement(int x, int y, int element)
1358 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1359 DrawScreenElement(SCREENX(x), SCREENY(y), element);
1362 void DrawScreenField(int x, int y)
1364 int lx = LEVELX(x), ly = LEVELY(y);
1365 int element, content;
1367 if (!IN_LEV_FIELD(lx, ly))
1369 if (lx < -1 || lx > lev_fieldx || ly < -1 || ly > lev_fieldy)
1372 element = getBorderElement(lx, ly);
1374 DrawScreenElement(x, y, element);
1378 element = Feld[lx][ly];
1379 content = Store[lx][ly];
1381 if (IS_MOVING(lx, ly))
1383 int horiz_move = (MovDir[lx][ly] == MV_LEFT || MovDir[lx][ly] == MV_RIGHT);
1384 boolean cut_mode = NO_CUTTING;
1386 if (element == EL_QUICKSAND_EMPTYING ||
1387 element == EL_MAGIC_WALL_EMPTYING ||
1388 element == EL_BD_MAGIC_WALL_EMPTYING ||
1389 element == EL_AMOEBA_DROPPING)
1390 cut_mode = CUT_ABOVE;
1391 else if (element == EL_QUICKSAND_FILLING ||
1392 element == EL_MAGIC_WALL_FILLING ||
1393 element == EL_BD_MAGIC_WALL_FILLING)
1394 cut_mode = CUT_BELOW;
1396 if (cut_mode == CUT_ABOVE)
1397 DrawScreenElementShifted(x, y, 0, 0, element, NO_CUTTING);
1399 DrawScreenElement(x, y, EL_EMPTY);
1402 DrawScreenElementShifted(x, y, MovPos[lx][ly], 0, element, NO_CUTTING);
1403 else if (cut_mode == NO_CUTTING)
1404 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], element, cut_mode);
1406 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], content, cut_mode);
1408 if (content == EL_ACID)
1409 DrawLevelElementThruMask(lx, ly + 1, EL_ACID);
1411 else if (IS_BLOCKED(lx, ly))
1416 boolean cut_mode = NO_CUTTING;
1417 int element_old, content_old;
1419 Blocked2Moving(lx, ly, &oldx, &oldy);
1422 horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
1423 MovDir[oldx][oldy] == MV_RIGHT);
1425 element_old = Feld[oldx][oldy];
1426 content_old = Store[oldx][oldy];
1428 if (element_old == EL_QUICKSAND_EMPTYING ||
1429 element_old == EL_MAGIC_WALL_EMPTYING ||
1430 element_old == EL_BD_MAGIC_WALL_EMPTYING ||
1431 element_old == EL_AMOEBA_DROPPING)
1432 cut_mode = CUT_ABOVE;
1434 DrawScreenElement(x, y, EL_EMPTY);
1437 DrawScreenElementShifted(sx, sy, MovPos[oldx][oldy], 0, element_old,
1439 else if (cut_mode == NO_CUTTING)
1440 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], element_old,
1443 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], content_old,
1446 else if (IS_DRAWABLE(element))
1447 DrawScreenElement(x, y, element);
1449 DrawScreenElement(x, y, EL_EMPTY);
1452 void DrawLevelField(int x, int y)
1454 if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1455 DrawScreenField(SCREENX(x), SCREENY(y));
1456 else if (IS_MOVING(x, y))
1460 Moving2Blocked(x, y, &newx, &newy);
1461 if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
1462 DrawScreenField(SCREENX(newx), SCREENY(newy));
1464 else if (IS_BLOCKED(x, y))
1468 Blocked2Moving(x, y, &oldx, &oldy);
1469 if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
1470 DrawScreenField(SCREENX(oldx), SCREENY(oldy));
1474 void DrawMiniElement(int x, int y, int element)
1478 graphic = el2edimg(element);
1479 DrawMiniGraphic(x, y, graphic);
1482 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
1484 int x = sx + scroll_x, y = sy + scroll_y;
1486 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
1487 DrawMiniElement(sx, sy, EL_EMPTY);
1488 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
1489 DrawMiniElement(sx, sy, Feld[x][y]);
1491 DrawMiniGraphic(sx, sy, el2edimg(getBorderElement(x, y)));
1494 void getMicroGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
1496 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
1497 int mini_startx = src_bitmap->width * 3 / 4;
1498 int mini_starty = src_bitmap->height * 2 / 3;
1499 int src_x = mini_startx + graphic_info[graphic].src_x / 8;
1500 int src_y = mini_starty + graphic_info[graphic].src_y / 8;
1502 if (src_x + MICRO_TILEX > src_bitmap->width ||
1503 src_y + MICRO_TILEY > src_bitmap->height)
1505 /* graphic of desired size seems not to be contained in this image;
1506 dirty workaround: get it from the middle of the normal sized image */
1508 getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
1509 src_x += (TILEX / 2 - MICRO_TILEX / 2);
1510 src_y += (TILEY / 2 - MICRO_TILEY / 2);
1513 *bitmap = src_bitmap;
1518 void DrawMicroElement(int xpos, int ypos, int element)
1522 int graphic = el2preimg(element);
1524 getMicroGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
1525 BlitBitmap(src_bitmap, drawto, src_x, src_y, MICRO_TILEX, MICRO_TILEY,
1533 SetDrawBackgroundMask(REDRAW_NONE);
1536 for(x=BX1; x<=BX2; x++)
1537 for(y=BY1; y<=BY2; y++)
1538 DrawScreenField(x, y);
1540 redraw_mask |= REDRAW_FIELD;
1543 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
1547 for(x=0; x<size_x; x++)
1548 for(y=0; y<size_y; y++)
1549 DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
1551 redraw_mask |= REDRAW_FIELD;
1554 static void DrawMicroLevelExt(int xpos, int ypos, int from_x, int from_y)
1558 DrawBackground(xpos, ypos, MICROLEV_XSIZE, MICROLEV_YSIZE);
1560 if (lev_fieldx < STD_LEV_FIELDX)
1561 xpos += (STD_LEV_FIELDX - lev_fieldx) / 2 * MICRO_TILEX;
1562 if (lev_fieldy < STD_LEV_FIELDY)
1563 ypos += (STD_LEV_FIELDY - lev_fieldy) / 2 * MICRO_TILEY;
1565 xpos += MICRO_TILEX;
1566 ypos += MICRO_TILEY;
1568 for(x=-1; x<=STD_LEV_FIELDX; x++)
1570 for(y=-1; y<=STD_LEV_FIELDY; y++)
1572 int lx = from_x + x, ly = from_y + y;
1574 if (lx >= 0 && lx < lev_fieldx && ly >= 0 && ly < lev_fieldy)
1575 DrawMicroElement(xpos + x * MICRO_TILEX, ypos + y * MICRO_TILEY,
1577 else if (lx >= -1 && lx < lev_fieldx+1 && ly >= -1 && ly < lev_fieldy+1
1578 && BorderElement != EL_EMPTY)
1579 DrawMicroElement(xpos + x * MICRO_TILEX, ypos + y * MICRO_TILEY,
1580 getBorderElement(lx, ly));
1584 redraw_mask |= REDRAW_MICROLEVEL;
1587 #define MICROLABEL_EMPTY 0
1588 #define MICROLABEL_LEVEL_NAME 1
1589 #define MICROLABEL_CREATED_BY 2
1590 #define MICROLABEL_LEVEL_AUTHOR 3
1591 #define MICROLABEL_IMPORTED_FROM 4
1592 #define MICROLABEL_LEVEL_IMPORT_INFO 5
1594 static void DrawMicroLevelLabelExt(int mode)
1596 char label_text[MAX_OUTPUT_LINESIZE + 1];
1597 int max_len_label_text;
1598 int font_nr = FONT_TEXT_2;
1600 if (mode == MICROLABEL_CREATED_BY || mode == MICROLABEL_IMPORTED_FROM)
1601 font_nr = FONT_TEXT_3;
1603 max_len_label_text = SXSIZE / getFontWidth(font_nr);
1605 DrawBackground(SX, MICROLABEL_YPOS, SXSIZE, getFontHeight(font_nr));
1607 strncpy(label_text, (mode == MICROLABEL_LEVEL_NAME ? level.name :
1608 mode == MICROLABEL_CREATED_BY ? "created by" :
1609 mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
1610 mode == MICROLABEL_IMPORTED_FROM ? "imported from" :
1611 mode == MICROLABEL_LEVEL_IMPORT_INFO ?
1612 leveldir_current->imported_from : ""),
1613 max_len_label_text);
1614 label_text[max_len_label_text] = '\0';
1616 if (strlen(label_text) > 0)
1618 int text_width = strlen(label_text) * getFontWidth(font_nr);
1619 int lxpos = SX + (SXSIZE - text_width) / 2;
1620 int lypos = MICROLABEL_YPOS;
1622 DrawText(lxpos, lypos, label_text, font_nr);
1625 redraw_mask |= REDRAW_MICROLEVEL;
1628 void DrawMicroLevel(int xpos, int ypos, boolean restart)
1630 static unsigned long scroll_delay = 0;
1631 static unsigned long label_delay = 0;
1632 static int from_x, from_y, scroll_direction;
1633 static int label_state, label_counter;
1634 int last_game_status = game_status; /* save current game status */
1636 game_status = PSEUDO_PREVIEW; /* force PREVIEW font on preview level */
1640 from_x = from_y = 0;
1641 scroll_direction = MV_RIGHT;
1645 DrawMicroLevelExt(xpos, ypos, from_x, from_y);
1646 DrawMicroLevelLabelExt(label_state);
1648 /* initialize delay counters */
1649 DelayReached(&scroll_delay, 0);
1650 DelayReached(&label_delay, 0);
1652 if (leveldir_current->name)
1654 int len = strlen(leveldir_current->name);
1655 int lxpos = SX + (SXSIZE - len * getFontWidth(FONT_TEXT_1)) / 2;
1656 int lypos = SY + 352;
1658 DrawText(lxpos, lypos, leveldir_current->name, FONT_TEXT_1);
1661 game_status = last_game_status; /* restore current game status */
1666 /* scroll micro level, if needed */
1667 if ((lev_fieldx > STD_LEV_FIELDX || lev_fieldy > STD_LEV_FIELDY) &&
1668 DelayReached(&scroll_delay, MICROLEVEL_SCROLL_DELAY))
1670 switch (scroll_direction)
1676 scroll_direction = MV_UP;
1680 if (from_x < lev_fieldx - STD_LEV_FIELDX)
1683 scroll_direction = MV_DOWN;
1690 scroll_direction = MV_RIGHT;
1694 if (from_y < lev_fieldy - STD_LEV_FIELDY)
1697 scroll_direction = MV_LEFT;
1704 DrawMicroLevelExt(xpos, ypos, from_x, from_y);
1707 /* redraw micro level label, if needed */
1708 if (strcmp(level.name, NAMELESS_LEVEL_NAME) != 0 &&
1709 strcmp(level.author, ANONYMOUS_NAME) != 0 &&
1710 strcmp(level.author, leveldir_current->name) != 0 &&
1711 DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
1713 int max_label_counter = 23;
1715 if (leveldir_current->imported_from != NULL)
1716 max_label_counter += 14;
1718 label_counter = (label_counter + 1) % max_label_counter;
1719 label_state = (label_counter >= 0 && label_counter <= 7 ?
1720 MICROLABEL_LEVEL_NAME :
1721 label_counter >= 9 && label_counter <= 12 ?
1722 MICROLABEL_CREATED_BY :
1723 label_counter >= 14 && label_counter <= 21 ?
1724 MICROLABEL_LEVEL_AUTHOR :
1725 label_counter >= 23 && label_counter <= 26 ?
1726 MICROLABEL_IMPORTED_FROM :
1727 label_counter >= 28 && label_counter <= 35 ?
1728 MICROLABEL_LEVEL_IMPORT_INFO : MICROLABEL_EMPTY);
1729 DrawMicroLevelLabelExt(label_state);
1732 game_status = last_game_status; /* restore current game status */
1735 int REQ_in_range(int x, int y)
1737 if (y > DY+249 && y < DY+278)
1739 if (x > DX+1 && x < DX+48)
1741 else if (x > DX+51 && x < DX+98)
1747 #define MAX_REQUEST_LINES 13
1748 #define MAX_REQUEST_LINE_LEN 7
1750 boolean Request(char *text, unsigned int req_state)
1752 int mx, my, ty, result = -1;
1753 unsigned int old_door_state;
1754 int last_game_status = game_status; /* save current game status */
1756 #if defined(PLATFORM_UNIX)
1757 /* pause network game while waiting for request to answer */
1758 if (options.network &&
1759 game_status == PLAYING &&
1760 req_state & REQUEST_WAIT_FOR)
1761 SendToServer_PausePlaying();
1764 old_door_state = GetDoorState();
1768 CloseDoor(DOOR_CLOSE_1);
1770 /* save old door content */
1771 BlitBitmap(bitmap_db_door, bitmap_db_door,
1772 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
1773 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
1775 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
1777 /* clear door drawing field */
1778 DrawBackground(DX, DY, DXSIZE, DYSIZE);
1780 game_status = PSEUDO_DOOR; /* force DOOR font on preview level */
1782 /* write text for request */
1783 for(ty=0; ty < MAX_REQUEST_LINES; ty++)
1785 char text_line[MAX_REQUEST_LINE_LEN + 1];
1791 for(tl=0,tx=0; tx < MAX_REQUEST_LINE_LEN; tl++,tx++)
1794 if (!tc || tc == ' ')
1805 strncpy(text_line, text, tl);
1808 DrawText(DX + (DXSIZE - tl * getFontWidth(FONT_TEXT_2)) / 2,
1809 DY + 8 + ty * (getFontHeight(FONT_TEXT_2) + 2),
1810 text_line, FONT_TEXT_2);
1812 text += tl + (tc == ' ' ? 1 : 0);
1815 game_status = last_game_status; /* restore current game status */
1817 if (req_state & REQ_ASK)
1819 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
1820 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
1822 else if (req_state & REQ_CONFIRM)
1824 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
1826 else if (req_state & REQ_PLAYER)
1828 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
1829 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
1830 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
1831 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
1834 /* copy request gadgets to door backbuffer */
1835 BlitBitmap(drawto, bitmap_db_door,
1836 DX, DY, DXSIZE, DYSIZE,
1837 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
1839 OpenDoor(DOOR_OPEN_1);
1845 if (!(req_state & REQUEST_WAIT_FOR))
1847 SetDrawBackgroundMask(REDRAW_FIELD);
1852 if (game_status != MAINMENU)
1855 button_status = MB_RELEASED;
1857 request_gadget_id = -1;
1859 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
1871 case EVENT_BUTTONPRESS:
1872 case EVENT_BUTTONRELEASE:
1873 case EVENT_MOTIONNOTIFY:
1875 if (event.type == EVENT_MOTIONNOTIFY)
1877 if (!PointerInWindow(window))
1878 continue; /* window and pointer are on different screens */
1883 motion_status = TRUE;
1884 mx = ((MotionEvent *) &event)->x;
1885 my = ((MotionEvent *) &event)->y;
1889 motion_status = FALSE;
1890 mx = ((ButtonEvent *) &event)->x;
1891 my = ((ButtonEvent *) &event)->y;
1892 if (event.type == EVENT_BUTTONPRESS)
1893 button_status = ((ButtonEvent *) &event)->button;
1895 button_status = MB_RELEASED;
1898 /* this sets 'request_gadget_id' */
1899 HandleGadgets(mx, my, button_status);
1901 switch(request_gadget_id)
1903 case TOOL_CTRL_ID_YES:
1906 case TOOL_CTRL_ID_NO:
1909 case TOOL_CTRL_ID_CONFIRM:
1910 result = TRUE | FALSE;
1913 case TOOL_CTRL_ID_PLAYER_1:
1916 case TOOL_CTRL_ID_PLAYER_2:
1919 case TOOL_CTRL_ID_PLAYER_3:
1922 case TOOL_CTRL_ID_PLAYER_4:
1933 case EVENT_KEYPRESS:
1934 switch(GetEventKey((KeyEvent *)&event, TRUE))
1947 if (req_state & REQ_PLAYER)
1951 case EVENT_KEYRELEASE:
1952 ClearPlayerAction();
1956 HandleOtherEvents(&event);
1960 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
1962 int joy = AnyJoystick();
1964 if (joy & JOY_BUTTON_1)
1966 else if (joy & JOY_BUTTON_2)
1972 /* don't eat all CPU time */
1976 if (game_status != MAINMENU)
1981 if (!(req_state & REQ_STAY_OPEN))
1983 CloseDoor(DOOR_CLOSE_1);
1985 if (!(req_state & REQ_STAY_CLOSED) && (old_door_state & DOOR_OPEN_1))
1987 BlitBitmap(bitmap_db_door, bitmap_db_door,
1988 DOOR_GFX_PAGEX2,DOOR_GFX_PAGEY1, DXSIZE,DYSIZE,
1989 DOOR_GFX_PAGEX1,DOOR_GFX_PAGEY1);
1990 OpenDoor(DOOR_OPEN_1);
1996 SetDrawBackgroundMask(REDRAW_FIELD);
1998 #if defined(PLATFORM_UNIX)
1999 /* continue network game after request */
2000 if (options.network &&
2001 game_status == PLAYING &&
2002 req_state & REQUEST_WAIT_FOR)
2003 SendToServer_ContinuePlaying();
2009 unsigned int OpenDoor(unsigned int door_state)
2011 unsigned int new_door_state;
2013 if (door_state & DOOR_COPY_BACK)
2015 BlitBitmap(bitmap_db_door, bitmap_db_door,
2016 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE + VYSIZE,
2017 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2018 door_state &= ~DOOR_COPY_BACK;
2021 new_door_state = MoveDoor(door_state);
2023 return(new_door_state);
2026 unsigned int CloseDoor(unsigned int door_state)
2028 unsigned int new_door_state;
2030 BlitBitmap(backbuffer, bitmap_db_door,
2031 DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2032 BlitBitmap(backbuffer, bitmap_db_door,
2033 VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
2035 new_door_state = MoveDoor(door_state);
2037 return(new_door_state);
2040 unsigned int GetDoorState()
2042 return MoveDoor(DOOR_GET_STATE);
2045 unsigned int SetDoorState(unsigned int door_state)
2047 return MoveDoor(door_state | DOOR_SET_STATE);
2050 unsigned int MoveDoor(unsigned int door_state)
2052 static int door1 = DOOR_OPEN_1;
2053 static int door2 = DOOR_CLOSE_2;
2054 static unsigned long door_delay = 0;
2055 int x, start, stepsize = 2;
2056 unsigned long door_delay_value = stepsize * 5;
2058 if (door_state == DOOR_GET_STATE)
2059 return(door1 | door2);
2061 if (door_state & DOOR_SET_STATE)
2063 if (door_state & DOOR_ACTION_1)
2064 door1 = door_state & DOOR_ACTION_1;
2065 if (door_state & DOOR_ACTION_2)
2066 door2 = door_state & DOOR_ACTION_2;
2068 return(door1 | door2);
2071 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
2072 door_state &= ~DOOR_OPEN_1;
2073 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
2074 door_state &= ~DOOR_CLOSE_1;
2075 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
2076 door_state &= ~DOOR_OPEN_2;
2077 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
2078 door_state &= ~DOOR_CLOSE_2;
2080 if (setup.quick_doors)
2083 door_delay_value = 0;
2085 StopSound(SND_MENU_DOOR_OPENING);
2086 StopSound(SND_MENU_DOOR_CLOSING);
2089 if (global.autoplay_leveldir)
2091 door_state |= DOOR_NO_DELAY;
2092 door_state &= ~DOOR_CLOSE_ALL;
2095 if (door_state & DOOR_ACTION)
2097 if (!(door_state & DOOR_NO_DELAY))
2099 /* opening door sound has priority over simultaneously closing door */
2100 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
2101 PlaySoundStereo(SND_MENU_DOOR_OPENING, SOUND_MAX_RIGHT);
2102 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
2103 PlaySoundStereo(SND_MENU_DOOR_CLOSING, SOUND_MAX_RIGHT);
2106 start = ((door_state & DOOR_NO_DELAY) ? DXSIZE : 0);
2108 for(x=start; x<=DXSIZE; x+=stepsize)
2110 Bitmap *bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
2111 GC gc = bitmap->stored_clip_gc;
2113 if (!(door_state & DOOR_NO_DELAY))
2114 WaitUntilDelayReached(&door_delay, door_delay_value);
2116 if (door_state & DOOR_ACTION_1)
2118 int i = (door_state & DOOR_OPEN_1 ? DXSIZE-x : x);
2119 int j = (DXSIZE - i) / 3;
2121 BlitBitmap(bitmap_db_door, drawto,
2122 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + i/2,
2123 DXSIZE,DYSIZE - i/2, DX, DY);
2125 ClearRectangle(drawto, DX, DY + DYSIZE - i/2, DXSIZE,i/2);
2127 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2128 BlitBitmapMasked(bitmap, drawto,
2129 DXSIZE, DOOR_GFX_PAGEY1, i, 77,
2130 DX + DXSIZE - i, DY + j);
2131 BlitBitmapMasked(bitmap, drawto,
2132 DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63,
2133 DX + DXSIZE - i, DY + 140 + j);
2134 SetClipOrigin(bitmap, gc, DX - DXSIZE + i, DY - (DOOR_GFX_PAGEY1 + j));
2135 BlitBitmapMasked(bitmap, drawto,
2136 DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j,
2138 BlitBitmapMasked(bitmap, drawto,
2139 DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63,
2142 BlitBitmapMasked(bitmap, drawto,
2143 DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
2145 BlitBitmapMasked(bitmap, drawto,
2146 DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
2148 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2149 BlitBitmapMasked(bitmap, drawto,
2150 DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
2151 DX + DXSIZE - i, DY + 77 + j);
2152 BlitBitmapMasked(bitmap, drawto,
2153 DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
2154 DX + DXSIZE - i, DY + 203 + j);
2156 redraw_mask |= REDRAW_DOOR_1;
2159 if (door_state & DOOR_ACTION_2)
2161 int i = (door_state & DOOR_OPEN_2 ? VXSIZE - x : x);
2162 int j = (VXSIZE - i) / 3;
2164 BlitBitmap(bitmap_db_door, drawto,
2165 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + i/2,
2166 VXSIZE, VYSIZE - i/2, VX, VY);
2168 ClearRectangle(drawto, VX, VY + VYSIZE-i/2, VXSIZE, i/2);
2170 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2171 BlitBitmapMasked(bitmap, drawto,
2172 VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2,
2173 VX + VXSIZE-i, VY+j);
2174 SetClipOrigin(bitmap, gc,
2175 VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
2176 BlitBitmapMasked(bitmap, drawto,
2177 VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j,
2180 BlitBitmapMasked(bitmap, drawto,
2181 VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2,
2182 i, VYSIZE / 2, VX, VY + VYSIZE / 2 - j);
2183 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2184 BlitBitmapMasked(bitmap, drawto,
2185 VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2,
2187 VX + VXSIZE - i, VY + VYSIZE / 2 + j);
2189 redraw_mask |= REDRAW_DOOR_2;
2194 if (game_status == MAINMENU)
2199 if (setup.quick_doors)
2201 StopSound(SND_MENU_DOOR_OPENING);
2202 StopSound(SND_MENU_DOOR_CLOSING);
2205 if (door_state & DOOR_ACTION_1)
2206 door1 = door_state & DOOR_ACTION_1;
2207 if (door_state & DOOR_ACTION_2)
2208 door2 = door_state & DOOR_ACTION_2;
2210 return (door1 | door2);
2213 void DrawSpecialEditorDoor()
2215 /* draw bigger toolbox window */
2216 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
2217 DOOR_GFX_PAGEX7, 0, EXSIZE + 8, 8,
2219 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
2220 EX - 4, VY - 4, EXSIZE + 8, EYSIZE - VYSIZE + 4,
2223 redraw_mask |= REDRAW_ALL;
2226 void UndrawSpecialEditorDoor()
2228 /* draw normal tape recorder window */
2229 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
2230 EX - 4, EY - 12, EXSIZE + 8, EYSIZE - VYSIZE + 12,
2233 redraw_mask |= REDRAW_ALL;
2237 int ReadPixel(DrawBuffer *bitmap, int x, int y)
2239 XImage *pixel_image;
2240 unsigned long pixel_value;
2242 pixel_image = XGetImage(display, bitmap->drawable,
2243 x, y, 1, 1, AllPlanes, ZPixmap);
2244 pixel_value = XGetPixel(pixel_image, 0, 0);
2246 XDestroyImage(pixel_image);
2252 /* ---------- new tool button stuff ---------------------------------------- */
2254 /* graphic position values for tool buttons */
2255 #define TOOL_BUTTON_YES_XPOS 2
2256 #define TOOL_BUTTON_YES_YPOS 250
2257 #define TOOL_BUTTON_YES_GFX_YPOS 0
2258 #define TOOL_BUTTON_YES_XSIZE 46
2259 #define TOOL_BUTTON_YES_YSIZE 28
2260 #define TOOL_BUTTON_NO_XPOS 52
2261 #define TOOL_BUTTON_NO_YPOS TOOL_BUTTON_YES_YPOS
2262 #define TOOL_BUTTON_NO_GFX_YPOS TOOL_BUTTON_YES_GFX_YPOS
2263 #define TOOL_BUTTON_NO_XSIZE TOOL_BUTTON_YES_XSIZE
2264 #define TOOL_BUTTON_NO_YSIZE TOOL_BUTTON_YES_YSIZE
2265 #define TOOL_BUTTON_CONFIRM_XPOS TOOL_BUTTON_YES_XPOS
2266 #define TOOL_BUTTON_CONFIRM_YPOS TOOL_BUTTON_YES_YPOS
2267 #define TOOL_BUTTON_CONFIRM_GFX_YPOS 30
2268 #define TOOL_BUTTON_CONFIRM_XSIZE 96
2269 #define TOOL_BUTTON_CONFIRM_YSIZE TOOL_BUTTON_YES_YSIZE
2270 #define TOOL_BUTTON_PLAYER_XSIZE 30
2271 #define TOOL_BUTTON_PLAYER_YSIZE 30
2272 #define TOOL_BUTTON_PLAYER_GFX_XPOS 5
2273 #define TOOL_BUTTON_PLAYER_GFX_YPOS 185
2274 #define TOOL_BUTTON_PLAYER_XPOS (5 + TOOL_BUTTON_PLAYER_XSIZE / 2)
2275 #define TOOL_BUTTON_PLAYER_YPOS (215 - TOOL_BUTTON_PLAYER_YSIZE / 2)
2276 #define TOOL_BUTTON_PLAYER1_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2277 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2278 #define TOOL_BUTTON_PLAYER2_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2279 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2280 #define TOOL_BUTTON_PLAYER3_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2281 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2282 #define TOOL_BUTTON_PLAYER4_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2283 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2284 #define TOOL_BUTTON_PLAYER1_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2285 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2286 #define TOOL_BUTTON_PLAYER2_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2287 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2288 #define TOOL_BUTTON_PLAYER3_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2289 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2290 #define TOOL_BUTTON_PLAYER4_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2291 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2300 } toolbutton_info[NUM_TOOL_BUTTONS] =
2303 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_GFX_YPOS,
2304 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_YPOS,
2305 TOOL_BUTTON_YES_XSIZE, TOOL_BUTTON_YES_YSIZE,
2310 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_GFX_YPOS,
2311 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_YPOS,
2312 TOOL_BUTTON_NO_XSIZE, TOOL_BUTTON_NO_YSIZE,
2317 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_GFX_YPOS,
2318 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_YPOS,
2319 TOOL_BUTTON_CONFIRM_XSIZE, TOOL_BUTTON_CONFIRM_YSIZE,
2320 TOOL_CTRL_ID_CONFIRM,
2324 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2325 TOOL_BUTTON_PLAYER1_XPOS, TOOL_BUTTON_PLAYER1_YPOS,
2326 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2327 TOOL_CTRL_ID_PLAYER_1,
2331 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2332 TOOL_BUTTON_PLAYER2_XPOS, TOOL_BUTTON_PLAYER2_YPOS,
2333 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2334 TOOL_CTRL_ID_PLAYER_2,
2338 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2339 TOOL_BUTTON_PLAYER3_XPOS, TOOL_BUTTON_PLAYER3_YPOS,
2340 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2341 TOOL_CTRL_ID_PLAYER_3,
2345 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2346 TOOL_BUTTON_PLAYER4_XPOS, TOOL_BUTTON_PLAYER4_YPOS,
2347 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2348 TOOL_CTRL_ID_PLAYER_4,
2353 void CreateToolButtons()
2357 for (i=0; i<NUM_TOOL_BUTTONS; i++)
2359 Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
2360 Bitmap *deco_bitmap = None;
2361 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
2362 struct GadgetInfo *gi;
2363 unsigned long event_mask;
2364 int gd_xoffset, gd_yoffset;
2365 int gd_x1, gd_x2, gd_y;
2368 event_mask = GD_EVENT_RELEASED;
2370 gd_xoffset = toolbutton_info[i].xpos;
2371 gd_yoffset = toolbutton_info[i].ypos;
2372 gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
2373 gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
2374 gd_y = DOOR_GFX_PAGEY1 + gd_yoffset;
2376 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
2378 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
2380 getMiniGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr),
2381 &deco_bitmap, &deco_x, &deco_y);
2382 deco_xpos = (toolbutton_info[i].width - MINI_TILEX) / 2;
2383 deco_ypos = (toolbutton_info[i].height - MINI_TILEY) / 2;
2386 gi = CreateGadget(GDI_CUSTOM_ID, id,
2387 GDI_INFO_TEXT, toolbutton_info[i].infotext,
2388 GDI_X, DX + toolbutton_info[i].x,
2389 GDI_Y, DY + toolbutton_info[i].y,
2390 GDI_WIDTH, toolbutton_info[i].width,
2391 GDI_HEIGHT, toolbutton_info[i].height,
2392 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
2393 GDI_STATE, GD_BUTTON_UNPRESSED,
2394 GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
2395 GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
2396 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
2397 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
2398 GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
2399 GDI_DECORATION_SHIFTING, 1, 1,
2400 GDI_EVENT_MASK, event_mask,
2401 GDI_CALLBACK_ACTION, HandleToolButtons,
2405 Error(ERR_EXIT, "cannot create gadget");
2407 tool_gadget[id] = gi;
2411 void FreeToolButtons()
2415 for (i=0; i<NUM_TOOL_BUTTONS; i++)
2416 FreeGadget(tool_gadget[i]);
2419 static void UnmapToolButtons()
2423 for (i=0; i<NUM_TOOL_BUTTONS; i++)
2424 UnmapGadget(tool_gadget[i]);
2427 static void HandleToolButtons(struct GadgetInfo *gi)
2429 request_gadget_id = gi->custom_id;
2432 int get_next_element(int element)
2436 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
2437 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
2438 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
2439 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
2440 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
2441 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
2442 case EL_AMOEBA_DROPPING: return EL_AMOEBA_WET;
2444 default: return element;
2448 int el_act_dir2img(int element, int action, int direction)
2450 direction = MV_DIR_BIT(direction);
2452 return element_info[element].direction_graphic[action][direction];
2455 int el_act2img(int element, int action)
2457 return element_info[element].graphic[action];
2460 int el_dir2img(int element, int direction)
2462 return el_act_dir2img(element, ACTION_DEFAULT, direction);
2465 int el2img(int element)
2467 return element_info[element].graphic[ACTION_DEFAULT];
2470 int el2edimg(int element)
2472 return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
2475 int el2preimg(int element)
2477 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];