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_moving ? ACTION_MOVING :
566 player->snapped ? ACTION_SNAPPING : ACTION_DEFAULT);
568 InitPlayerGfxAnimation(player, current_action, player->MovDir);
570 /* ----------------------------------------------------------------------- */
571 /* draw things in the field the player is leaving, if needed */
572 /* ----------------------------------------------------------------------- */
574 if (player_is_moving)
576 if (Store[last_jx][last_jy] && IS_DRAWABLE(last_element))
578 DrawLevelElement(last_jx, last_jy, Store[last_jx][last_jy]);
580 if (last_element == EL_DYNAMITE_ACTIVE ||
581 last_element == EL_SP_DISK_RED_ACTIVE)
582 DrawDynamite(last_jx, last_jy);
584 DrawLevelFieldThruMask(last_jx, last_jy);
586 else if (last_element == EL_DYNAMITE_ACTIVE ||
587 last_element == EL_SP_DISK_RED_ACTIVE)
588 DrawDynamite(last_jx, last_jy);
590 DrawLevelField(last_jx, last_jy);
592 if (player->Pushing && IN_SCR_FIELD(SCREENX(next_jx), SCREENY(next_jy)))
596 if (Feld[next_jx][next_jy] == EL_SOKOBAN_FIELD_FULL)
597 DrawLevelElement(next_jx, next_jy, EL_SOKOBAN_FIELD_EMPTY);
599 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
602 DrawLevelField(next_jx, next_jy);
606 if (!IN_SCR_FIELD(sx, sy))
609 if (setup.direct_draw)
610 SetDrawtoField(DRAW_BUFFERED);
612 /* ----------------------------------------------------------------------- */
613 /* draw things behind the player, if needed */
614 /* ----------------------------------------------------------------------- */
617 DrawLevelElement(jx, jy, Store[jx][jy]);
618 else if (IS_ACTIVE_BOMB(element))
619 DrawLevelElement(jx, jy, EL_EMPTY);
622 if (player_is_moving && GfxElement[jx][jy] != EL_UNDEFINED)
624 int old_element = GfxElement[jx][jy];
626 el_act_dir2img(old_element, ACTION_DIGGING, player->MovDir);
627 int frame = getGraphicAnimationFrame(old_graphic, player->StepFrame);
632 int width = TILEX, height = TILEY;
635 if (player->MovDir == MV_UP)
640 else if (player->MovDir == MV_DOWN)
643 height = TILEY - player->GfxPos;
645 else if (player->MovDir == MV_LEFT)
650 else if (player->MovDir == MV_RIGHT)
653 width = TILEX - player->GfxPos;
656 getGraphicSource(old_graphic, frame, &src_bitmap, &src_x, &src_y);
658 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
659 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
662 printf("::: %d, %d, %d, %d => %d, %d [%d, %d, %d]\n",
663 old_element, ACTION_DIGGING, player->MovDir, player->Frame,
665 player->MovPos, player->GfxPos, player->StepFrame);
668 DrawGraphic(sx, sy, old_graphic, frame);
673 GfxElement[jx][jy] = EL_UNDEFINED;
675 DrawLevelField(jx, jy);
679 /* ----------------------------------------------------------------------- */
680 /* draw player himself */
681 /* ----------------------------------------------------------------------- */
683 if (player->use_murphy_graphic)
685 static int last_horizontal_dir = MV_LEFT;
688 if (player->MovDir == MV_LEFT || player->MovDir == MV_RIGHT)
689 last_horizontal_dir = player->MovDir;
691 direction = (player->snapped ? player->MovDir : last_horizontal_dir);
693 graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, direction);
696 graphic = el_act_dir2img(player->element_nr, player->GfxAction,
699 frame = getGraphicAnimationFrame(graphic, player->Frame);
703 if (player->MovDir == MV_LEFT || player->MovDir == MV_RIGHT)
704 sxx = player->GfxPos;
706 syy = player->GfxPos;
709 if (!setup.soft_scrolling && ScreenMovPos)
712 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
714 if (SHIELD_ON(player))
716 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
717 IMG_SHIELD_NORMAL_ACTIVE);
718 int frame = getGraphicAnimationFrame(graphic, -1);
720 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
723 /* ----------------------------------------------------------------------- */
724 /* draw things the player is pushing, if needed */
725 /* ----------------------------------------------------------------------- */
727 if (player->Pushing && player_is_moving)
729 int px = SCREENX(next_jx), py = SCREENY(next_jy);
732 (element == EL_SOKOBAN_FIELD_EMPTY ||
733 Feld[next_jx][next_jy] == EL_SOKOBAN_FIELD_FULL))
734 DrawGraphicShiftedThruMask(px, py, sxx, syy, IMG_SOKOBAN_OBJECT, 0,
738 int element = Feld[next_jx][next_jy];
739 int graphic = el2img(element);
742 if ((sxx || syy) && IS_PUSHABLE(element))
744 graphic = el_act_dir2img(element, ACTION_MOVING, player->MovDir);
745 frame = getGraphicAnimationFrame(graphic, player->Frame);
748 DrawGraphicShifted(px, py, sxx, syy, graphic, frame,
749 NO_CUTTING, NO_MASKING);
753 /* ----------------------------------------------------------------------- */
754 /* draw things in front of player (active dynamite or dynabombs) */
755 /* ----------------------------------------------------------------------- */
757 if (IS_ACTIVE_BOMB(element))
759 graphic = el2img(element);
760 frame = getGraphicAnimationFrame(graphic, GfxFrame[jx][jy]);
762 if (game.emulation == EMU_SUPAPLEX)
763 DrawGraphic(sx, sy, IMG_SP_DISK_RED, frame);
765 DrawGraphicThruMask(sx, sy, graphic, frame);
768 if (player_is_moving && last_element == EL_EXPLOSION)
770 int stored = Store[last_jx][last_jy];
771 int graphic = (game.emulation != EMU_SUPAPLEX ? IMG_EXPLOSION :
772 stored == EL_SP_INFOTRON ? IMG_SP_EXPLOSION_INFOTRON :
774 int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
775 int phase = ExplodePhase[last_jx][last_jy] - 1;
776 int frame = getGraphicAnimationFrame(graphic, phase - delay);
779 DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy), graphic, frame);
782 /* ----------------------------------------------------------------------- */
783 /* draw elements that stay over the player */
784 /* ----------------------------------------------------------------------- */
786 /* handle the field the player is leaving ... */
787 if (player_is_moving && IS_OVER_PLAYER(last_element))
788 DrawLevelField(last_jx, last_jy);
790 /* ... and the field the player is entering */
791 if (IS_OVER_PLAYER(element))
792 DrawLevelField(jx, jy);
794 if (setup.direct_draw)
796 int dest_x = SX + SCREENX(MIN(jx, last_jx)) * TILEX;
797 int dest_y = SY + SCREENY(MIN(jy, last_jy)) * TILEY;
798 int x_size = TILEX * (1 + ABS(jx - last_jx));
799 int y_size = TILEY * (1 + ABS(jy - last_jy));
801 BlitBitmap(drawto_field, window,
802 dest_x, dest_y, x_size, y_size, dest_x, dest_y);
803 SetDrawtoField(DRAW_DIRECT);
806 MarkTileDirty(sx,sy);
809 void getGraphicSource(int graphic, int frame, Bitmap **bitmap, int *x, int *y)
811 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
812 int offset_x = graphic_info[graphic].offset_x;
813 int offset_y = graphic_info[graphic].offset_y;
814 int src_x = graphic_info[graphic].src_x + frame * offset_x;
815 int src_y = graphic_info[graphic].src_y + frame * offset_y;
817 *bitmap = src_bitmap;
822 void DrawGraphic(int x, int y, int graphic, int frame)
825 if (!IN_SCR_FIELD(x, y))
827 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
828 printf("DrawGraphic(): This should never happen!\n");
833 DrawGraphicExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic, frame);
838 void DrawOldGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic)
843 getOldGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
844 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
848 void DrawGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
855 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
857 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
858 int src_x = graphic_info[graphic].src_x;
859 int src_y = graphic_info[graphic].src_y;
860 int offset_x = graphic_info[graphic].offset_x;
861 int offset_y = graphic_info[graphic].offset_y;
863 src_x += frame * offset_x;
864 src_y += frame * offset_y;
867 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
870 void DrawGraphicThruMask(int x, int y, int graphic, int frame)
873 if (!IN_SCR_FIELD(x, y))
875 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
876 printf("DrawGraphicThruMask(): This should never happen!\n");
881 DrawGraphicThruMaskExt(drawto_field, FX + x * TILEX, FY + y *TILEY, graphic,
886 void DrawGraphicThruMaskExt(DrawBuffer *d, int dest_x, int dest_y, int graphic,
894 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
895 drawing_gc = src_bitmap->stored_clip_gc;
897 GC drawing_gc = src_bitmap->stored_clip_gc;
898 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
899 int src_x = graphic_info[graphic].src_x;
900 int src_y = graphic_info[graphic].src_y;
901 int offset_x = graphic_info[graphic].offset_x;
902 int offset_y = graphic_info[graphic].offset_y;
904 src_x += frame * offset_x;
905 src_y += frame * offset_y;
909 SetClipOrigin(src_bitmap, drawing_gc, dest_x - src_x, dest_y - src_y);
910 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX, TILEY, dest_x, dest_y);
913 void DrawMiniGraphic(int x, int y, int graphic)
915 DrawMiniGraphicExt(drawto, SX + x * MINI_TILEX,SY + y * MINI_TILEY, graphic);
916 MarkTileDirty(x / 2, y / 2);
919 void getMiniGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
921 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
923 int mini_starty = src_bitmap->height * 2 / 3;
924 int src_x = mini_startx + graphic_info[graphic].src_x / 2;
925 int src_y = mini_starty + graphic_info[graphic].src_y / 2;
928 /* !!! not needed anymore, because of automatically created mini graphics */
929 if (src_x + MINI_TILEX > src_bitmap->width ||
930 src_y + MINI_TILEY > src_bitmap->height)
932 /* graphic of desired size seems not to be contained in this image;
933 dirty workaround: get it from the middle of the normal sized image */
935 printf("::: using dirty workaround for %d (%d, %d)\n",
936 graphic, src_bitmap->width, src_bitmap->height);
938 getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
939 src_x += (TILEX / 2 - MINI_TILEX / 2);
940 src_y += (TILEY / 2 - MINI_TILEY / 2);
944 *bitmap = src_bitmap;
949 void DrawMiniGraphicExt(DrawBuffer *d, int x, int y, int graphic)
954 getMiniGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
955 BlitBitmap(src_bitmap, d, src_x, src_y, MINI_TILEX, MINI_TILEY, x, y);
958 void DrawGraphicShifted(int x,int y, int dx,int dy, int graphic, int frame,
959 int cut_mode, int mask_mode)
968 int width = TILEX, height = TILEY;
974 DrawGraphic(x, y, graphic, frame);
978 if (dx || dy) /* shifted graphic */
980 if (x < BX1) /* object enters playfield from the left */
987 else if (x > BX2) /* object enters playfield from the right */
993 else if (x==BX1 && dx < 0) /* object leaves playfield to the left */
999 else if (x==BX2 && dx > 0) /* object leaves playfield to the right */
1001 else if (dx) /* general horizontal movement */
1002 MarkTileDirty(x + SIGN(dx), y);
1004 if (y < BY1) /* object enters playfield from the top */
1006 if (cut_mode==CUT_BELOW) /* object completely above top border */
1014 else if (y > BY2) /* object enters playfield from the bottom */
1020 else if (y==BY1 && dy < 0) /* object leaves playfield to the top */
1026 else if (dy > 0 && cut_mode == CUT_ABOVE)
1028 if (y == BY2) /* object completely above bottom border */
1034 MarkTileDirty(x, y + 1);
1035 } /* object leaves playfield to the bottom */
1036 else if (dy > 0 && (y == BY2 || cut_mode == CUT_BELOW))
1038 else if (dy) /* general vertical movement */
1039 MarkTileDirty(x, y + SIGN(dy));
1042 src_bitmap = graphic_info[graphic].bitmap;
1043 src_x = graphic_info[graphic].src_x;
1044 src_y = graphic_info[graphic].src_y;
1045 offset_x = graphic_info[graphic].offset_x;
1046 offset_y = graphic_info[graphic].offset_y;
1048 drawing_gc = src_bitmap->stored_clip_gc;
1050 src_x += frame * offset_x;
1051 src_y += frame * offset_y;
1056 dest_x = FX + x * TILEX + dx;
1057 dest_y = FY + y * TILEY + dy;
1060 if (!IN_SCR_FIELD(x,y))
1062 printf("DrawGraphicShifted(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
1063 printf("DrawGraphicShifted(): This should never happen!\n");
1068 if (mask_mode == USE_MASKING)
1070 SetClipOrigin(src_bitmap, drawing_gc, dest_x - src_x, dest_y - src_y);
1071 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1075 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1081 void DrawGraphicShiftedThruMask(int x, int y, int dx, int dy, int graphic,
1082 int frame, int cut_mode)
1084 DrawGraphicShifted(x,y, dx,dy, graphic, frame, cut_mode, USE_MASKING);
1087 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
1088 int cut_mode, int mask_mode)
1090 int lx = LEVELX(x), ly = LEVELY(y);
1094 if (IN_LEV_FIELD(lx, ly))
1096 SetRandomAnimationValue(lx, ly);
1098 graphic = el_act_dir2img(element, GfxAction[lx][ly], MovDir[lx][ly]);
1099 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1101 else /* border element */
1103 graphic = el2img(element);
1104 frame = getGraphicAnimationFrame(graphic, -1);
1107 if (element == EL_EXPANDABLE_WALL)
1109 boolean left_stopped = FALSE, right_stopped = FALSE;
1111 if (!IN_LEV_FIELD(lx - 1, ly) || IS_MAUER(Feld[lx - 1][ly]))
1112 left_stopped = TRUE;
1113 if (!IN_LEV_FIELD(lx + 1, ly) || IS_MAUER(Feld[lx + 1][ly]))
1114 right_stopped = TRUE;
1116 if (left_stopped && right_stopped)
1118 else if (left_stopped)
1120 graphic = IMG_EXPANDABLE_WALL_GROWING_RIGHT;
1121 frame = graphic_info[graphic].anim_frames - 1;
1123 else if (right_stopped)
1125 graphic = IMG_EXPANDABLE_WALL_GROWING_LEFT;
1126 frame = graphic_info[graphic].anim_frames - 1;
1130 else if (IS_AMOEBOID(element) || element == EL_AMOEBA_DROPPING)
1132 graphic = (element == EL_BD_AMOEBA ? IMG_BD_AMOEBA_PART1 :
1133 element == EL_AMOEBA_WET ? IMG_AMOEBA_WET_PART1 :
1134 element == EL_AMOEBA_DRY ? IMG_AMOEBA_DRY_PART1 :
1135 element == EL_AMOEBA_FULL ? IMG_AMOEBA_FULL_PART1 :
1136 IMG_AMOEBA_DEAD_PART1);
1138 graphic += (x + 2 * y + 4) % 4;
1143 if (IS_AMOEBOID(element) || element == EL_AMOEBA_DROPPING)
1145 if (Feld[lx][ly] == EL_AMOEBA_DROPPING)
1146 printf("---> %d -> %d / %d [%d]\n",
1147 element, graphic, frame, GfxRandom[lx][ly]);
1152 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, mask_mode);
1153 else if (mask_mode == USE_MASKING)
1154 DrawGraphicThruMask(x, y, graphic, frame);
1156 DrawGraphic(x, y, graphic, frame);
1159 void DrawLevelElementExt(int x, int y, int dx, int dy, int element,
1160 int cut_mode, int mask_mode)
1162 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1163 DrawScreenElementExt(SCREENX(x), SCREENY(y), dx, dy, element,
1164 cut_mode, mask_mode);
1167 void DrawScreenElementShifted(int x, int y, int dx, int dy, int element,
1170 DrawScreenElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1173 void DrawLevelElementShifted(int x, int y, int dx, int dy, int element,
1176 DrawLevelElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1180 void DrawOldScreenElementThruMask(int x, int y, int element)
1182 DrawOldScreenElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1185 void DrawScreenElementThruMask(int x, int y, int element)
1187 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1191 void DrawLevelElementThruMask(int x, int y, int element)
1193 DrawLevelElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1196 void DrawLevelFieldThruMask(int x, int y)
1198 DrawLevelElementExt(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
1201 void DrawCrumbledSand(int x, int y)
1205 int i, width, height, cx,cy;
1206 int lx = LEVELX(x), ly = LEVELY(y);
1207 int element, graphic;
1209 static int xy[4][2] =
1217 if (!IN_LEV_FIELD(lx, ly))
1220 element = Feld[lx][ly];
1222 if (element == EL_SAND ||
1224 (element == EL_EMPTY_SPACE && GfxElement[lx][ly] == EL_SAND) ||
1226 element == EL_LANDMINE ||
1227 element == EL_TRAP ||
1228 element == EL_TRAP_ACTIVE)
1230 if (!IN_SCR_FIELD(x, y))
1233 graphic = IMG_SAND_CRUMBLED;
1235 src_bitmap = graphic_info[graphic].bitmap;
1236 src_x = graphic_info[graphic].src_x;
1237 src_y = graphic_info[graphic].src_y;
1243 lxx = lx + xy[i][0];
1244 lyy = ly + xy[i][1];
1245 if (!IN_LEV_FIELD(lxx, lyy))
1246 element = EL_STEELWALL;
1248 element = Feld[lxx][lyy];
1250 if (element == EL_SAND ||
1252 (element == EL_EMPTY_SPACE && GfxElement[lxx][lyy] == EL_SAND) ||
1254 element == EL_LANDMINE ||
1255 element == EL_TRAP ||
1256 element == EL_TRAP_ACTIVE)
1259 if (i == 1 || i == 2)
1263 cx = (i == 2 ? TILEX - snip : 0);
1271 cy = (i == 3 ? TILEY - snip : 0);
1274 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1275 width, height, FX + x * TILEX + cx, FY + y * TILEY + cy);
1278 MarkTileDirty(x, y);
1282 graphic = IMG_SAND_CRUMBLED;
1284 src_bitmap = graphic_info[graphic].bitmap;
1285 src_x = graphic_info[graphic].src_x;
1286 src_y = graphic_info[graphic].src_y;
1290 int xx, yy, lxx, lyy;
1294 lxx = lx + xy[i][0];
1295 lyy = ly + xy[i][1];
1297 if (!IN_LEV_FIELD(lxx, lyy) ||
1298 (Feld[lxx][lyy] != EL_SAND &&
1300 !(Feld[lxx][lyy] == EL_EMPTY_SPACE && GfxElement[lxx][lyy] == EL_SAND) &&
1302 Feld[lxx][lyy] != EL_LANDMINE &&
1303 Feld[lxx][lyy] != EL_TRAP &&
1304 Feld[lxx][lyy] != EL_TRAP_ACTIVE) ||
1305 !IN_SCR_FIELD(xx, yy))
1308 if (i == 1 || i == 2)
1312 cx = (i == 1 ? TILEX - snip : 0);
1320 cy = (i==0 ? TILEY-snip : 0);
1323 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1324 width, height, FX + xx * TILEX + cx, FY + yy * TILEY + cy);
1326 MarkTileDirty(xx, yy);
1331 static int getBorderElement(int x, int y)
1335 { EL_STEELWALL_TOPLEFT, EL_INVISIBLE_STEELWALL_TOPLEFT },
1336 { EL_STEELWALL_TOPRIGHT, EL_INVISIBLE_STEELWALL_TOPRIGHT },
1337 { EL_STEELWALL_BOTTOMLEFT, EL_INVISIBLE_STEELWALL_BOTTOMLEFT },
1338 { EL_STEELWALL_BOTTOMRIGHT, EL_INVISIBLE_STEELWALL_BOTTOMRIGHT },
1339 { EL_STEELWALL_VERTICAL, EL_INVISIBLE_STEELWALL_VERTICAL },
1340 { EL_STEELWALL_HORIZONTAL, EL_INVISIBLE_STEELWALL_HORIZONTAL },
1341 { EL_STEELWALL, EL_INVISIBLE_STEELWALL }
1343 int steel_type = (BorderElement == EL_STEELWALL ? 0 : 1);
1344 int steel_position = (x == -1 && y == -1 ? 0 :
1345 x == lev_fieldx && y == -1 ? 1 :
1346 x == -1 && y == lev_fieldy ? 2 :
1347 x == lev_fieldx && y == lev_fieldy ? 3 :
1348 x == -1 || x == lev_fieldx ? 4 :
1349 y == -1 || y == lev_fieldy ? 5 : 6);
1351 return border[steel_position][steel_type];
1354 void DrawScreenElement(int x, int y, int element)
1356 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
1357 DrawCrumbledSand(x, y);
1360 void DrawLevelElement(int x, int y, int element)
1362 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1363 DrawScreenElement(SCREENX(x), SCREENY(y), element);
1366 void DrawScreenField(int x, int y)
1368 int lx = LEVELX(x), ly = LEVELY(y);
1369 int element, content;
1371 if (!IN_LEV_FIELD(lx, ly))
1373 if (lx < -1 || lx > lev_fieldx || ly < -1 || ly > lev_fieldy)
1376 element = getBorderElement(lx, ly);
1378 DrawScreenElement(x, y, element);
1382 element = Feld[lx][ly];
1383 content = Store[lx][ly];
1385 if (IS_MOVING(lx, ly))
1387 int horiz_move = (MovDir[lx][ly] == MV_LEFT || MovDir[lx][ly] == MV_RIGHT);
1388 boolean cut_mode = NO_CUTTING;
1390 if (element == EL_QUICKSAND_EMPTYING ||
1391 element == EL_MAGIC_WALL_EMPTYING ||
1392 element == EL_BD_MAGIC_WALL_EMPTYING ||
1393 element == EL_AMOEBA_DROPPING)
1394 cut_mode = CUT_ABOVE;
1395 else if (element == EL_QUICKSAND_FILLING ||
1396 element == EL_MAGIC_WALL_FILLING ||
1397 element == EL_BD_MAGIC_WALL_FILLING)
1398 cut_mode = CUT_BELOW;
1400 if (cut_mode == CUT_ABOVE)
1401 DrawScreenElementShifted(x, y, 0, 0, element, NO_CUTTING);
1403 DrawScreenElement(x, y, EL_EMPTY);
1406 DrawScreenElementShifted(x, y, MovPos[lx][ly], 0, element, NO_CUTTING);
1407 else if (cut_mode == NO_CUTTING)
1408 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], element, cut_mode);
1410 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], content, cut_mode);
1412 if (content == EL_ACID)
1413 DrawLevelElementThruMask(lx, ly + 1, EL_ACID);
1415 else if (IS_BLOCKED(lx, ly))
1420 boolean cut_mode = NO_CUTTING;
1421 int element_old, content_old;
1423 Blocked2Moving(lx, ly, &oldx, &oldy);
1426 horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
1427 MovDir[oldx][oldy] == MV_RIGHT);
1429 element_old = Feld[oldx][oldy];
1430 content_old = Store[oldx][oldy];
1432 if (element_old == EL_QUICKSAND_EMPTYING ||
1433 element_old == EL_MAGIC_WALL_EMPTYING ||
1434 element_old == EL_BD_MAGIC_WALL_EMPTYING ||
1435 element_old == EL_AMOEBA_DROPPING)
1436 cut_mode = CUT_ABOVE;
1438 DrawScreenElement(x, y, EL_EMPTY);
1441 DrawScreenElementShifted(sx, sy, MovPos[oldx][oldy], 0, element_old,
1443 else if (cut_mode == NO_CUTTING)
1444 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], element_old,
1447 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], content_old,
1450 else if (IS_DRAWABLE(element))
1451 DrawScreenElement(x, y, element);
1453 DrawScreenElement(x, y, EL_EMPTY);
1456 void DrawLevelField(int x, int y)
1458 if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1459 DrawScreenField(SCREENX(x), SCREENY(y));
1460 else if (IS_MOVING(x, y))
1464 Moving2Blocked(x, y, &newx, &newy);
1465 if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
1466 DrawScreenField(SCREENX(newx), SCREENY(newy));
1468 else if (IS_BLOCKED(x, y))
1472 Blocked2Moving(x, y, &oldx, &oldy);
1473 if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
1474 DrawScreenField(SCREENX(oldx), SCREENY(oldy));
1478 void DrawMiniElement(int x, int y, int element)
1482 graphic = el2edimg(element);
1483 DrawMiniGraphic(x, y, graphic);
1486 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
1488 int x = sx + scroll_x, y = sy + scroll_y;
1490 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
1491 DrawMiniElement(sx, sy, EL_EMPTY);
1492 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
1493 DrawMiniElement(sx, sy, Feld[x][y]);
1495 DrawMiniGraphic(sx, sy, el2edimg(getBorderElement(x, y)));
1498 void getMicroGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
1500 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
1501 int mini_startx = src_bitmap->width * 3 / 4;
1502 int mini_starty = src_bitmap->height * 2 / 3;
1503 int src_x = mini_startx + graphic_info[graphic].src_x / 8;
1504 int src_y = mini_starty + graphic_info[graphic].src_y / 8;
1506 if (src_x + MICRO_TILEX > src_bitmap->width ||
1507 src_y + MICRO_TILEY > src_bitmap->height)
1509 /* graphic of desired size seems not to be contained in this image;
1510 dirty workaround: get it from the middle of the normal sized image */
1512 getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
1513 src_x += (TILEX / 2 - MICRO_TILEX / 2);
1514 src_y += (TILEY / 2 - MICRO_TILEY / 2);
1517 *bitmap = src_bitmap;
1522 void DrawMicroElement(int xpos, int ypos, int element)
1526 int graphic = el2preimg(element);
1528 getMicroGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
1529 BlitBitmap(src_bitmap, drawto, src_x, src_y, MICRO_TILEX, MICRO_TILEY,
1537 SetDrawBackgroundMask(REDRAW_NONE);
1540 for(x=BX1; x<=BX2; x++)
1541 for(y=BY1; y<=BY2; y++)
1542 DrawScreenField(x, y);
1544 redraw_mask |= REDRAW_FIELD;
1547 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
1551 for(x=0; x<size_x; x++)
1552 for(y=0; y<size_y; y++)
1553 DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
1555 redraw_mask |= REDRAW_FIELD;
1558 static void DrawMicroLevelExt(int xpos, int ypos, int from_x, int from_y)
1562 DrawBackground(xpos, ypos, MICROLEV_XSIZE, MICROLEV_YSIZE);
1564 if (lev_fieldx < STD_LEV_FIELDX)
1565 xpos += (STD_LEV_FIELDX - lev_fieldx) / 2 * MICRO_TILEX;
1566 if (lev_fieldy < STD_LEV_FIELDY)
1567 ypos += (STD_LEV_FIELDY - lev_fieldy) / 2 * MICRO_TILEY;
1569 xpos += MICRO_TILEX;
1570 ypos += MICRO_TILEY;
1572 for(x=-1; x<=STD_LEV_FIELDX; x++)
1574 for(y=-1; y<=STD_LEV_FIELDY; y++)
1576 int lx = from_x + x, ly = from_y + y;
1578 if (lx >= 0 && lx < lev_fieldx && ly >= 0 && ly < lev_fieldy)
1579 DrawMicroElement(xpos + x * MICRO_TILEX, ypos + y * MICRO_TILEY,
1581 else if (lx >= -1 && lx < lev_fieldx+1 && ly >= -1 && ly < lev_fieldy+1
1582 && BorderElement != EL_EMPTY)
1583 DrawMicroElement(xpos + x * MICRO_TILEX, ypos + y * MICRO_TILEY,
1584 getBorderElement(lx, ly));
1588 redraw_mask |= REDRAW_MICROLEVEL;
1591 #define MICROLABEL_EMPTY 0
1592 #define MICROLABEL_LEVEL_NAME 1
1593 #define MICROLABEL_CREATED_BY 2
1594 #define MICROLABEL_LEVEL_AUTHOR 3
1595 #define MICROLABEL_IMPORTED_FROM 4
1596 #define MICROLABEL_LEVEL_IMPORT_INFO 5
1598 static void DrawMicroLevelLabelExt(int mode)
1600 char label_text[MAX_OUTPUT_LINESIZE + 1];
1601 int max_len_label_text;
1602 int font_nr = FONT_TEXT_2;
1604 if (mode == MICROLABEL_CREATED_BY || mode == MICROLABEL_IMPORTED_FROM)
1605 font_nr = FONT_TEXT_3;
1607 max_len_label_text = SXSIZE / getFontWidth(font_nr);
1609 DrawBackground(SX, MICROLABEL_YPOS, SXSIZE, getFontHeight(font_nr));
1611 strncpy(label_text, (mode == MICROLABEL_LEVEL_NAME ? level.name :
1612 mode == MICROLABEL_CREATED_BY ? "created by" :
1613 mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
1614 mode == MICROLABEL_IMPORTED_FROM ? "imported from" :
1615 mode == MICROLABEL_LEVEL_IMPORT_INFO ?
1616 leveldir_current->imported_from : ""),
1617 max_len_label_text);
1618 label_text[max_len_label_text] = '\0';
1620 if (strlen(label_text) > 0)
1622 int text_width = strlen(label_text) * getFontWidth(font_nr);
1623 int lxpos = SX + (SXSIZE - text_width) / 2;
1624 int lypos = MICROLABEL_YPOS;
1626 DrawText(lxpos, lypos, label_text, font_nr);
1629 redraw_mask |= REDRAW_MICROLEVEL;
1632 void DrawMicroLevel(int xpos, int ypos, boolean restart)
1634 static unsigned long scroll_delay = 0;
1635 static unsigned long label_delay = 0;
1636 static int from_x, from_y, scroll_direction;
1637 static int label_state, label_counter;
1638 int last_game_status = game_status; /* save current game status */
1640 game_status = PSEUDO_PREVIEW; /* force PREVIEW font on preview level */
1644 from_x = from_y = 0;
1645 scroll_direction = MV_RIGHT;
1649 DrawMicroLevelExt(xpos, ypos, from_x, from_y);
1650 DrawMicroLevelLabelExt(label_state);
1652 /* initialize delay counters */
1653 DelayReached(&scroll_delay, 0);
1654 DelayReached(&label_delay, 0);
1656 if (leveldir_current->name)
1658 int len = strlen(leveldir_current->name);
1659 int lxpos = SX + (SXSIZE - len * getFontWidth(FONT_TEXT_1)) / 2;
1660 int lypos = SY + 352;
1662 DrawText(lxpos, lypos, leveldir_current->name, FONT_TEXT_1);
1665 game_status = last_game_status; /* restore current game status */
1670 /* scroll micro level, if needed */
1671 if ((lev_fieldx > STD_LEV_FIELDX || lev_fieldy > STD_LEV_FIELDY) &&
1672 DelayReached(&scroll_delay, MICROLEVEL_SCROLL_DELAY))
1674 switch (scroll_direction)
1680 scroll_direction = MV_UP;
1684 if (from_x < lev_fieldx - STD_LEV_FIELDX)
1687 scroll_direction = MV_DOWN;
1694 scroll_direction = MV_RIGHT;
1698 if (from_y < lev_fieldy - STD_LEV_FIELDY)
1701 scroll_direction = MV_LEFT;
1708 DrawMicroLevelExt(xpos, ypos, from_x, from_y);
1711 /* redraw micro level label, if needed */
1712 if (strcmp(level.name, NAMELESS_LEVEL_NAME) != 0 &&
1713 strcmp(level.author, ANONYMOUS_NAME) != 0 &&
1714 strcmp(level.author, leveldir_current->name) != 0 &&
1715 DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
1717 int max_label_counter = 23;
1719 if (leveldir_current->imported_from != NULL)
1720 max_label_counter += 14;
1722 label_counter = (label_counter + 1) % max_label_counter;
1723 label_state = (label_counter >= 0 && label_counter <= 7 ?
1724 MICROLABEL_LEVEL_NAME :
1725 label_counter >= 9 && label_counter <= 12 ?
1726 MICROLABEL_CREATED_BY :
1727 label_counter >= 14 && label_counter <= 21 ?
1728 MICROLABEL_LEVEL_AUTHOR :
1729 label_counter >= 23 && label_counter <= 26 ?
1730 MICROLABEL_IMPORTED_FROM :
1731 label_counter >= 28 && label_counter <= 35 ?
1732 MICROLABEL_LEVEL_IMPORT_INFO : MICROLABEL_EMPTY);
1733 DrawMicroLevelLabelExt(label_state);
1736 game_status = last_game_status; /* restore current game status */
1739 int REQ_in_range(int x, int y)
1741 if (y > DY+249 && y < DY+278)
1743 if (x > DX+1 && x < DX+48)
1745 else if (x > DX+51 && x < DX+98)
1751 #define MAX_REQUEST_LINES 13
1752 #define MAX_REQUEST_LINE_LEN 7
1754 boolean Request(char *text, unsigned int req_state)
1756 int mx, my, ty, result = -1;
1757 unsigned int old_door_state;
1758 int last_game_status = game_status; /* save current game status */
1760 #if defined(PLATFORM_UNIX)
1761 /* pause network game while waiting for request to answer */
1762 if (options.network &&
1763 game_status == PLAYING &&
1764 req_state & REQUEST_WAIT_FOR)
1765 SendToServer_PausePlaying();
1768 old_door_state = GetDoorState();
1772 CloseDoor(DOOR_CLOSE_1);
1774 /* save old door content */
1775 BlitBitmap(bitmap_db_door, bitmap_db_door,
1776 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
1777 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
1779 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
1781 /* clear door drawing field */
1782 DrawBackground(DX, DY, DXSIZE, DYSIZE);
1784 game_status = PSEUDO_DOOR; /* force DOOR font on preview level */
1786 /* write text for request */
1787 for(ty=0; ty < MAX_REQUEST_LINES; ty++)
1789 char text_line[MAX_REQUEST_LINE_LEN + 1];
1795 for(tl=0,tx=0; tx < MAX_REQUEST_LINE_LEN; tl++,tx++)
1798 if (!tc || tc == ' ')
1809 strncpy(text_line, text, tl);
1812 DrawText(DX + (DXSIZE - tl * getFontWidth(FONT_TEXT_2)) / 2,
1813 DY + 8 + ty * (getFontHeight(FONT_TEXT_2) + 2),
1814 text_line, FONT_TEXT_2);
1816 text += tl + (tc == ' ' ? 1 : 0);
1819 game_status = last_game_status; /* restore current game status */
1821 if (req_state & REQ_ASK)
1823 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
1824 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
1826 else if (req_state & REQ_CONFIRM)
1828 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
1830 else if (req_state & REQ_PLAYER)
1832 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
1833 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
1834 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
1835 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
1838 /* copy request gadgets to door backbuffer */
1839 BlitBitmap(drawto, bitmap_db_door,
1840 DX, DY, DXSIZE, DYSIZE,
1841 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
1843 OpenDoor(DOOR_OPEN_1);
1849 if (!(req_state & REQUEST_WAIT_FOR))
1851 SetDrawBackgroundMask(REDRAW_FIELD);
1856 if (game_status != MAINMENU)
1859 button_status = MB_RELEASED;
1861 request_gadget_id = -1;
1863 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
1875 case EVENT_BUTTONPRESS:
1876 case EVENT_BUTTONRELEASE:
1877 case EVENT_MOTIONNOTIFY:
1879 if (event.type == EVENT_MOTIONNOTIFY)
1881 if (!PointerInWindow(window))
1882 continue; /* window and pointer are on different screens */
1887 motion_status = TRUE;
1888 mx = ((MotionEvent *) &event)->x;
1889 my = ((MotionEvent *) &event)->y;
1893 motion_status = FALSE;
1894 mx = ((ButtonEvent *) &event)->x;
1895 my = ((ButtonEvent *) &event)->y;
1896 if (event.type == EVENT_BUTTONPRESS)
1897 button_status = ((ButtonEvent *) &event)->button;
1899 button_status = MB_RELEASED;
1902 /* this sets 'request_gadget_id' */
1903 HandleGadgets(mx, my, button_status);
1905 switch(request_gadget_id)
1907 case TOOL_CTRL_ID_YES:
1910 case TOOL_CTRL_ID_NO:
1913 case TOOL_CTRL_ID_CONFIRM:
1914 result = TRUE | FALSE;
1917 case TOOL_CTRL_ID_PLAYER_1:
1920 case TOOL_CTRL_ID_PLAYER_2:
1923 case TOOL_CTRL_ID_PLAYER_3:
1926 case TOOL_CTRL_ID_PLAYER_4:
1937 case EVENT_KEYPRESS:
1938 switch(GetEventKey((KeyEvent *)&event, TRUE))
1951 if (req_state & REQ_PLAYER)
1955 case EVENT_KEYRELEASE:
1956 ClearPlayerAction();
1960 HandleOtherEvents(&event);
1964 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
1966 int joy = AnyJoystick();
1968 if (joy & JOY_BUTTON_1)
1970 else if (joy & JOY_BUTTON_2)
1976 /* don't eat all CPU time */
1980 if (game_status != MAINMENU)
1985 if (!(req_state & REQ_STAY_OPEN))
1987 CloseDoor(DOOR_CLOSE_1);
1989 if (!(req_state & REQ_STAY_CLOSED) && (old_door_state & DOOR_OPEN_1))
1991 BlitBitmap(bitmap_db_door, bitmap_db_door,
1992 DOOR_GFX_PAGEX2,DOOR_GFX_PAGEY1, DXSIZE,DYSIZE,
1993 DOOR_GFX_PAGEX1,DOOR_GFX_PAGEY1);
1994 OpenDoor(DOOR_OPEN_1);
2000 SetDrawBackgroundMask(REDRAW_FIELD);
2002 #if defined(PLATFORM_UNIX)
2003 /* continue network game after request */
2004 if (options.network &&
2005 game_status == PLAYING &&
2006 req_state & REQUEST_WAIT_FOR)
2007 SendToServer_ContinuePlaying();
2013 unsigned int OpenDoor(unsigned int door_state)
2015 unsigned int new_door_state;
2017 if (door_state & DOOR_COPY_BACK)
2019 BlitBitmap(bitmap_db_door, bitmap_db_door,
2020 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE + VYSIZE,
2021 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2022 door_state &= ~DOOR_COPY_BACK;
2025 new_door_state = MoveDoor(door_state);
2027 return(new_door_state);
2030 unsigned int CloseDoor(unsigned int door_state)
2032 unsigned int new_door_state;
2034 BlitBitmap(backbuffer, bitmap_db_door,
2035 DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2036 BlitBitmap(backbuffer, bitmap_db_door,
2037 VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
2039 new_door_state = MoveDoor(door_state);
2041 return(new_door_state);
2044 unsigned int GetDoorState()
2046 return MoveDoor(DOOR_GET_STATE);
2049 unsigned int SetDoorState(unsigned int door_state)
2051 return MoveDoor(door_state | DOOR_SET_STATE);
2054 unsigned int MoveDoor(unsigned int door_state)
2056 static int door1 = DOOR_OPEN_1;
2057 static int door2 = DOOR_CLOSE_2;
2058 static unsigned long door_delay = 0;
2059 int x, start, stepsize = global.door_step_offset;
2060 unsigned long door_delay_value = global.door_step_delay;
2062 if (door_state == DOOR_GET_STATE)
2063 return(door1 | door2);
2065 if (door_state & DOOR_SET_STATE)
2067 if (door_state & DOOR_ACTION_1)
2068 door1 = door_state & DOOR_ACTION_1;
2069 if (door_state & DOOR_ACTION_2)
2070 door2 = door_state & DOOR_ACTION_2;
2072 return(door1 | door2);
2075 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
2076 door_state &= ~DOOR_OPEN_1;
2077 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
2078 door_state &= ~DOOR_CLOSE_1;
2079 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
2080 door_state &= ~DOOR_OPEN_2;
2081 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
2082 door_state &= ~DOOR_CLOSE_2;
2084 if (setup.quick_doors)
2087 door_delay_value = 0;
2089 StopSound(SND_MENU_DOOR_OPENING);
2090 StopSound(SND_MENU_DOOR_CLOSING);
2093 if (global.autoplay_leveldir)
2095 door_state |= DOOR_NO_DELAY;
2096 door_state &= ~DOOR_CLOSE_ALL;
2099 if (door_state & DOOR_ACTION)
2101 if (!(door_state & DOOR_NO_DELAY))
2103 /* opening door sound has priority over simultaneously closing door */
2104 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
2105 PlaySoundStereo(SND_MENU_DOOR_OPENING, SOUND_MAX_RIGHT);
2106 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
2107 PlaySoundStereo(SND_MENU_DOOR_CLOSING, SOUND_MAX_RIGHT);
2110 start = ((door_state & DOOR_NO_DELAY) ? DXSIZE : 0);
2112 for(x=start; x<=DXSIZE; x+=stepsize)
2114 Bitmap *bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
2115 GC gc = bitmap->stored_clip_gc;
2117 if (!(door_state & DOOR_NO_DELAY))
2118 WaitUntilDelayReached(&door_delay, door_delay_value);
2120 if (door_state & DOOR_ACTION_1)
2122 int i = (door_state & DOOR_OPEN_1 ? DXSIZE-x : x);
2123 int j = (DXSIZE - i) / 3;
2125 BlitBitmap(bitmap_db_door, drawto,
2126 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + i/2,
2127 DXSIZE,DYSIZE - i/2, DX, DY);
2129 ClearRectangle(drawto, DX, DY + DYSIZE - i/2, DXSIZE,i/2);
2131 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2132 BlitBitmapMasked(bitmap, drawto,
2133 DXSIZE, DOOR_GFX_PAGEY1, i, 77,
2134 DX + DXSIZE - i, DY + j);
2135 BlitBitmapMasked(bitmap, drawto,
2136 DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63,
2137 DX + DXSIZE - i, DY + 140 + j);
2138 SetClipOrigin(bitmap, gc, DX - DXSIZE + i, DY - (DOOR_GFX_PAGEY1 + j));
2139 BlitBitmapMasked(bitmap, drawto,
2140 DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j,
2142 BlitBitmapMasked(bitmap, drawto,
2143 DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63,
2146 BlitBitmapMasked(bitmap, drawto,
2147 DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
2149 BlitBitmapMasked(bitmap, drawto,
2150 DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
2152 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2153 BlitBitmapMasked(bitmap, drawto,
2154 DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
2155 DX + DXSIZE - i, DY + 77 + j);
2156 BlitBitmapMasked(bitmap, drawto,
2157 DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
2158 DX + DXSIZE - i, DY + 203 + j);
2160 redraw_mask |= REDRAW_DOOR_1;
2163 if (door_state & DOOR_ACTION_2)
2165 int i = (door_state & DOOR_OPEN_2 ? VXSIZE - x : x);
2166 int j = (VXSIZE - i) / 3;
2168 BlitBitmap(bitmap_db_door, drawto,
2169 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + i/2,
2170 VXSIZE, VYSIZE - i/2, VX, VY);
2172 ClearRectangle(drawto, VX, VY + VYSIZE-i/2, VXSIZE, i/2);
2174 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2175 BlitBitmapMasked(bitmap, drawto,
2176 VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2,
2177 VX + VXSIZE-i, VY+j);
2178 SetClipOrigin(bitmap, gc,
2179 VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
2180 BlitBitmapMasked(bitmap, drawto,
2181 VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j,
2184 BlitBitmapMasked(bitmap, drawto,
2185 VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2,
2186 i, VYSIZE / 2, VX, VY + VYSIZE / 2 - j);
2187 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2188 BlitBitmapMasked(bitmap, drawto,
2189 VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2,
2191 VX + VXSIZE - i, VY + VYSIZE / 2 + j);
2193 redraw_mask |= REDRAW_DOOR_2;
2198 if (game_status == MAINMENU)
2203 if (setup.quick_doors)
2205 StopSound(SND_MENU_DOOR_OPENING);
2206 StopSound(SND_MENU_DOOR_CLOSING);
2209 if (door_state & DOOR_ACTION_1)
2210 door1 = door_state & DOOR_ACTION_1;
2211 if (door_state & DOOR_ACTION_2)
2212 door2 = door_state & DOOR_ACTION_2;
2214 return (door1 | door2);
2217 void DrawSpecialEditorDoor()
2219 /* draw bigger toolbox window */
2220 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
2221 DOOR_GFX_PAGEX7, 0, EXSIZE + 8, 8,
2223 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
2224 EX - 4, VY - 4, EXSIZE + 8, EYSIZE - VYSIZE + 4,
2227 redraw_mask |= REDRAW_ALL;
2230 void UndrawSpecialEditorDoor()
2232 /* draw normal tape recorder window */
2233 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
2234 EX - 4, EY - 12, EXSIZE + 8, EYSIZE - VYSIZE + 12,
2237 redraw_mask |= REDRAW_ALL;
2241 int ReadPixel(DrawBuffer *bitmap, int x, int y)
2243 XImage *pixel_image;
2244 unsigned long pixel_value;
2246 pixel_image = XGetImage(display, bitmap->drawable,
2247 x, y, 1, 1, AllPlanes, ZPixmap);
2248 pixel_value = XGetPixel(pixel_image, 0, 0);
2250 XDestroyImage(pixel_image);
2256 /* ---------- new tool button stuff ---------------------------------------- */
2258 /* graphic position values for tool buttons */
2259 #define TOOL_BUTTON_YES_XPOS 2
2260 #define TOOL_BUTTON_YES_YPOS 250
2261 #define TOOL_BUTTON_YES_GFX_YPOS 0
2262 #define TOOL_BUTTON_YES_XSIZE 46
2263 #define TOOL_BUTTON_YES_YSIZE 28
2264 #define TOOL_BUTTON_NO_XPOS 52
2265 #define TOOL_BUTTON_NO_YPOS TOOL_BUTTON_YES_YPOS
2266 #define TOOL_BUTTON_NO_GFX_YPOS TOOL_BUTTON_YES_GFX_YPOS
2267 #define TOOL_BUTTON_NO_XSIZE TOOL_BUTTON_YES_XSIZE
2268 #define TOOL_BUTTON_NO_YSIZE TOOL_BUTTON_YES_YSIZE
2269 #define TOOL_BUTTON_CONFIRM_XPOS TOOL_BUTTON_YES_XPOS
2270 #define TOOL_BUTTON_CONFIRM_YPOS TOOL_BUTTON_YES_YPOS
2271 #define TOOL_BUTTON_CONFIRM_GFX_YPOS 30
2272 #define TOOL_BUTTON_CONFIRM_XSIZE 96
2273 #define TOOL_BUTTON_CONFIRM_YSIZE TOOL_BUTTON_YES_YSIZE
2274 #define TOOL_BUTTON_PLAYER_XSIZE 30
2275 #define TOOL_BUTTON_PLAYER_YSIZE 30
2276 #define TOOL_BUTTON_PLAYER_GFX_XPOS 5
2277 #define TOOL_BUTTON_PLAYER_GFX_YPOS 185
2278 #define TOOL_BUTTON_PLAYER_XPOS (5 + TOOL_BUTTON_PLAYER_XSIZE / 2)
2279 #define TOOL_BUTTON_PLAYER_YPOS (215 - TOOL_BUTTON_PLAYER_YSIZE / 2)
2280 #define TOOL_BUTTON_PLAYER1_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2281 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2282 #define TOOL_BUTTON_PLAYER2_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2283 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2284 #define TOOL_BUTTON_PLAYER3_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2285 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2286 #define TOOL_BUTTON_PLAYER4_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2287 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2288 #define TOOL_BUTTON_PLAYER1_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2289 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2290 #define TOOL_BUTTON_PLAYER2_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2291 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2292 #define TOOL_BUTTON_PLAYER3_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2293 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2294 #define TOOL_BUTTON_PLAYER4_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2295 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2304 } toolbutton_info[NUM_TOOL_BUTTONS] =
2307 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_GFX_YPOS,
2308 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_YPOS,
2309 TOOL_BUTTON_YES_XSIZE, TOOL_BUTTON_YES_YSIZE,
2314 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_GFX_YPOS,
2315 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_YPOS,
2316 TOOL_BUTTON_NO_XSIZE, TOOL_BUTTON_NO_YSIZE,
2321 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_GFX_YPOS,
2322 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_YPOS,
2323 TOOL_BUTTON_CONFIRM_XSIZE, TOOL_BUTTON_CONFIRM_YSIZE,
2324 TOOL_CTRL_ID_CONFIRM,
2328 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2329 TOOL_BUTTON_PLAYER1_XPOS, TOOL_BUTTON_PLAYER1_YPOS,
2330 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2331 TOOL_CTRL_ID_PLAYER_1,
2335 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2336 TOOL_BUTTON_PLAYER2_XPOS, TOOL_BUTTON_PLAYER2_YPOS,
2337 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2338 TOOL_CTRL_ID_PLAYER_2,
2342 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2343 TOOL_BUTTON_PLAYER3_XPOS, TOOL_BUTTON_PLAYER3_YPOS,
2344 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2345 TOOL_CTRL_ID_PLAYER_3,
2349 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2350 TOOL_BUTTON_PLAYER4_XPOS, TOOL_BUTTON_PLAYER4_YPOS,
2351 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2352 TOOL_CTRL_ID_PLAYER_4,
2357 void CreateToolButtons()
2361 for (i=0; i<NUM_TOOL_BUTTONS; i++)
2363 Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
2364 Bitmap *deco_bitmap = None;
2365 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
2366 struct GadgetInfo *gi;
2367 unsigned long event_mask;
2368 int gd_xoffset, gd_yoffset;
2369 int gd_x1, gd_x2, gd_y;
2372 event_mask = GD_EVENT_RELEASED;
2374 gd_xoffset = toolbutton_info[i].xpos;
2375 gd_yoffset = toolbutton_info[i].ypos;
2376 gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
2377 gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
2378 gd_y = DOOR_GFX_PAGEY1 + gd_yoffset;
2380 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
2382 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
2384 getMiniGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr),
2385 &deco_bitmap, &deco_x, &deco_y);
2386 deco_xpos = (toolbutton_info[i].width - MINI_TILEX) / 2;
2387 deco_ypos = (toolbutton_info[i].height - MINI_TILEY) / 2;
2390 gi = CreateGadget(GDI_CUSTOM_ID, id,
2391 GDI_INFO_TEXT, toolbutton_info[i].infotext,
2392 GDI_X, DX + toolbutton_info[i].x,
2393 GDI_Y, DY + toolbutton_info[i].y,
2394 GDI_WIDTH, toolbutton_info[i].width,
2395 GDI_HEIGHT, toolbutton_info[i].height,
2396 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
2397 GDI_STATE, GD_BUTTON_UNPRESSED,
2398 GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
2399 GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
2400 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
2401 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
2402 GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
2403 GDI_DECORATION_SHIFTING, 1, 1,
2404 GDI_EVENT_MASK, event_mask,
2405 GDI_CALLBACK_ACTION, HandleToolButtons,
2409 Error(ERR_EXIT, "cannot create gadget");
2411 tool_gadget[id] = gi;
2415 void FreeToolButtons()
2419 for (i=0; i<NUM_TOOL_BUTTONS; i++)
2420 FreeGadget(tool_gadget[i]);
2423 static void UnmapToolButtons()
2427 for (i=0; i<NUM_TOOL_BUTTONS; i++)
2428 UnmapGadget(tool_gadget[i]);
2431 static void HandleToolButtons(struct GadgetInfo *gi)
2433 request_gadget_id = gi->custom_id;
2436 int get_next_element(int element)
2440 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
2441 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
2442 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
2443 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
2444 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
2445 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
2446 case EL_AMOEBA_DROPPING: return EL_AMOEBA_WET;
2448 default: return element;
2452 int el_act_dir2img(int element, int action, int direction)
2454 direction = MV_DIR_BIT(direction);
2456 return element_info[element].direction_graphic[action][direction];
2459 int el_act2img(int element, int action)
2461 return element_info[element].graphic[action];
2464 int el_dir2img(int element, int direction)
2466 return el_act_dir2img(element, ACTION_DEFAULT, direction);
2469 int el2img(int element)
2471 return element_info[element].graphic[ACTION_DEFAULT];
2474 int el2edimg(int element)
2476 return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
2479 int el2preimg(int element)
2481 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];