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);
545 int current_action = ACTION_DEFAULT;
547 if (!player->active || !IN_SCR_FIELD(SCREENX(last_jx), SCREENY(last_jy)))
551 if (!IN_LEV_FIELD(jx,jy))
553 printf("DrawPlayerField(): x = %d, y = %d\n",jx,jy);
554 printf("DrawPlayerField(): sx = %d, sy = %d\n",sx,sy);
555 printf("DrawPlayerField(): This should never happen!\n");
560 if (element == EL_EXPLOSION)
563 current_action = (player->Pushing ? ACTION_PUSHING :
564 player->is_digging ? ACTION_DIGGING :
565 player->is_collecting ? ACTION_COLLECTING :
566 player->is_moving ? ACTION_MOVING :
567 player->snapped ? ACTION_SNAPPING : ACTION_DEFAULT);
569 InitPlayerGfxAnimation(player, current_action, player->MovDir);
571 /* ----------------------------------------------------------------------- */
572 /* draw things in the field the player is leaving, if needed */
573 /* ----------------------------------------------------------------------- */
575 if (player_is_moving)
577 if (Store[last_jx][last_jy] && IS_DRAWABLE(last_element))
579 DrawLevelElement(last_jx, last_jy, Store[last_jx][last_jy]);
581 if (last_element == EL_DYNAMITE_ACTIVE ||
582 last_element == EL_SP_DISK_RED_ACTIVE)
583 DrawDynamite(last_jx, last_jy);
585 DrawLevelFieldThruMask(last_jx, last_jy);
587 else if (last_element == EL_DYNAMITE_ACTIVE ||
588 last_element == EL_SP_DISK_RED_ACTIVE)
589 DrawDynamite(last_jx, last_jy);
591 DrawLevelField(last_jx, last_jy);
593 if (player->Pushing && IN_SCR_FIELD(SCREENX(next_jx), SCREENY(next_jy)))
597 if (Feld[next_jx][next_jy] == EL_SOKOBAN_FIELD_FULL)
598 DrawLevelElement(next_jx, next_jy, EL_SOKOBAN_FIELD_EMPTY);
600 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
603 DrawLevelField(next_jx, next_jy);
607 if (!IN_SCR_FIELD(sx, sy))
610 if (setup.direct_draw)
611 SetDrawtoField(DRAW_BUFFERED);
613 /* ----------------------------------------------------------------------- */
614 /* draw things behind the player, if needed */
615 /* ----------------------------------------------------------------------- */
618 DrawLevelElement(jx, jy, Store[jx][jy]);
619 else if (IS_ACTIVE_BOMB(element))
620 DrawLevelElement(jx, jy, EL_EMPTY);
623 if (player_is_moving && GfxElement[jx][jy] != EL_UNDEFINED)
625 int old_element = GfxElement[jx][jy];
627 el_act_dir2img(old_element, ACTION_DIGGING, player->MovDir);
628 int frame = getGraphicAnimationFrame(old_graphic, player->StepFrame);
633 int width = TILEX, height = TILEY;
636 if (player->MovDir == MV_UP)
641 else if (player->MovDir == MV_DOWN)
644 height = TILEY - player->GfxPos;
646 else if (player->MovDir == MV_LEFT)
651 else if (player->MovDir == MV_RIGHT)
654 width = TILEX - player->GfxPos;
657 getGraphicSource(old_graphic, frame, &src_bitmap, &src_x, &src_y);
659 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
660 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
663 printf("::: %d, %d, %d, %d => %d, %d [%d, %d, %d]\n",
664 old_element, ACTION_DIGGING, player->MovDir, player->Frame,
666 player->MovPos, player->GfxPos, player->StepFrame);
669 DrawGraphic(sx, sy, old_graphic, frame);
674 GfxElement[jx][jy] = EL_UNDEFINED;
676 DrawLevelField(jx, jy);
680 /* ----------------------------------------------------------------------- */
681 /* draw player himself */
682 /* ----------------------------------------------------------------------- */
684 if (player->use_murphy_graphic)
686 static int last_horizontal_dir = MV_LEFT;
689 if (player->MovDir == MV_LEFT || player->MovDir == MV_RIGHT)
690 last_horizontal_dir = player->MovDir;
692 direction = (player->snapped ? player->MovDir : last_horizontal_dir);
694 graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, direction);
697 graphic = el_act_dir2img(player->element_nr, player->GfxAction,
700 frame = getGraphicAnimationFrame(graphic, player->Frame);
704 if (player->MovDir == MV_LEFT || player->MovDir == MV_RIGHT)
705 sxx = player->GfxPos;
707 syy = player->GfxPos;
710 if (!setup.soft_scrolling && ScreenMovPos)
713 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
715 if (SHIELD_ON(player))
717 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
718 IMG_SHIELD_NORMAL_ACTIVE);
719 int frame = getGraphicAnimationFrame(graphic, -1);
721 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
724 /* ----------------------------------------------------------------------- */
725 /* draw things the player is pushing, if needed */
726 /* ----------------------------------------------------------------------- */
728 if (player->Pushing && player_is_moving)
730 int px = SCREENX(next_jx), py = SCREENY(next_jy);
733 (element == EL_SOKOBAN_FIELD_EMPTY ||
734 Feld[next_jx][next_jy] == EL_SOKOBAN_FIELD_FULL))
735 DrawGraphicShiftedThruMask(px, py, sxx, syy, IMG_SOKOBAN_OBJECT, 0,
739 int element = Feld[next_jx][next_jy];
740 int graphic = el2img(element);
743 if ((sxx || syy) && IS_PUSHABLE(element))
745 graphic = el_act_dir2img(element, ACTION_MOVING, player->MovDir);
746 frame = getGraphicAnimationFrame(graphic, player->Frame);
749 DrawGraphicShifted(px, py, sxx, syy, graphic, frame,
750 NO_CUTTING, NO_MASKING);
754 /* ----------------------------------------------------------------------- */
755 /* draw things in front of player (active dynamite or dynabombs) */
756 /* ----------------------------------------------------------------------- */
758 if (IS_ACTIVE_BOMB(element))
760 graphic = el2img(element);
761 frame = getGraphicAnimationFrame(graphic, GfxFrame[jx][jy]);
763 if (game.emulation == EMU_SUPAPLEX)
764 DrawGraphic(sx, sy, IMG_SP_DISK_RED, frame);
766 DrawGraphicThruMask(sx, sy, graphic, frame);
769 if (player_is_moving && last_element == EL_EXPLOSION)
771 int stored = Store[last_jx][last_jy];
772 int graphic = (game.emulation != EMU_SUPAPLEX ? IMG_EXPLOSION :
773 stored == EL_SP_INFOTRON ? IMG_SP_EXPLOSION_INFOTRON :
775 int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
776 int phase = ExplodePhase[last_jx][last_jy] - 1;
777 int frame = getGraphicAnimationFrame(graphic, phase - delay);
780 DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy), graphic, frame);
783 /* ----------------------------------------------------------------------- */
784 /* draw elements that stay over the player */
785 /* ----------------------------------------------------------------------- */
787 /* handle the field the player is leaving ... */
788 if (player_is_moving && IS_OVER_PLAYER(last_element))
789 DrawLevelField(last_jx, last_jy);
791 /* ... and the field the player is entering */
792 if (IS_OVER_PLAYER(element))
793 DrawLevelField(jx, jy);
795 if (setup.direct_draw)
797 int dest_x = SX + SCREENX(MIN(jx, last_jx)) * TILEX;
798 int dest_y = SY + SCREENY(MIN(jy, last_jy)) * TILEY;
799 int x_size = TILEX * (1 + ABS(jx - last_jx));
800 int y_size = TILEY * (1 + ABS(jy - last_jy));
802 BlitBitmap(drawto_field, window,
803 dest_x, dest_y, x_size, y_size, dest_x, dest_y);
804 SetDrawtoField(DRAW_DIRECT);
807 MarkTileDirty(sx,sy);
810 void getGraphicSource(int graphic, int frame, Bitmap **bitmap, int *x, int *y)
812 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
813 int offset_x = graphic_info[graphic].offset_x;
814 int offset_y = graphic_info[graphic].offset_y;
815 int src_x = graphic_info[graphic].src_x + frame * offset_x;
816 int src_y = graphic_info[graphic].src_y + frame * offset_y;
818 *bitmap = src_bitmap;
823 void DrawGraphic(int x, int y, int graphic, int frame)
826 if (!IN_SCR_FIELD(x, y))
828 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
829 printf("DrawGraphic(): This should never happen!\n");
834 DrawGraphicExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic, frame);
839 void DrawOldGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic)
844 getOldGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
845 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
849 void DrawGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
856 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
858 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
859 int src_x = graphic_info[graphic].src_x;
860 int src_y = graphic_info[graphic].src_y;
861 int offset_x = graphic_info[graphic].offset_x;
862 int offset_y = graphic_info[graphic].offset_y;
864 src_x += frame * offset_x;
865 src_y += frame * offset_y;
868 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
871 void DrawGraphicThruMask(int x, int y, int graphic, int frame)
874 if (!IN_SCR_FIELD(x, y))
876 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
877 printf("DrawGraphicThruMask(): This should never happen!\n");
882 DrawGraphicThruMaskExt(drawto_field, FX + x * TILEX, FY + y *TILEY, graphic,
887 void DrawGraphicThruMaskExt(DrawBuffer *d, int dest_x, int dest_y, int graphic,
895 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
896 drawing_gc = src_bitmap->stored_clip_gc;
898 GC drawing_gc = src_bitmap->stored_clip_gc;
899 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
900 int src_x = graphic_info[graphic].src_x;
901 int src_y = graphic_info[graphic].src_y;
902 int offset_x = graphic_info[graphic].offset_x;
903 int offset_y = graphic_info[graphic].offset_y;
905 src_x += frame * offset_x;
906 src_y += frame * offset_y;
910 SetClipOrigin(src_bitmap, drawing_gc, dest_x - src_x, dest_y - src_y);
911 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX, TILEY, dest_x, dest_y);
914 void DrawMiniGraphic(int x, int y, int graphic)
916 DrawMiniGraphicExt(drawto, SX + x * MINI_TILEX,SY + y * MINI_TILEY, graphic);
917 MarkTileDirty(x / 2, y / 2);
920 void getMiniGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
922 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
924 int mini_starty = src_bitmap->height * 2 / 3;
925 int src_x = mini_startx + graphic_info[graphic].src_x / 2;
926 int src_y = mini_starty + graphic_info[graphic].src_y / 2;
929 /* !!! not needed anymore, because of automatically created mini graphics */
930 if (src_x + MINI_TILEX > src_bitmap->width ||
931 src_y + MINI_TILEY > src_bitmap->height)
933 /* graphic of desired size seems not to be contained in this image;
934 dirty workaround: get it from the middle of the normal sized image */
936 printf("::: using dirty workaround for %d (%d, %d)\n",
937 graphic, src_bitmap->width, src_bitmap->height);
939 getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
940 src_x += (TILEX / 2 - MINI_TILEX / 2);
941 src_y += (TILEY / 2 - MINI_TILEY / 2);
945 *bitmap = src_bitmap;
950 void DrawMiniGraphicExt(DrawBuffer *d, int x, int y, int graphic)
955 getMiniGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
956 BlitBitmap(src_bitmap, d, src_x, src_y, MINI_TILEX, MINI_TILEY, x, y);
959 void DrawGraphicShifted(int x,int y, int dx,int dy, int graphic, int frame,
960 int cut_mode, int mask_mode)
969 int width = TILEX, height = TILEY;
975 DrawGraphic(x, y, graphic, frame);
979 if (dx || dy) /* shifted graphic */
981 if (x < BX1) /* object enters playfield from the left */
988 else if (x > BX2) /* object enters playfield from the right */
994 else if (x==BX1 && dx < 0) /* object leaves playfield to the left */
1000 else if (x==BX2 && dx > 0) /* object leaves playfield to the right */
1002 else if (dx) /* general horizontal movement */
1003 MarkTileDirty(x + SIGN(dx), y);
1005 if (y < BY1) /* object enters playfield from the top */
1007 if (cut_mode==CUT_BELOW) /* object completely above top border */
1015 else if (y > BY2) /* object enters playfield from the bottom */
1021 else if (y==BY1 && dy < 0) /* object leaves playfield to the top */
1027 else if (dy > 0 && cut_mode == CUT_ABOVE)
1029 if (y == BY2) /* object completely above bottom border */
1035 MarkTileDirty(x, y + 1);
1036 } /* object leaves playfield to the bottom */
1037 else if (dy > 0 && (y == BY2 || cut_mode == CUT_BELOW))
1039 else if (dy) /* general vertical movement */
1040 MarkTileDirty(x, y + SIGN(dy));
1043 src_bitmap = graphic_info[graphic].bitmap;
1044 src_x = graphic_info[graphic].src_x;
1045 src_y = graphic_info[graphic].src_y;
1046 offset_x = graphic_info[graphic].offset_x;
1047 offset_y = graphic_info[graphic].offset_y;
1049 drawing_gc = src_bitmap->stored_clip_gc;
1051 src_x += frame * offset_x;
1052 src_y += frame * offset_y;
1057 dest_x = FX + x * TILEX + dx;
1058 dest_y = FY + y * TILEY + dy;
1061 if (!IN_SCR_FIELD(x,y))
1063 printf("DrawGraphicShifted(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
1064 printf("DrawGraphicShifted(): This should never happen!\n");
1069 if (mask_mode == USE_MASKING)
1071 SetClipOrigin(src_bitmap, drawing_gc, dest_x - src_x, dest_y - src_y);
1072 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1076 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1082 void DrawGraphicShiftedThruMask(int x, int y, int dx, int dy, int graphic,
1083 int frame, int cut_mode)
1085 DrawGraphicShifted(x,y, dx,dy, graphic, frame, cut_mode, USE_MASKING);
1088 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
1089 int cut_mode, int mask_mode)
1091 int lx = LEVELX(x), ly = LEVELY(y);
1095 if (IN_LEV_FIELD(lx, ly))
1097 SetRandomAnimationValue(lx, ly);
1099 graphic = el_act_dir2img(element, GfxAction[lx][ly], MovDir[lx][ly]);
1100 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1102 else /* border element */
1104 graphic = el2img(element);
1105 frame = getGraphicAnimationFrame(graphic, -1);
1108 if (element == EL_EXPANDABLE_WALL)
1110 boolean left_stopped = FALSE, right_stopped = FALSE;
1112 if (!IN_LEV_FIELD(lx - 1, ly) || IS_MAUER(Feld[lx - 1][ly]))
1113 left_stopped = TRUE;
1114 if (!IN_LEV_FIELD(lx + 1, ly) || IS_MAUER(Feld[lx + 1][ly]))
1115 right_stopped = TRUE;
1117 if (left_stopped && right_stopped)
1119 else if (left_stopped)
1121 graphic = IMG_EXPANDABLE_WALL_GROWING_RIGHT;
1122 frame = graphic_info[graphic].anim_frames - 1;
1124 else if (right_stopped)
1126 graphic = IMG_EXPANDABLE_WALL_GROWING_LEFT;
1127 frame = graphic_info[graphic].anim_frames - 1;
1131 else if (IS_AMOEBOID(element) || element == EL_AMOEBA_DROPPING)
1133 graphic = (element == EL_BD_AMOEBA ? IMG_BD_AMOEBA_PART1 :
1134 element == EL_AMOEBA_WET ? IMG_AMOEBA_WET_PART1 :
1135 element == EL_AMOEBA_DRY ? IMG_AMOEBA_DRY_PART1 :
1136 element == EL_AMOEBA_FULL ? IMG_AMOEBA_FULL_PART1 :
1137 IMG_AMOEBA_DEAD_PART1);
1139 graphic += (x + 2 * y + 4) % 4;
1144 if (IS_AMOEBOID(element) || element == EL_AMOEBA_DROPPING)
1146 if (Feld[lx][ly] == EL_AMOEBA_DROPPING)
1147 printf("---> %d -> %d / %d [%d]\n",
1148 element, graphic, frame, GfxRandom[lx][ly]);
1153 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, mask_mode);
1154 else if (mask_mode == USE_MASKING)
1155 DrawGraphicThruMask(x, y, graphic, frame);
1157 DrawGraphic(x, y, graphic, frame);
1160 void DrawLevelElementExt(int x, int y, int dx, int dy, int element,
1161 int cut_mode, int mask_mode)
1163 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1164 DrawScreenElementExt(SCREENX(x), SCREENY(y), dx, dy, element,
1165 cut_mode, mask_mode);
1168 void DrawScreenElementShifted(int x, int y, int dx, int dy, int element,
1171 DrawScreenElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1174 void DrawLevelElementShifted(int x, int y, int dx, int dy, int element,
1177 DrawLevelElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1181 void DrawOldScreenElementThruMask(int x, int y, int element)
1183 DrawOldScreenElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1186 void DrawScreenElementThruMask(int x, int y, int element)
1188 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1192 void DrawLevelElementThruMask(int x, int y, int element)
1194 DrawLevelElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1197 void DrawLevelFieldThruMask(int x, int y)
1199 DrawLevelElementExt(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
1202 void DrawCrumbledSand(int x, int y)
1206 int i, width, height, cx,cy;
1207 int lx = LEVELX(x), ly = LEVELY(y);
1208 int element, graphic;
1210 static int xy[4][2] =
1218 if (!IN_LEV_FIELD(lx, ly))
1221 element = Feld[lx][ly];
1223 if (element == EL_SAND ||
1225 (element == EL_EMPTY_SPACE && GfxElement[lx][ly] == EL_SAND) ||
1227 element == EL_LANDMINE ||
1228 element == EL_TRAP ||
1229 element == EL_TRAP_ACTIVE)
1231 if (!IN_SCR_FIELD(x, y))
1234 graphic = IMG_SAND_CRUMBLED;
1236 src_bitmap = graphic_info[graphic].bitmap;
1237 src_x = graphic_info[graphic].src_x;
1238 src_y = graphic_info[graphic].src_y;
1244 lxx = lx + xy[i][0];
1245 lyy = ly + xy[i][1];
1246 if (!IN_LEV_FIELD(lxx, lyy))
1247 element = EL_STEELWALL;
1249 element = Feld[lxx][lyy];
1251 if (element == EL_SAND ||
1253 (element == EL_EMPTY_SPACE && GfxElement[lxx][lyy] == EL_SAND) ||
1255 element == EL_LANDMINE ||
1256 element == EL_TRAP ||
1257 element == EL_TRAP_ACTIVE)
1260 if (i == 1 || i == 2)
1264 cx = (i == 2 ? TILEX - snip : 0);
1272 cy = (i == 3 ? TILEY - snip : 0);
1275 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1276 width, height, FX + x * TILEX + cx, FY + y * TILEY + cy);
1279 MarkTileDirty(x, y);
1283 graphic = IMG_SAND_CRUMBLED;
1285 src_bitmap = graphic_info[graphic].bitmap;
1286 src_x = graphic_info[graphic].src_x;
1287 src_y = graphic_info[graphic].src_y;
1291 int xx, yy, lxx, lyy;
1295 lxx = lx + xy[i][0];
1296 lyy = ly + xy[i][1];
1298 if (!IN_LEV_FIELD(lxx, lyy) ||
1299 (Feld[lxx][lyy] != EL_SAND &&
1301 !(Feld[lxx][lyy] == EL_EMPTY_SPACE && GfxElement[lxx][lyy] == EL_SAND) &&
1303 Feld[lxx][lyy] != EL_LANDMINE &&
1304 Feld[lxx][lyy] != EL_TRAP &&
1305 Feld[lxx][lyy] != EL_TRAP_ACTIVE) ||
1306 !IN_SCR_FIELD(xx, yy))
1309 if (i == 1 || i == 2)
1313 cx = (i == 1 ? TILEX - snip : 0);
1321 cy = (i==0 ? TILEY-snip : 0);
1324 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1325 width, height, FX + xx * TILEX + cx, FY + yy * TILEY + cy);
1327 MarkTileDirty(xx, yy);
1332 static int getBorderElement(int x, int y)
1336 { EL_STEELWALL_TOPLEFT, EL_INVISIBLE_STEELWALL_TOPLEFT },
1337 { EL_STEELWALL_TOPRIGHT, EL_INVISIBLE_STEELWALL_TOPRIGHT },
1338 { EL_STEELWALL_BOTTOMLEFT, EL_INVISIBLE_STEELWALL_BOTTOMLEFT },
1339 { EL_STEELWALL_BOTTOMRIGHT, EL_INVISIBLE_STEELWALL_BOTTOMRIGHT },
1340 { EL_STEELWALL_VERTICAL, EL_INVISIBLE_STEELWALL_VERTICAL },
1341 { EL_STEELWALL_HORIZONTAL, EL_INVISIBLE_STEELWALL_HORIZONTAL },
1342 { EL_STEELWALL, EL_INVISIBLE_STEELWALL }
1344 int steel_type = (BorderElement == EL_STEELWALL ? 0 : 1);
1345 int steel_position = (x == -1 && y == -1 ? 0 :
1346 x == lev_fieldx && y == -1 ? 1 :
1347 x == -1 && y == lev_fieldy ? 2 :
1348 x == lev_fieldx && y == lev_fieldy ? 3 :
1349 x == -1 || x == lev_fieldx ? 4 :
1350 y == -1 || y == lev_fieldy ? 5 : 6);
1352 return border[steel_position][steel_type];
1355 void DrawScreenElement(int x, int y, int element)
1357 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
1358 DrawCrumbledSand(x, y);
1361 void DrawLevelElement(int x, int y, int element)
1363 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1364 DrawScreenElement(SCREENX(x), SCREENY(y), element);
1367 void DrawScreenField(int x, int y)
1369 int lx = LEVELX(x), ly = LEVELY(y);
1370 int element, content;
1372 if (!IN_LEV_FIELD(lx, ly))
1374 if (lx < -1 || lx > lev_fieldx || ly < -1 || ly > lev_fieldy)
1377 element = getBorderElement(lx, ly);
1379 DrawScreenElement(x, y, element);
1383 element = Feld[lx][ly];
1384 content = Store[lx][ly];
1386 if (IS_MOVING(lx, ly))
1388 int horiz_move = (MovDir[lx][ly] == MV_LEFT || MovDir[lx][ly] == MV_RIGHT);
1389 boolean cut_mode = NO_CUTTING;
1391 if (element == EL_QUICKSAND_EMPTYING ||
1392 element == EL_MAGIC_WALL_EMPTYING ||
1393 element == EL_BD_MAGIC_WALL_EMPTYING ||
1394 element == EL_AMOEBA_DROPPING)
1395 cut_mode = CUT_ABOVE;
1396 else if (element == EL_QUICKSAND_FILLING ||
1397 element == EL_MAGIC_WALL_FILLING ||
1398 element == EL_BD_MAGIC_WALL_FILLING)
1399 cut_mode = CUT_BELOW;
1401 if (cut_mode == CUT_ABOVE)
1402 DrawScreenElementShifted(x, y, 0, 0, element, NO_CUTTING);
1404 DrawScreenElement(x, y, EL_EMPTY);
1407 DrawScreenElementShifted(x, y, MovPos[lx][ly], 0, element, NO_CUTTING);
1408 else if (cut_mode == NO_CUTTING)
1409 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], element, cut_mode);
1411 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], content, cut_mode);
1413 if (content == EL_ACID)
1414 DrawLevelElementThruMask(lx, ly + 1, EL_ACID);
1416 else if (IS_BLOCKED(lx, ly))
1421 boolean cut_mode = NO_CUTTING;
1422 int element_old, content_old;
1424 Blocked2Moving(lx, ly, &oldx, &oldy);
1427 horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
1428 MovDir[oldx][oldy] == MV_RIGHT);
1430 element_old = Feld[oldx][oldy];
1431 content_old = Store[oldx][oldy];
1433 if (element_old == EL_QUICKSAND_EMPTYING ||
1434 element_old == EL_MAGIC_WALL_EMPTYING ||
1435 element_old == EL_BD_MAGIC_WALL_EMPTYING ||
1436 element_old == EL_AMOEBA_DROPPING)
1437 cut_mode = CUT_ABOVE;
1439 DrawScreenElement(x, y, EL_EMPTY);
1442 DrawScreenElementShifted(sx, sy, MovPos[oldx][oldy], 0, element_old,
1444 else if (cut_mode == NO_CUTTING)
1445 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], element_old,
1448 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], content_old,
1451 else if (IS_DRAWABLE(element))
1452 DrawScreenElement(x, y, element);
1454 DrawScreenElement(x, y, EL_EMPTY);
1457 void DrawLevelField(int x, int y)
1459 if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1460 DrawScreenField(SCREENX(x), SCREENY(y));
1461 else if (IS_MOVING(x, y))
1465 Moving2Blocked(x, y, &newx, &newy);
1466 if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
1467 DrawScreenField(SCREENX(newx), SCREENY(newy));
1469 else if (IS_BLOCKED(x, y))
1473 Blocked2Moving(x, y, &oldx, &oldy);
1474 if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
1475 DrawScreenField(SCREENX(oldx), SCREENY(oldy));
1479 void DrawMiniElement(int x, int y, int element)
1483 graphic = el2edimg(element);
1484 DrawMiniGraphic(x, y, graphic);
1487 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
1489 int x = sx + scroll_x, y = sy + scroll_y;
1491 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
1492 DrawMiniElement(sx, sy, EL_EMPTY);
1493 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
1494 DrawMiniElement(sx, sy, Feld[x][y]);
1496 DrawMiniGraphic(sx, sy, el2edimg(getBorderElement(x, y)));
1499 void getMicroGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
1501 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
1502 int mini_startx = src_bitmap->width * 3 / 4;
1503 int mini_starty = src_bitmap->height * 2 / 3;
1504 int src_x = mini_startx + graphic_info[graphic].src_x / 8;
1505 int src_y = mini_starty + graphic_info[graphic].src_y / 8;
1507 if (src_x + MICRO_TILEX > src_bitmap->width ||
1508 src_y + MICRO_TILEY > src_bitmap->height)
1510 /* graphic of desired size seems not to be contained in this image;
1511 dirty workaround: get it from the middle of the normal sized image */
1513 getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
1514 src_x += (TILEX / 2 - MICRO_TILEX / 2);
1515 src_y += (TILEY / 2 - MICRO_TILEY / 2);
1518 *bitmap = src_bitmap;
1523 void DrawMicroElement(int xpos, int ypos, int element)
1527 int graphic = el2preimg(element);
1529 getMicroGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
1530 BlitBitmap(src_bitmap, drawto, src_x, src_y, MICRO_TILEX, MICRO_TILEY,
1538 SetDrawBackgroundMask(REDRAW_NONE);
1541 for(x=BX1; x<=BX2; x++)
1542 for(y=BY1; y<=BY2; y++)
1543 DrawScreenField(x, y);
1545 redraw_mask |= REDRAW_FIELD;
1548 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
1552 for(x=0; x<size_x; x++)
1553 for(y=0; y<size_y; y++)
1554 DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
1556 redraw_mask |= REDRAW_FIELD;
1559 static void DrawMicroLevelExt(int xpos, int ypos, int from_x, int from_y)
1563 DrawBackground(xpos, ypos, MICROLEV_XSIZE, MICROLEV_YSIZE);
1565 if (lev_fieldx < STD_LEV_FIELDX)
1566 xpos += (STD_LEV_FIELDX - lev_fieldx) / 2 * MICRO_TILEX;
1567 if (lev_fieldy < STD_LEV_FIELDY)
1568 ypos += (STD_LEV_FIELDY - lev_fieldy) / 2 * MICRO_TILEY;
1570 xpos += MICRO_TILEX;
1571 ypos += MICRO_TILEY;
1573 for(x=-1; x<=STD_LEV_FIELDX; x++)
1575 for(y=-1; y<=STD_LEV_FIELDY; y++)
1577 int lx = from_x + x, ly = from_y + y;
1579 if (lx >= 0 && lx < lev_fieldx && ly >= 0 && ly < lev_fieldy)
1580 DrawMicroElement(xpos + x * MICRO_TILEX, ypos + y * MICRO_TILEY,
1582 else if (lx >= -1 && lx < lev_fieldx+1 && ly >= -1 && ly < lev_fieldy+1
1583 && BorderElement != EL_EMPTY)
1584 DrawMicroElement(xpos + x * MICRO_TILEX, ypos + y * MICRO_TILEY,
1585 getBorderElement(lx, ly));
1589 redraw_mask |= REDRAW_MICROLEVEL;
1592 #define MICROLABEL_EMPTY 0
1593 #define MICROLABEL_LEVEL_NAME 1
1594 #define MICROLABEL_CREATED_BY 2
1595 #define MICROLABEL_LEVEL_AUTHOR 3
1596 #define MICROLABEL_IMPORTED_FROM 4
1597 #define MICROLABEL_LEVEL_IMPORT_INFO 5
1599 static void DrawMicroLevelLabelExt(int mode)
1601 char label_text[MAX_OUTPUT_LINESIZE + 1];
1602 int max_len_label_text;
1603 int font_nr = FONT_TEXT_2;
1605 if (mode == MICROLABEL_CREATED_BY || mode == MICROLABEL_IMPORTED_FROM)
1606 font_nr = FONT_TEXT_3;
1608 max_len_label_text = SXSIZE / getFontWidth(font_nr);
1610 DrawBackground(SX, MICROLABEL_YPOS, SXSIZE, getFontHeight(font_nr));
1612 strncpy(label_text, (mode == MICROLABEL_LEVEL_NAME ? level.name :
1613 mode == MICROLABEL_CREATED_BY ? "created by" :
1614 mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
1615 mode == MICROLABEL_IMPORTED_FROM ? "imported from" :
1616 mode == MICROLABEL_LEVEL_IMPORT_INFO ?
1617 leveldir_current->imported_from : ""),
1618 max_len_label_text);
1619 label_text[max_len_label_text] = '\0';
1621 if (strlen(label_text) > 0)
1623 int text_width = strlen(label_text) * getFontWidth(font_nr);
1624 int lxpos = SX + (SXSIZE - text_width) / 2;
1625 int lypos = MICROLABEL_YPOS;
1627 DrawText(lxpos, lypos, label_text, font_nr);
1630 redraw_mask |= REDRAW_MICROLEVEL;
1633 void DrawMicroLevel(int xpos, int ypos, boolean restart)
1635 static unsigned long scroll_delay = 0;
1636 static unsigned long label_delay = 0;
1637 static int from_x, from_y, scroll_direction;
1638 static int label_state, label_counter;
1639 int last_game_status = game_status; /* save current game status */
1641 game_status = PSEUDO_PREVIEW; /* force PREVIEW font on preview level */
1645 from_x = from_y = 0;
1646 scroll_direction = MV_RIGHT;
1650 DrawMicroLevelExt(xpos, ypos, from_x, from_y);
1651 DrawMicroLevelLabelExt(label_state);
1653 /* initialize delay counters */
1654 DelayReached(&scroll_delay, 0);
1655 DelayReached(&label_delay, 0);
1657 if (leveldir_current->name)
1659 int len = strlen(leveldir_current->name);
1660 int lxpos = SX + (SXSIZE - len * getFontWidth(FONT_TEXT_1)) / 2;
1661 int lypos = SY + 352;
1663 DrawText(lxpos, lypos, leveldir_current->name, FONT_TEXT_1);
1666 game_status = last_game_status; /* restore current game status */
1671 /* scroll micro level, if needed */
1672 if ((lev_fieldx > STD_LEV_FIELDX || lev_fieldy > STD_LEV_FIELDY) &&
1673 DelayReached(&scroll_delay, MICROLEVEL_SCROLL_DELAY))
1675 switch (scroll_direction)
1681 scroll_direction = MV_UP;
1685 if (from_x < lev_fieldx - STD_LEV_FIELDX)
1688 scroll_direction = MV_DOWN;
1695 scroll_direction = MV_RIGHT;
1699 if (from_y < lev_fieldy - STD_LEV_FIELDY)
1702 scroll_direction = MV_LEFT;
1709 DrawMicroLevelExt(xpos, ypos, from_x, from_y);
1712 /* redraw micro level label, if needed */
1713 if (strcmp(level.name, NAMELESS_LEVEL_NAME) != 0 &&
1714 strcmp(level.author, ANONYMOUS_NAME) != 0 &&
1715 strcmp(level.author, leveldir_current->name) != 0 &&
1716 DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
1718 int max_label_counter = 23;
1720 if (leveldir_current->imported_from != NULL)
1721 max_label_counter += 14;
1723 label_counter = (label_counter + 1) % max_label_counter;
1724 label_state = (label_counter >= 0 && label_counter <= 7 ?
1725 MICROLABEL_LEVEL_NAME :
1726 label_counter >= 9 && label_counter <= 12 ?
1727 MICROLABEL_CREATED_BY :
1728 label_counter >= 14 && label_counter <= 21 ?
1729 MICROLABEL_LEVEL_AUTHOR :
1730 label_counter >= 23 && label_counter <= 26 ?
1731 MICROLABEL_IMPORTED_FROM :
1732 label_counter >= 28 && label_counter <= 35 ?
1733 MICROLABEL_LEVEL_IMPORT_INFO : MICROLABEL_EMPTY);
1734 DrawMicroLevelLabelExt(label_state);
1737 game_status = last_game_status; /* restore current game status */
1740 int REQ_in_range(int x, int y)
1742 if (y > DY+249 && y < DY+278)
1744 if (x > DX+1 && x < DX+48)
1746 else if (x > DX+51 && x < DX+98)
1752 #define MAX_REQUEST_LINES 13
1753 #define MAX_REQUEST_LINE_LEN 7
1755 boolean Request(char *text, unsigned int req_state)
1757 int mx, my, ty, result = -1;
1758 unsigned int old_door_state;
1759 int last_game_status = game_status; /* save current game status */
1761 #if defined(PLATFORM_UNIX)
1762 /* pause network game while waiting for request to answer */
1763 if (options.network &&
1764 game_status == PLAYING &&
1765 req_state & REQUEST_WAIT_FOR)
1766 SendToServer_PausePlaying();
1769 old_door_state = GetDoorState();
1773 CloseDoor(DOOR_CLOSE_1);
1775 /* save old door content */
1776 BlitBitmap(bitmap_db_door, bitmap_db_door,
1777 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
1778 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
1780 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
1782 /* clear door drawing field */
1783 DrawBackground(DX, DY, DXSIZE, DYSIZE);
1785 game_status = PSEUDO_DOOR; /* force DOOR font on preview level */
1787 /* write text for request */
1788 for(ty=0; ty < MAX_REQUEST_LINES; ty++)
1790 char text_line[MAX_REQUEST_LINE_LEN + 1];
1796 for(tl=0,tx=0; tx < MAX_REQUEST_LINE_LEN; tl++,tx++)
1799 if (!tc || tc == ' ')
1810 strncpy(text_line, text, tl);
1813 DrawText(DX + (DXSIZE - tl * getFontWidth(FONT_TEXT_2)) / 2,
1814 DY + 8 + ty * (getFontHeight(FONT_TEXT_2) + 2),
1815 text_line, FONT_TEXT_2);
1817 text += tl + (tc == ' ' ? 1 : 0);
1820 game_status = last_game_status; /* restore current game status */
1822 if (req_state & REQ_ASK)
1824 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
1825 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
1827 else if (req_state & REQ_CONFIRM)
1829 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
1831 else if (req_state & REQ_PLAYER)
1833 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
1834 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
1835 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
1836 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
1839 /* copy request gadgets to door backbuffer */
1840 BlitBitmap(drawto, bitmap_db_door,
1841 DX, DY, DXSIZE, DYSIZE,
1842 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
1844 OpenDoor(DOOR_OPEN_1);
1850 if (!(req_state & REQUEST_WAIT_FOR))
1852 SetDrawBackgroundMask(REDRAW_FIELD);
1857 if (game_status != MAINMENU)
1860 button_status = MB_RELEASED;
1862 request_gadget_id = -1;
1864 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
1876 case EVENT_BUTTONPRESS:
1877 case EVENT_BUTTONRELEASE:
1878 case EVENT_MOTIONNOTIFY:
1880 if (event.type == EVENT_MOTIONNOTIFY)
1882 if (!PointerInWindow(window))
1883 continue; /* window and pointer are on different screens */
1888 motion_status = TRUE;
1889 mx = ((MotionEvent *) &event)->x;
1890 my = ((MotionEvent *) &event)->y;
1894 motion_status = FALSE;
1895 mx = ((ButtonEvent *) &event)->x;
1896 my = ((ButtonEvent *) &event)->y;
1897 if (event.type == EVENT_BUTTONPRESS)
1898 button_status = ((ButtonEvent *) &event)->button;
1900 button_status = MB_RELEASED;
1903 /* this sets 'request_gadget_id' */
1904 HandleGadgets(mx, my, button_status);
1906 switch(request_gadget_id)
1908 case TOOL_CTRL_ID_YES:
1911 case TOOL_CTRL_ID_NO:
1914 case TOOL_CTRL_ID_CONFIRM:
1915 result = TRUE | FALSE;
1918 case TOOL_CTRL_ID_PLAYER_1:
1921 case TOOL_CTRL_ID_PLAYER_2:
1924 case TOOL_CTRL_ID_PLAYER_3:
1927 case TOOL_CTRL_ID_PLAYER_4:
1938 case EVENT_KEYPRESS:
1939 switch(GetEventKey((KeyEvent *)&event, TRUE))
1952 if (req_state & REQ_PLAYER)
1956 case EVENT_KEYRELEASE:
1957 ClearPlayerAction();
1961 HandleOtherEvents(&event);
1965 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
1967 int joy = AnyJoystick();
1969 if (joy & JOY_BUTTON_1)
1971 else if (joy & JOY_BUTTON_2)
1977 /* don't eat all CPU time */
1981 if (game_status != MAINMENU)
1986 if (!(req_state & REQ_STAY_OPEN))
1988 CloseDoor(DOOR_CLOSE_1);
1990 if (!(req_state & REQ_STAY_CLOSED) && (old_door_state & DOOR_OPEN_1))
1992 BlitBitmap(bitmap_db_door, bitmap_db_door,
1993 DOOR_GFX_PAGEX2,DOOR_GFX_PAGEY1, DXSIZE,DYSIZE,
1994 DOOR_GFX_PAGEX1,DOOR_GFX_PAGEY1);
1995 OpenDoor(DOOR_OPEN_1);
2001 SetDrawBackgroundMask(REDRAW_FIELD);
2003 #if defined(PLATFORM_UNIX)
2004 /* continue network game after request */
2005 if (options.network &&
2006 game_status == PLAYING &&
2007 req_state & REQUEST_WAIT_FOR)
2008 SendToServer_ContinuePlaying();
2014 unsigned int OpenDoor(unsigned int door_state)
2016 unsigned int new_door_state;
2018 if (door_state & DOOR_COPY_BACK)
2020 BlitBitmap(bitmap_db_door, bitmap_db_door,
2021 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE + VYSIZE,
2022 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2023 door_state &= ~DOOR_COPY_BACK;
2026 new_door_state = MoveDoor(door_state);
2028 return(new_door_state);
2031 unsigned int CloseDoor(unsigned int door_state)
2033 unsigned int new_door_state;
2035 BlitBitmap(backbuffer, bitmap_db_door,
2036 DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2037 BlitBitmap(backbuffer, bitmap_db_door,
2038 VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
2040 new_door_state = MoveDoor(door_state);
2042 return(new_door_state);
2045 unsigned int GetDoorState()
2047 return MoveDoor(DOOR_GET_STATE);
2050 unsigned int SetDoorState(unsigned int door_state)
2052 return MoveDoor(door_state | DOOR_SET_STATE);
2055 unsigned int MoveDoor(unsigned int door_state)
2057 static int door1 = DOOR_OPEN_1;
2058 static int door2 = DOOR_CLOSE_2;
2059 static unsigned long door_delay = 0;
2060 int x, start, stepsize = global.door_step_offset;
2061 unsigned long door_delay_value = global.door_step_delay;
2063 if (door_state == DOOR_GET_STATE)
2064 return(door1 | door2);
2066 if (door_state & DOOR_SET_STATE)
2068 if (door_state & DOOR_ACTION_1)
2069 door1 = door_state & DOOR_ACTION_1;
2070 if (door_state & DOOR_ACTION_2)
2071 door2 = door_state & DOOR_ACTION_2;
2073 return(door1 | door2);
2076 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
2077 door_state &= ~DOOR_OPEN_1;
2078 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
2079 door_state &= ~DOOR_CLOSE_1;
2080 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
2081 door_state &= ~DOOR_OPEN_2;
2082 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
2083 door_state &= ~DOOR_CLOSE_2;
2085 if (setup.quick_doors)
2088 door_delay_value = 0;
2090 StopSound(SND_DOOR_OPENING);
2091 StopSound(SND_DOOR_CLOSING);
2094 if (global.autoplay_leveldir)
2096 door_state |= DOOR_NO_DELAY;
2097 door_state &= ~DOOR_CLOSE_ALL;
2100 if (door_state & DOOR_ACTION)
2102 if (!(door_state & DOOR_NO_DELAY))
2104 /* opening door sound has priority over simultaneously closing door */
2105 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
2106 PlaySoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
2107 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
2108 PlaySoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
2111 start = ((door_state & DOOR_NO_DELAY) ? DXSIZE : 0);
2113 for(x=start; x<=DXSIZE; x+=stepsize)
2115 Bitmap *bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
2116 GC gc = bitmap->stored_clip_gc;
2118 if (!(door_state & DOOR_NO_DELAY))
2119 WaitUntilDelayReached(&door_delay, door_delay_value);
2121 if (door_state & DOOR_ACTION_1)
2123 int i = (door_state & DOOR_OPEN_1 ? DXSIZE-x : x);
2124 int j = (DXSIZE - i) / 3;
2126 BlitBitmap(bitmap_db_door, drawto,
2127 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + i/2,
2128 DXSIZE,DYSIZE - i/2, DX, DY);
2130 ClearRectangle(drawto, DX, DY + DYSIZE - i/2, DXSIZE,i/2);
2132 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2133 BlitBitmapMasked(bitmap, drawto,
2134 DXSIZE, DOOR_GFX_PAGEY1, i, 77,
2135 DX + DXSIZE - i, DY + j);
2136 BlitBitmapMasked(bitmap, drawto,
2137 DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63,
2138 DX + DXSIZE - i, DY + 140 + j);
2139 SetClipOrigin(bitmap, gc, DX - DXSIZE + i, DY - (DOOR_GFX_PAGEY1 + j));
2140 BlitBitmapMasked(bitmap, drawto,
2141 DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j,
2143 BlitBitmapMasked(bitmap, drawto,
2144 DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63,
2147 BlitBitmapMasked(bitmap, drawto,
2148 DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
2150 BlitBitmapMasked(bitmap, drawto,
2151 DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
2153 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2154 BlitBitmapMasked(bitmap, drawto,
2155 DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
2156 DX + DXSIZE - i, DY + 77 + j);
2157 BlitBitmapMasked(bitmap, drawto,
2158 DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
2159 DX + DXSIZE - i, DY + 203 + j);
2161 redraw_mask |= REDRAW_DOOR_1;
2164 if (door_state & DOOR_ACTION_2)
2166 int i = (door_state & DOOR_OPEN_2 ? VXSIZE - x : x);
2167 int j = (VXSIZE - i) / 3;
2169 BlitBitmap(bitmap_db_door, drawto,
2170 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + i/2,
2171 VXSIZE, VYSIZE - i/2, VX, VY);
2173 ClearRectangle(drawto, VX, VY + VYSIZE-i/2, VXSIZE, i/2);
2175 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2176 BlitBitmapMasked(bitmap, drawto,
2177 VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2,
2178 VX + VXSIZE-i, VY+j);
2179 SetClipOrigin(bitmap, gc,
2180 VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
2181 BlitBitmapMasked(bitmap, drawto,
2182 VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j,
2185 BlitBitmapMasked(bitmap, drawto,
2186 VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2,
2187 i, VYSIZE / 2, VX, VY + VYSIZE / 2 - j);
2188 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2189 BlitBitmapMasked(bitmap, drawto,
2190 VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2,
2192 VX + VXSIZE - i, VY + VYSIZE / 2 + j);
2194 redraw_mask |= REDRAW_DOOR_2;
2199 if (game_status == MAINMENU)
2204 if (setup.quick_doors)
2206 StopSound(SND_DOOR_OPENING);
2207 StopSound(SND_DOOR_CLOSING);
2210 if (door_state & DOOR_ACTION_1)
2211 door1 = door_state & DOOR_ACTION_1;
2212 if (door_state & DOOR_ACTION_2)
2213 door2 = door_state & DOOR_ACTION_2;
2215 return (door1 | door2);
2218 void DrawSpecialEditorDoor()
2220 /* draw bigger toolbox window */
2221 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
2222 DOOR_GFX_PAGEX7, 0, EXSIZE + 8, 8,
2224 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
2225 EX - 4, VY - 4, EXSIZE + 8, EYSIZE - VYSIZE + 4,
2228 redraw_mask |= REDRAW_ALL;
2231 void UndrawSpecialEditorDoor()
2233 /* draw normal tape recorder window */
2234 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
2235 EX - 4, EY - 12, EXSIZE + 8, EYSIZE - VYSIZE + 12,
2238 redraw_mask |= REDRAW_ALL;
2242 int ReadPixel(DrawBuffer *bitmap, int x, int y)
2244 XImage *pixel_image;
2245 unsigned long pixel_value;
2247 pixel_image = XGetImage(display, bitmap->drawable,
2248 x, y, 1, 1, AllPlanes, ZPixmap);
2249 pixel_value = XGetPixel(pixel_image, 0, 0);
2251 XDestroyImage(pixel_image);
2257 /* ---------- new tool button stuff ---------------------------------------- */
2259 /* graphic position values for tool buttons */
2260 #define TOOL_BUTTON_YES_XPOS 2
2261 #define TOOL_BUTTON_YES_YPOS 250
2262 #define TOOL_BUTTON_YES_GFX_YPOS 0
2263 #define TOOL_BUTTON_YES_XSIZE 46
2264 #define TOOL_BUTTON_YES_YSIZE 28
2265 #define TOOL_BUTTON_NO_XPOS 52
2266 #define TOOL_BUTTON_NO_YPOS TOOL_BUTTON_YES_YPOS
2267 #define TOOL_BUTTON_NO_GFX_YPOS TOOL_BUTTON_YES_GFX_YPOS
2268 #define TOOL_BUTTON_NO_XSIZE TOOL_BUTTON_YES_XSIZE
2269 #define TOOL_BUTTON_NO_YSIZE TOOL_BUTTON_YES_YSIZE
2270 #define TOOL_BUTTON_CONFIRM_XPOS TOOL_BUTTON_YES_XPOS
2271 #define TOOL_BUTTON_CONFIRM_YPOS TOOL_BUTTON_YES_YPOS
2272 #define TOOL_BUTTON_CONFIRM_GFX_YPOS 30
2273 #define TOOL_BUTTON_CONFIRM_XSIZE 96
2274 #define TOOL_BUTTON_CONFIRM_YSIZE TOOL_BUTTON_YES_YSIZE
2275 #define TOOL_BUTTON_PLAYER_XSIZE 30
2276 #define TOOL_BUTTON_PLAYER_YSIZE 30
2277 #define TOOL_BUTTON_PLAYER_GFX_XPOS 5
2278 #define TOOL_BUTTON_PLAYER_GFX_YPOS 185
2279 #define TOOL_BUTTON_PLAYER_XPOS (5 + TOOL_BUTTON_PLAYER_XSIZE / 2)
2280 #define TOOL_BUTTON_PLAYER_YPOS (215 - TOOL_BUTTON_PLAYER_YSIZE / 2)
2281 #define TOOL_BUTTON_PLAYER1_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2282 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2283 #define TOOL_BUTTON_PLAYER2_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2284 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2285 #define TOOL_BUTTON_PLAYER3_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2286 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2287 #define TOOL_BUTTON_PLAYER4_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2288 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2289 #define TOOL_BUTTON_PLAYER1_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2290 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2291 #define TOOL_BUTTON_PLAYER2_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2292 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2293 #define TOOL_BUTTON_PLAYER3_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2294 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2295 #define TOOL_BUTTON_PLAYER4_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2296 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2305 } toolbutton_info[NUM_TOOL_BUTTONS] =
2308 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_GFX_YPOS,
2309 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_YPOS,
2310 TOOL_BUTTON_YES_XSIZE, TOOL_BUTTON_YES_YSIZE,
2315 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_GFX_YPOS,
2316 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_YPOS,
2317 TOOL_BUTTON_NO_XSIZE, TOOL_BUTTON_NO_YSIZE,
2322 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_GFX_YPOS,
2323 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_YPOS,
2324 TOOL_BUTTON_CONFIRM_XSIZE, TOOL_BUTTON_CONFIRM_YSIZE,
2325 TOOL_CTRL_ID_CONFIRM,
2329 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2330 TOOL_BUTTON_PLAYER1_XPOS, TOOL_BUTTON_PLAYER1_YPOS,
2331 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2332 TOOL_CTRL_ID_PLAYER_1,
2336 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2337 TOOL_BUTTON_PLAYER2_XPOS, TOOL_BUTTON_PLAYER2_YPOS,
2338 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2339 TOOL_CTRL_ID_PLAYER_2,
2343 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2344 TOOL_BUTTON_PLAYER3_XPOS, TOOL_BUTTON_PLAYER3_YPOS,
2345 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2346 TOOL_CTRL_ID_PLAYER_3,
2350 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2351 TOOL_BUTTON_PLAYER4_XPOS, TOOL_BUTTON_PLAYER4_YPOS,
2352 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2353 TOOL_CTRL_ID_PLAYER_4,
2358 void CreateToolButtons()
2362 for (i=0; i<NUM_TOOL_BUTTONS; i++)
2364 Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
2365 Bitmap *deco_bitmap = None;
2366 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
2367 struct GadgetInfo *gi;
2368 unsigned long event_mask;
2369 int gd_xoffset, gd_yoffset;
2370 int gd_x1, gd_x2, gd_y;
2373 event_mask = GD_EVENT_RELEASED;
2375 gd_xoffset = toolbutton_info[i].xpos;
2376 gd_yoffset = toolbutton_info[i].ypos;
2377 gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
2378 gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
2379 gd_y = DOOR_GFX_PAGEY1 + gd_yoffset;
2381 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
2383 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
2385 getMiniGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr),
2386 &deco_bitmap, &deco_x, &deco_y);
2387 deco_xpos = (toolbutton_info[i].width - MINI_TILEX) / 2;
2388 deco_ypos = (toolbutton_info[i].height - MINI_TILEY) / 2;
2391 gi = CreateGadget(GDI_CUSTOM_ID, id,
2392 GDI_INFO_TEXT, toolbutton_info[i].infotext,
2393 GDI_X, DX + toolbutton_info[i].x,
2394 GDI_Y, DY + toolbutton_info[i].y,
2395 GDI_WIDTH, toolbutton_info[i].width,
2396 GDI_HEIGHT, toolbutton_info[i].height,
2397 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
2398 GDI_STATE, GD_BUTTON_UNPRESSED,
2399 GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
2400 GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
2401 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
2402 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
2403 GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
2404 GDI_DECORATION_SHIFTING, 1, 1,
2405 GDI_EVENT_MASK, event_mask,
2406 GDI_CALLBACK_ACTION, HandleToolButtons,
2410 Error(ERR_EXIT, "cannot create gadget");
2412 tool_gadget[id] = gi;
2416 void FreeToolButtons()
2420 for (i=0; i<NUM_TOOL_BUTTONS; i++)
2421 FreeGadget(tool_gadget[i]);
2424 static void UnmapToolButtons()
2428 for (i=0; i<NUM_TOOL_BUTTONS; i++)
2429 UnmapGadget(tool_gadget[i]);
2432 static void HandleToolButtons(struct GadgetInfo *gi)
2434 request_gadget_id = gi->custom_id;
2437 int get_next_element(int element)
2441 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
2442 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
2443 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
2444 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
2445 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
2446 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
2447 case EL_AMOEBA_DROPPING: return EL_AMOEBA_WET;
2449 default: return element;
2453 int el_act_dir2img(int element, int action, int direction)
2455 direction = MV_DIR_BIT(direction);
2457 return element_info[element].direction_graphic[action][direction];
2460 int el_act2img(int element, int action)
2462 return element_info[element].graphic[action];
2465 int el_dir2img(int element, int direction)
2467 return el_act_dir2img(element, ACTION_DEFAULT, direction);
2470 int el2img(int element)
2472 return element_info[element].graphic[ACTION_DEFAULT];
2475 int el2edimg(int element)
2477 return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
2480 int el2preimg(int element)
2482 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];