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, BLIT_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 move_dir = player->MovDir;
546 int action = ACTION_DEFAULT;
548 if (!player->active || !IN_SCR_FIELD(SCREENX(last_jx), SCREENY(last_jy)))
552 if (!IN_LEV_FIELD(jx,jy))
554 printf("DrawPlayerField(): x = %d, y = %d\n",jx,jy);
555 printf("DrawPlayerField(): sx = %d, sy = %d\n",sx,sy);
556 printf("DrawPlayerField(): This should never happen!\n");
561 if (element == EL_EXPLOSION)
564 action = (player->Pushing ? ACTION_PUSHING :
565 player->is_digging ? ACTION_DIGGING :
566 player->is_collecting ? ACTION_COLLECTING :
567 player->is_moving ? ACTION_MOVING :
568 player->snapped ? ACTION_SNAPPING : ACTION_DEFAULT);
570 InitPlayerGfxAnimation(player, action, move_dir);
572 /* ----------------------------------------------------------------------- */
573 /* draw things in the field the player is leaving, if needed */
574 /* ----------------------------------------------------------------------- */
576 if (player_is_moving)
578 if (Store[last_jx][last_jy] && IS_DRAWABLE(last_element))
580 DrawLevelElement(last_jx, last_jy, Store[last_jx][last_jy]);
582 if (last_element == EL_DYNAMITE_ACTIVE ||
583 last_element == EL_SP_DISK_RED_ACTIVE)
584 DrawDynamite(last_jx, last_jy);
586 DrawLevelFieldThruMask(last_jx, last_jy);
588 else if (last_element == EL_DYNAMITE_ACTIVE ||
589 last_element == EL_SP_DISK_RED_ACTIVE)
590 DrawDynamite(last_jx, last_jy);
592 DrawLevelField(last_jx, last_jy);
594 if (player->Pushing && IN_SCR_FIELD(SCREENX(next_jx), SCREENY(next_jy)))
598 if (Feld[next_jx][next_jy] == EL_SOKOBAN_FIELD_FULL)
599 DrawLevelElement(next_jx, next_jy, EL_SOKOBAN_FIELD_EMPTY);
601 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
604 DrawLevelField(next_jx, next_jy);
608 if (!IN_SCR_FIELD(sx, sy))
611 if (setup.direct_draw)
612 SetDrawtoField(DRAW_BUFFERED);
614 /* ----------------------------------------------------------------------- */
615 /* draw things behind the player, if needed */
616 /* ----------------------------------------------------------------------- */
619 DrawLevelElement(jx, jy, Store[jx][jy]);
620 else if (IS_ACTIVE_BOMB(element))
621 DrawLevelElement(jx, jy, EL_EMPTY);
624 if (player_is_moving && GfxElement[jx][jy] != EL_UNDEFINED)
626 if (GfxElement[jx][jy] == EL_SAND)
627 DrawLevelFieldCrumbledSandDigging(jx, jy, move_dir, player->StepFrame);
630 int old_element = GfxElement[jx][jy];
631 int old_graphic = el_act_dir2img(old_element, action, move_dir);
632 int frame = getGraphicAnimationFrame(old_graphic, player->StepFrame);
634 DrawGraphic(sx, sy, old_graphic, frame);
639 GfxElement[jx][jy] = EL_UNDEFINED;
641 DrawLevelField(jx, jy);
645 /* ----------------------------------------------------------------------- */
646 /* draw player himself */
647 /* ----------------------------------------------------------------------- */
649 if (player->use_murphy_graphic)
651 static int last_horizontal_dir = MV_LEFT;
654 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
655 last_horizontal_dir = move_dir;
657 direction = (player->snapped ? move_dir : last_horizontal_dir);
659 graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, direction);
662 graphic = el_act_dir2img(player->element_nr, player->GfxAction, move_dir);
664 frame = getGraphicAnimationFrame(graphic, player->Frame);
668 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
669 sxx = player->GfxPos;
671 syy = player->GfxPos;
674 if (!setup.soft_scrolling && ScreenMovPos)
677 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
679 if (SHIELD_ON(player))
681 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
682 IMG_SHIELD_NORMAL_ACTIVE);
683 int frame = getGraphicAnimationFrame(graphic, -1);
685 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
688 /* ----------------------------------------------------------------------- */
689 /* draw things the player is pushing, if needed */
690 /* ----------------------------------------------------------------------- */
692 if (player->Pushing && player_is_moving)
694 int px = SCREENX(next_jx), py = SCREENY(next_jy);
697 (element == EL_SOKOBAN_FIELD_EMPTY ||
698 Feld[next_jx][next_jy] == EL_SOKOBAN_FIELD_FULL))
699 DrawGraphicShiftedThruMask(px, py, sxx, syy, IMG_SOKOBAN_OBJECT, 0,
703 int element = Feld[next_jx][next_jy];
704 int graphic = el2img(element);
707 if ((sxx || syy) && IS_PUSHABLE(element))
709 graphic = el_act_dir2img(element, ACTION_MOVING, move_dir);
710 frame = getGraphicAnimationFrame(graphic, player->Frame);
713 DrawGraphicShifted(px, py, sxx, syy, graphic, frame,
714 NO_CUTTING, NO_MASKING);
718 /* ----------------------------------------------------------------------- */
719 /* draw things in front of player (active dynamite or dynabombs) */
720 /* ----------------------------------------------------------------------- */
722 if (IS_ACTIVE_BOMB(element))
724 graphic = el2img(element);
725 frame = getGraphicAnimationFrame(graphic, GfxFrame[jx][jy]);
727 if (game.emulation == EMU_SUPAPLEX)
728 DrawGraphic(sx, sy, IMG_SP_DISK_RED, frame);
730 DrawGraphicThruMask(sx, sy, graphic, frame);
733 if (player_is_moving && last_element == EL_EXPLOSION)
735 int stored = Store[last_jx][last_jy];
736 int graphic = (game.emulation != EMU_SUPAPLEX ? IMG_EXPLOSION :
737 stored == EL_SP_INFOTRON ? IMG_SP_EXPLOSION_INFOTRON :
739 int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
740 int phase = ExplodePhase[last_jx][last_jy] - 1;
741 int frame = getGraphicAnimationFrame(graphic, phase - delay);
744 DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy), graphic, frame);
747 /* ----------------------------------------------------------------------- */
748 /* draw elements that stay over the player */
749 /* ----------------------------------------------------------------------- */
751 /* handle the field the player is leaving ... */
752 if (player_is_moving && IS_OVER_PLAYER(last_element))
753 DrawLevelField(last_jx, last_jy);
755 /* ... and the field the player is entering */
756 if (IS_OVER_PLAYER(element))
757 DrawLevelField(jx, jy);
759 if (setup.direct_draw)
761 int dest_x = SX + SCREENX(MIN(jx, last_jx)) * TILEX;
762 int dest_y = SY + SCREENY(MIN(jy, last_jy)) * TILEY;
763 int x_size = TILEX * (1 + ABS(jx - last_jx));
764 int y_size = TILEY * (1 + ABS(jy - last_jy));
766 BlitBitmap(drawto_field, window,
767 dest_x, dest_y, x_size, y_size, dest_x, dest_y);
768 SetDrawtoField(DRAW_DIRECT);
771 MarkTileDirty(sx,sy);
774 void getGraphicSource(int graphic, int frame, Bitmap **bitmap, int *x, int *y)
776 struct GraphicInfo *g = &graphic_info[graphic];
780 if (g->offset_y == 0) /* frames are ordered horizontally */
782 *x = g->src_x + (frame % g->anim_frames_per_line) * g->offset_x;
783 *y = g->src_y + (frame / g->anim_frames_per_line) * g->height;
785 else if (g->offset_x == 0) /* frames are ordered vertically */
787 *x = g->src_x + (frame / g->anim_frames_per_line) * g->width;
788 *y = g->src_y + (frame % g->anim_frames_per_line) * g->offset_y;
790 else /* frames are ordered diagonally */
792 *x = g->src_x + frame * g->offset_x;
793 *y = g->src_y + frame * g->offset_y;
797 void DrawGraphic(int x, int y, int graphic, int frame)
800 if (!IN_SCR_FIELD(x, y))
802 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
803 printf("DrawGraphic(): This should never happen!\n");
808 DrawGraphicExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic, frame);
813 void DrawOldGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic)
818 getOldGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
819 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
823 void DrawGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
830 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
832 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
833 int src_x = graphic_info[graphic].src_x;
834 int src_y = graphic_info[graphic].src_y;
835 int offset_x = graphic_info[graphic].offset_x;
836 int offset_y = graphic_info[graphic].offset_y;
838 src_x += frame * offset_x;
839 src_y += frame * offset_y;
842 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
845 void DrawGraphicThruMask(int x, int y, int graphic, int frame)
848 if (!IN_SCR_FIELD(x, y))
850 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
851 printf("DrawGraphicThruMask(): This should never happen!\n");
856 DrawGraphicThruMaskExt(drawto_field, FX + x * TILEX, FY + y *TILEY, graphic,
861 void DrawGraphicThruMaskExt(DrawBuffer *d, int dest_x, int dest_y, int graphic,
869 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
870 drawing_gc = src_bitmap->stored_clip_gc;
872 GC drawing_gc = src_bitmap->stored_clip_gc;
873 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
874 int src_x = graphic_info[graphic].src_x;
875 int src_y = graphic_info[graphic].src_y;
876 int offset_x = graphic_info[graphic].offset_x;
877 int offset_y = graphic_info[graphic].offset_y;
879 src_x += frame * offset_x;
880 src_y += frame * offset_y;
884 SetClipOrigin(src_bitmap, drawing_gc, dest_x - src_x, dest_y - src_y);
885 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX, TILEY, dest_x, dest_y);
888 void DrawMiniGraphic(int x, int y, int graphic)
890 DrawMiniGraphicExt(drawto, SX + x * MINI_TILEX,SY + y * MINI_TILEY, graphic);
891 MarkTileDirty(x / 2, y / 2);
894 void getMiniGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
896 struct GraphicInfo *g = &graphic_info[graphic];
898 int mini_starty = g->bitmap->height * 2 / 3;
901 *x = mini_startx + g->src_x / 2;
902 *y = mini_starty + g->src_y / 2;
905 void DrawMiniGraphicExt(DrawBuffer *d, int x, int y, int graphic)
910 getMiniGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
911 BlitBitmap(src_bitmap, d, src_x, src_y, MINI_TILEX, MINI_TILEY, x, y);
914 void DrawGraphicShifted(int x,int y, int dx,int dy, int graphic, int frame,
915 int cut_mode, int mask_mode)
924 int width = TILEX, height = TILEY;
930 DrawGraphic(x, y, graphic, frame);
934 if (dx || dy) /* shifted graphic */
936 if (x < BX1) /* object enters playfield from the left */
943 else if (x > BX2) /* object enters playfield from the right */
949 else if (x==BX1 && dx < 0) /* object leaves playfield to the left */
955 else if (x==BX2 && dx > 0) /* object leaves playfield to the right */
957 else if (dx) /* general horizontal movement */
958 MarkTileDirty(x + SIGN(dx), y);
960 if (y < BY1) /* object enters playfield from the top */
962 if (cut_mode==CUT_BELOW) /* object completely above top border */
970 else if (y > BY2) /* object enters playfield from the bottom */
976 else if (y==BY1 && dy < 0) /* object leaves playfield to the top */
982 else if (dy > 0 && cut_mode == CUT_ABOVE)
984 if (y == BY2) /* object completely above bottom border */
990 MarkTileDirty(x, y + 1);
991 } /* object leaves playfield to the bottom */
992 else if (dy > 0 && (y == BY2 || cut_mode == CUT_BELOW))
994 else if (dy) /* general vertical movement */
995 MarkTileDirty(x, y + SIGN(dy));
998 src_bitmap = graphic_info[graphic].bitmap;
999 src_x = graphic_info[graphic].src_x;
1000 src_y = graphic_info[graphic].src_y;
1001 offset_x = graphic_info[graphic].offset_x;
1002 offset_y = graphic_info[graphic].offset_y;
1004 drawing_gc = src_bitmap->stored_clip_gc;
1006 src_x += frame * offset_x;
1007 src_y += frame * offset_y;
1012 dest_x = FX + x * TILEX + dx;
1013 dest_y = FY + y * TILEY + dy;
1016 if (!IN_SCR_FIELD(x,y))
1018 printf("DrawGraphicShifted(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
1019 printf("DrawGraphicShifted(): This should never happen!\n");
1024 if (mask_mode == USE_MASKING)
1026 SetClipOrigin(src_bitmap, drawing_gc, dest_x - src_x, dest_y - src_y);
1027 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1031 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1037 void DrawGraphicShiftedThruMask(int x, int y, int dx, int dy, int graphic,
1038 int frame, int cut_mode)
1040 DrawGraphicShifted(x,y, dx,dy, graphic, frame, cut_mode, USE_MASKING);
1043 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
1044 int cut_mode, int mask_mode)
1046 int lx = LEVELX(x), ly = LEVELY(y);
1050 if (IN_LEV_FIELD(lx, ly))
1052 SetRandomAnimationValue(lx, ly);
1054 graphic = el_act_dir2img(element, GfxAction[lx][ly], MovDir[lx][ly]);
1055 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1057 else /* border element */
1059 graphic = el2img(element);
1060 frame = getGraphicAnimationFrame(graphic, -1);
1063 if (element == EL_EXPANDABLE_WALL)
1065 boolean left_stopped = FALSE, right_stopped = FALSE;
1067 if (!IN_LEV_FIELD(lx - 1, ly) || IS_MAUER(Feld[lx - 1][ly]))
1068 left_stopped = TRUE;
1069 if (!IN_LEV_FIELD(lx + 1, ly) || IS_MAUER(Feld[lx + 1][ly]))
1070 right_stopped = TRUE;
1072 if (left_stopped && right_stopped)
1074 else if (left_stopped)
1076 graphic = IMG_EXPANDABLE_WALL_GROWING_RIGHT;
1077 frame = graphic_info[graphic].anim_frames - 1;
1079 else if (right_stopped)
1081 graphic = IMG_EXPANDABLE_WALL_GROWING_LEFT;
1082 frame = graphic_info[graphic].anim_frames - 1;
1086 else if (IS_AMOEBOID(element) || element == EL_AMOEBA_DROPPING)
1088 graphic = (element == EL_BD_AMOEBA ? IMG_BD_AMOEBA_PART1 :
1089 element == EL_AMOEBA_WET ? IMG_AMOEBA_WET_PART1 :
1090 element == EL_AMOEBA_DRY ? IMG_AMOEBA_DRY_PART1 :
1091 element == EL_AMOEBA_FULL ? IMG_AMOEBA_FULL_PART1 :
1092 IMG_AMOEBA_DEAD_PART1);
1094 graphic += (x + 2 * y + 4) % 4;
1099 if (IS_AMOEBOID(element) || element == EL_AMOEBA_DROPPING)
1101 if (Feld[lx][ly] == EL_AMOEBA_DROPPING)
1102 printf("---> %d -> %d / %d [%d]\n",
1103 element, graphic, frame, GfxRandom[lx][ly]);
1108 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, mask_mode);
1109 else if (mask_mode == USE_MASKING)
1110 DrawGraphicThruMask(x, y, graphic, frame);
1112 DrawGraphic(x, y, graphic, frame);
1115 void DrawLevelElementExt(int x, int y, int dx, int dy, int element,
1116 int cut_mode, int mask_mode)
1118 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1119 DrawScreenElementExt(SCREENX(x), SCREENY(y), dx, dy, element,
1120 cut_mode, mask_mode);
1123 void DrawScreenElementShifted(int x, int y, int dx, int dy, int element,
1126 DrawScreenElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1129 void DrawLevelElementShifted(int x, int y, int dx, int dy, int element,
1132 DrawLevelElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1136 void DrawOldScreenElementThruMask(int x, int y, int element)
1138 DrawOldScreenElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1141 void DrawScreenElementThruMask(int x, int y, int element)
1143 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1147 void DrawLevelElementThruMask(int x, int y, int element)
1149 DrawLevelElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1152 void DrawLevelFieldThruMask(int x, int y)
1154 DrawLevelElementExt(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
1157 static void DrawLevelFieldCrumbledSandExt(int x, int y, int graphic, int frame)
1161 int sx = SCREENX(x), sy = SCREENY(y);
1163 int width, height, cx, cy, i;
1164 int snip = TILEX / 8; /* number of border pixels from "crumbled graphic" */
1165 static int xy[4][2] =
1173 if (!IN_LEV_FIELD(x, y))
1176 element = (GfxElement[x][y] != EL_UNDEFINED ? GfxElement[x][y] : Feld[x][y]);
1178 /* crumble field itself */
1179 if (CAN_BE_CRUMBLED(element))
1181 if (!IN_SCR_FIELD(sx, sy))
1184 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1188 int xx = x + xy[i][0];
1189 int yy = y + xy[i][1];
1191 element = (IN_LEV_FIELD(xx, yy) ? Feld[xx][yy] : EL_STEELWALL);
1193 if (CAN_BE_CRUMBLED(element)) /* neighbour is of same type */
1196 if (i == 1 || i == 2)
1200 cx = (i == 2 ? TILEX - snip : 0);
1208 cy = (i == 3 ? TILEY - snip : 0);
1211 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1212 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
1215 MarkTileDirty(sx, sy);
1217 else /* crumble neighbour fields */
1219 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1223 int xx = x + xy[i][0];
1224 int yy = y + xy[i][1];
1225 int sxx = sx + xy[i][0];
1226 int syy = sy + xy[i][1];
1228 if (!IN_LEV_FIELD(xx, yy) ||
1229 !IN_SCR_FIELD(sxx, syy) ||
1230 !CAN_BE_CRUMBLED(Feld[xx][yy]))
1233 if (i == 1 || i == 2)
1237 cx = (i == 1 ? TILEX - snip : 0);
1245 cy = (i==0 ? TILEY-snip : 0);
1248 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1249 width, height, FX + sxx * TILEX + cx, FY + syy * TILEY + cy);
1251 MarkTileDirty(sxx, syy);
1256 void DrawLevelFieldCrumbledSand(int x, int y)
1258 DrawLevelFieldCrumbledSandExt(x, y, IMG_SAND_CRUMBLED, 0);
1261 void DrawLevelFieldCrumbledSandDigging(int x, int y, int direction,
1264 int graphic1 = el_act_dir2img(EL_SAND, ACTION_DIGGING, direction);
1265 int graphic2 = el_act_dir2img(EL_SAND_CRUMBLED, ACTION_DIGGING, direction);
1266 int frame1 = getGraphicAnimationFrame(graphic1, step_frame);
1267 int frame2 = getGraphicAnimationFrame(graphic2, step_frame);
1268 int sx = SCREENX(x), sy = SCREENY(y);
1270 DrawGraphic(sx, sy, graphic1, frame1);
1271 DrawLevelFieldCrumbledSandExt(x, y, graphic2, frame2);
1274 static int getBorderElement(int x, int y)
1278 { EL_STEELWALL_TOPLEFT, EL_INVISIBLE_STEELWALL_TOPLEFT },
1279 { EL_STEELWALL_TOPRIGHT, EL_INVISIBLE_STEELWALL_TOPRIGHT },
1280 { EL_STEELWALL_BOTTOMLEFT, EL_INVISIBLE_STEELWALL_BOTTOMLEFT },
1281 { EL_STEELWALL_BOTTOMRIGHT, EL_INVISIBLE_STEELWALL_BOTTOMRIGHT },
1282 { EL_STEELWALL_VERTICAL, EL_INVISIBLE_STEELWALL_VERTICAL },
1283 { EL_STEELWALL_HORIZONTAL, EL_INVISIBLE_STEELWALL_HORIZONTAL },
1284 { EL_STEELWALL, EL_INVISIBLE_STEELWALL }
1286 int steel_type = (BorderElement == EL_STEELWALL ? 0 : 1);
1287 int steel_position = (x == -1 && y == -1 ? 0 :
1288 x == lev_fieldx && y == -1 ? 1 :
1289 x == -1 && y == lev_fieldy ? 2 :
1290 x == lev_fieldx && y == lev_fieldy ? 3 :
1291 x == -1 || x == lev_fieldx ? 4 :
1292 y == -1 || y == lev_fieldy ? 5 : 6);
1294 return border[steel_position][steel_type];
1297 void DrawScreenElement(int x, int y, int element)
1299 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
1300 DrawLevelFieldCrumbledSand(LEVELX(x), LEVELY(y));
1303 void DrawLevelElement(int x, int y, int element)
1305 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1306 DrawScreenElement(SCREENX(x), SCREENY(y), element);
1309 void DrawScreenField(int x, int y)
1311 int lx = LEVELX(x), ly = LEVELY(y);
1312 int element, content;
1314 if (!IN_LEV_FIELD(lx, ly))
1316 if (lx < -1 || lx > lev_fieldx || ly < -1 || ly > lev_fieldy)
1319 element = getBorderElement(lx, ly);
1321 DrawScreenElement(x, y, element);
1325 element = Feld[lx][ly];
1326 content = Store[lx][ly];
1328 if (IS_MOVING(lx, ly))
1330 int horiz_move = (MovDir[lx][ly] == MV_LEFT || MovDir[lx][ly] == MV_RIGHT);
1331 boolean cut_mode = NO_CUTTING;
1333 if (element == EL_QUICKSAND_EMPTYING ||
1334 element == EL_MAGIC_WALL_EMPTYING ||
1335 element == EL_BD_MAGIC_WALL_EMPTYING ||
1336 element == EL_AMOEBA_DROPPING)
1337 cut_mode = CUT_ABOVE;
1338 else if (element == EL_QUICKSAND_FILLING ||
1339 element == EL_MAGIC_WALL_FILLING ||
1340 element == EL_BD_MAGIC_WALL_FILLING)
1341 cut_mode = CUT_BELOW;
1343 if (cut_mode == CUT_ABOVE)
1344 DrawScreenElementShifted(x, y, 0, 0, element, NO_CUTTING);
1346 DrawScreenElement(x, y, EL_EMPTY);
1349 DrawScreenElementShifted(x, y, MovPos[lx][ly], 0, element, NO_CUTTING);
1350 else if (cut_mode == NO_CUTTING)
1351 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], element, cut_mode);
1353 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], content, cut_mode);
1355 if (content == EL_ACID)
1356 DrawLevelElementThruMask(lx, ly + 1, EL_ACID);
1358 else if (IS_BLOCKED(lx, ly))
1363 boolean cut_mode = NO_CUTTING;
1364 int element_old, content_old;
1366 Blocked2Moving(lx, ly, &oldx, &oldy);
1369 horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
1370 MovDir[oldx][oldy] == MV_RIGHT);
1372 element_old = Feld[oldx][oldy];
1373 content_old = Store[oldx][oldy];
1375 if (element_old == EL_QUICKSAND_EMPTYING ||
1376 element_old == EL_MAGIC_WALL_EMPTYING ||
1377 element_old == EL_BD_MAGIC_WALL_EMPTYING ||
1378 element_old == EL_AMOEBA_DROPPING)
1379 cut_mode = CUT_ABOVE;
1381 DrawScreenElement(x, y, EL_EMPTY);
1384 DrawScreenElementShifted(sx, sy, MovPos[oldx][oldy], 0, element_old,
1386 else if (cut_mode == NO_CUTTING)
1387 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], element_old,
1390 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], content_old,
1393 else if (IS_DRAWABLE(element))
1394 DrawScreenElement(x, y, element);
1396 DrawScreenElement(x, y, EL_EMPTY);
1399 void DrawLevelField(int x, int y)
1401 if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1402 DrawScreenField(SCREENX(x), SCREENY(y));
1403 else if (IS_MOVING(x, y))
1407 Moving2Blocked(x, y, &newx, &newy);
1408 if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
1409 DrawScreenField(SCREENX(newx), SCREENY(newy));
1411 else if (IS_BLOCKED(x, y))
1415 Blocked2Moving(x, y, &oldx, &oldy);
1416 if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
1417 DrawScreenField(SCREENX(oldx), SCREENY(oldy));
1421 void DrawMiniElement(int x, int y, int element)
1425 graphic = el2edimg(element);
1426 DrawMiniGraphic(x, y, graphic);
1429 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
1431 int x = sx + scroll_x, y = sy + scroll_y;
1433 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
1434 DrawMiniElement(sx, sy, EL_EMPTY);
1435 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
1436 DrawMiniElement(sx, sy, Feld[x][y]);
1438 DrawMiniGraphic(sx, sy, el2edimg(getBorderElement(x, y)));
1441 void getMicroGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
1443 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
1444 int mini_startx = src_bitmap->width * 3 / 4;
1445 int mini_starty = src_bitmap->height * 2 / 3;
1446 int src_x = mini_startx + graphic_info[graphic].src_x / 8;
1447 int src_y = mini_starty + graphic_info[graphic].src_y / 8;
1449 if (src_x + MICRO_TILEX > src_bitmap->width ||
1450 src_y + MICRO_TILEY > src_bitmap->height)
1452 /* graphic of desired size seems not to be contained in this image;
1453 dirty workaround: get it from the middle of the normal sized image */
1455 getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
1456 src_x += (TILEX / 2 - MICRO_TILEX / 2);
1457 src_y += (TILEY / 2 - MICRO_TILEY / 2);
1460 *bitmap = src_bitmap;
1465 void DrawMicroElement(int xpos, int ypos, int element)
1469 int graphic = el2preimg(element);
1471 getMicroGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
1472 BlitBitmap(src_bitmap, drawto, src_x, src_y, MICRO_TILEX, MICRO_TILEY,
1480 SetDrawBackgroundMask(REDRAW_NONE);
1483 for(x=BX1; x<=BX2; x++)
1484 for(y=BY1; y<=BY2; y++)
1485 DrawScreenField(x, y);
1487 redraw_mask |= REDRAW_FIELD;
1490 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
1494 for(x=0; x<size_x; x++)
1495 for(y=0; y<size_y; y++)
1496 DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
1498 redraw_mask |= REDRAW_FIELD;
1501 static void DrawMicroLevelExt(int xpos, int ypos, int from_x, int from_y)
1505 DrawBackground(xpos, ypos, MICROLEV_XSIZE, MICROLEV_YSIZE);
1507 if (lev_fieldx < STD_LEV_FIELDX)
1508 xpos += (STD_LEV_FIELDX - lev_fieldx) / 2 * MICRO_TILEX;
1509 if (lev_fieldy < STD_LEV_FIELDY)
1510 ypos += (STD_LEV_FIELDY - lev_fieldy) / 2 * MICRO_TILEY;
1512 xpos += MICRO_TILEX;
1513 ypos += MICRO_TILEY;
1515 for(x=-1; x<=STD_LEV_FIELDX; x++)
1517 for(y=-1; y<=STD_LEV_FIELDY; y++)
1519 int lx = from_x + x, ly = from_y + y;
1521 if (lx >= 0 && lx < lev_fieldx && ly >= 0 && ly < lev_fieldy)
1522 DrawMicroElement(xpos + x * MICRO_TILEX, ypos + y * MICRO_TILEY,
1524 else if (lx >= -1 && lx < lev_fieldx+1 && ly >= -1 && ly < lev_fieldy+1
1525 && BorderElement != EL_EMPTY)
1526 DrawMicroElement(xpos + x * MICRO_TILEX, ypos + y * MICRO_TILEY,
1527 getBorderElement(lx, ly));
1531 redraw_mask |= REDRAW_MICROLEVEL;
1534 #define MICROLABEL_EMPTY 0
1535 #define MICROLABEL_LEVEL_NAME 1
1536 #define MICROLABEL_CREATED_BY 2
1537 #define MICROLABEL_LEVEL_AUTHOR 3
1538 #define MICROLABEL_IMPORTED_FROM 4
1539 #define MICROLABEL_LEVEL_IMPORT_INFO 5
1541 static void DrawMicroLevelLabelExt(int mode)
1543 char label_text[MAX_OUTPUT_LINESIZE + 1];
1544 int max_len_label_text;
1545 int font_nr = FONT_TEXT_2;
1547 if (mode == MICROLABEL_CREATED_BY || mode == MICROLABEL_IMPORTED_FROM)
1548 font_nr = FONT_TEXT_3;
1550 max_len_label_text = SXSIZE / getFontWidth(font_nr);
1552 DrawBackground(SX, MICROLABEL_YPOS, SXSIZE, getFontHeight(font_nr));
1554 strncpy(label_text, (mode == MICROLABEL_LEVEL_NAME ? level.name :
1555 mode == MICROLABEL_CREATED_BY ? "created by" :
1556 mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
1557 mode == MICROLABEL_IMPORTED_FROM ? "imported from" :
1558 mode == MICROLABEL_LEVEL_IMPORT_INFO ?
1559 leveldir_current->imported_from : ""),
1560 max_len_label_text);
1561 label_text[max_len_label_text] = '\0';
1563 if (strlen(label_text) > 0)
1565 int text_width = strlen(label_text) * getFontWidth(font_nr);
1566 int lxpos = SX + (SXSIZE - text_width) / 2;
1567 int lypos = MICROLABEL_YPOS;
1569 DrawText(lxpos, lypos, label_text, font_nr);
1572 redraw_mask |= REDRAW_MICROLEVEL;
1575 void DrawMicroLevel(int xpos, int ypos, boolean restart)
1577 static unsigned long scroll_delay = 0;
1578 static unsigned long label_delay = 0;
1579 static int from_x, from_y, scroll_direction;
1580 static int label_state, label_counter;
1581 int last_game_status = game_status; /* save current game status */
1583 game_status = PSEUDO_PREVIEW; /* force PREVIEW font on preview level */
1587 from_x = from_y = 0;
1588 scroll_direction = MV_RIGHT;
1592 DrawMicroLevelExt(xpos, ypos, from_x, from_y);
1593 DrawMicroLevelLabelExt(label_state);
1595 /* initialize delay counters */
1596 DelayReached(&scroll_delay, 0);
1597 DelayReached(&label_delay, 0);
1599 if (leveldir_current->name)
1601 int len = strlen(leveldir_current->name);
1602 int lxpos = SX + (SXSIZE - len * getFontWidth(FONT_TEXT_1)) / 2;
1603 int lypos = SY + 352;
1605 DrawText(lxpos, lypos, leveldir_current->name, FONT_TEXT_1);
1608 game_status = last_game_status; /* restore current game status */
1613 /* scroll micro level, if needed */
1614 if ((lev_fieldx > STD_LEV_FIELDX || lev_fieldy > STD_LEV_FIELDY) &&
1615 DelayReached(&scroll_delay, MICROLEVEL_SCROLL_DELAY))
1617 switch (scroll_direction)
1623 scroll_direction = MV_UP;
1627 if (from_x < lev_fieldx - STD_LEV_FIELDX)
1630 scroll_direction = MV_DOWN;
1637 scroll_direction = MV_RIGHT;
1641 if (from_y < lev_fieldy - STD_LEV_FIELDY)
1644 scroll_direction = MV_LEFT;
1651 DrawMicroLevelExt(xpos, ypos, from_x, from_y);
1654 /* redraw micro level label, if needed */
1655 if (strcmp(level.name, NAMELESS_LEVEL_NAME) != 0 &&
1656 strcmp(level.author, ANONYMOUS_NAME) != 0 &&
1657 strcmp(level.author, leveldir_current->name) != 0 &&
1658 DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
1660 int max_label_counter = 23;
1662 if (leveldir_current->imported_from != NULL)
1663 max_label_counter += 14;
1665 label_counter = (label_counter + 1) % max_label_counter;
1666 label_state = (label_counter >= 0 && label_counter <= 7 ?
1667 MICROLABEL_LEVEL_NAME :
1668 label_counter >= 9 && label_counter <= 12 ?
1669 MICROLABEL_CREATED_BY :
1670 label_counter >= 14 && label_counter <= 21 ?
1671 MICROLABEL_LEVEL_AUTHOR :
1672 label_counter >= 23 && label_counter <= 26 ?
1673 MICROLABEL_IMPORTED_FROM :
1674 label_counter >= 28 && label_counter <= 35 ?
1675 MICROLABEL_LEVEL_IMPORT_INFO : MICROLABEL_EMPTY);
1676 DrawMicroLevelLabelExt(label_state);
1679 game_status = last_game_status; /* restore current game status */
1682 int REQ_in_range(int x, int y)
1684 if (y > DY+249 && y < DY+278)
1686 if (x > DX+1 && x < DX+48)
1688 else if (x > DX+51 && x < DX+98)
1694 #define MAX_REQUEST_LINES 13
1695 #define MAX_REQUEST_LINE_LEN 7
1697 boolean Request(char *text, unsigned int req_state)
1699 int mx, my, ty, result = -1;
1700 unsigned int old_door_state;
1701 int last_game_status = game_status; /* save current game status */
1703 #if defined(PLATFORM_UNIX)
1704 /* pause network game while waiting for request to answer */
1705 if (options.network &&
1706 game_status == PLAYING &&
1707 req_state & REQUEST_WAIT_FOR)
1708 SendToServer_PausePlaying();
1711 old_door_state = GetDoorState();
1715 CloseDoor(DOOR_CLOSE_1);
1717 /* save old door content */
1718 BlitBitmap(bitmap_db_door, bitmap_db_door,
1719 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
1720 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
1722 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
1724 /* clear door drawing field */
1725 DrawBackground(DX, DY, DXSIZE, DYSIZE);
1727 game_status = PSEUDO_DOOR; /* force DOOR font on preview level */
1729 /* write text for request */
1730 for(ty=0; ty < MAX_REQUEST_LINES; ty++)
1732 char text_line[MAX_REQUEST_LINE_LEN + 1];
1738 for(tl=0,tx=0; tx < MAX_REQUEST_LINE_LEN; tl++,tx++)
1741 if (!tc || tc == ' ')
1752 strncpy(text_line, text, tl);
1755 DrawText(DX + (DXSIZE - tl * getFontWidth(FONT_TEXT_2)) / 2,
1756 DY + 8 + ty * (getFontHeight(FONT_TEXT_2) + 2),
1757 text_line, FONT_TEXT_2);
1759 text += tl + (tc == ' ' ? 1 : 0);
1762 game_status = last_game_status; /* restore current game status */
1764 if (req_state & REQ_ASK)
1766 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
1767 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
1769 else if (req_state & REQ_CONFIRM)
1771 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
1773 else if (req_state & REQ_PLAYER)
1775 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
1776 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
1777 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
1778 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
1781 /* copy request gadgets to door backbuffer */
1782 BlitBitmap(drawto, bitmap_db_door,
1783 DX, DY, DXSIZE, DYSIZE,
1784 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
1786 OpenDoor(DOOR_OPEN_1);
1792 if (!(req_state & REQUEST_WAIT_FOR))
1794 SetDrawBackgroundMask(REDRAW_FIELD);
1799 if (game_status != MAINMENU)
1802 button_status = MB_RELEASED;
1804 request_gadget_id = -1;
1806 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
1818 case EVENT_BUTTONPRESS:
1819 case EVENT_BUTTONRELEASE:
1820 case EVENT_MOTIONNOTIFY:
1822 if (event.type == EVENT_MOTIONNOTIFY)
1824 if (!PointerInWindow(window))
1825 continue; /* window and pointer are on different screens */
1830 motion_status = TRUE;
1831 mx = ((MotionEvent *) &event)->x;
1832 my = ((MotionEvent *) &event)->y;
1836 motion_status = FALSE;
1837 mx = ((ButtonEvent *) &event)->x;
1838 my = ((ButtonEvent *) &event)->y;
1839 if (event.type == EVENT_BUTTONPRESS)
1840 button_status = ((ButtonEvent *) &event)->button;
1842 button_status = MB_RELEASED;
1845 /* this sets 'request_gadget_id' */
1846 HandleGadgets(mx, my, button_status);
1848 switch(request_gadget_id)
1850 case TOOL_CTRL_ID_YES:
1853 case TOOL_CTRL_ID_NO:
1856 case TOOL_CTRL_ID_CONFIRM:
1857 result = TRUE | FALSE;
1860 case TOOL_CTRL_ID_PLAYER_1:
1863 case TOOL_CTRL_ID_PLAYER_2:
1866 case TOOL_CTRL_ID_PLAYER_3:
1869 case TOOL_CTRL_ID_PLAYER_4:
1880 case EVENT_KEYPRESS:
1881 switch(GetEventKey((KeyEvent *)&event, TRUE))
1894 if (req_state & REQ_PLAYER)
1898 case EVENT_KEYRELEASE:
1899 ClearPlayerAction();
1903 HandleOtherEvents(&event);
1907 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
1909 int joy = AnyJoystick();
1911 if (joy & JOY_BUTTON_1)
1913 else if (joy & JOY_BUTTON_2)
1919 /* don't eat all CPU time */
1923 if (game_status != MAINMENU)
1928 if (!(req_state & REQ_STAY_OPEN))
1930 CloseDoor(DOOR_CLOSE_1);
1932 if (!(req_state & REQ_STAY_CLOSED) && (old_door_state & DOOR_OPEN_1))
1934 BlitBitmap(bitmap_db_door, bitmap_db_door,
1935 DOOR_GFX_PAGEX2,DOOR_GFX_PAGEY1, DXSIZE,DYSIZE,
1936 DOOR_GFX_PAGEX1,DOOR_GFX_PAGEY1);
1937 OpenDoor(DOOR_OPEN_1);
1943 SetDrawBackgroundMask(REDRAW_FIELD);
1945 #if defined(PLATFORM_UNIX)
1946 /* continue network game after request */
1947 if (options.network &&
1948 game_status == PLAYING &&
1949 req_state & REQUEST_WAIT_FOR)
1950 SendToServer_ContinuePlaying();
1956 unsigned int OpenDoor(unsigned int door_state)
1958 unsigned int new_door_state;
1960 if (door_state & DOOR_COPY_BACK)
1962 BlitBitmap(bitmap_db_door, bitmap_db_door,
1963 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE + VYSIZE,
1964 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
1965 door_state &= ~DOOR_COPY_BACK;
1968 new_door_state = MoveDoor(door_state);
1970 return(new_door_state);
1973 unsigned int CloseDoor(unsigned int door_state)
1975 unsigned int new_door_state;
1977 BlitBitmap(backbuffer, bitmap_db_door,
1978 DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
1979 BlitBitmap(backbuffer, bitmap_db_door,
1980 VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
1982 new_door_state = MoveDoor(door_state);
1984 return(new_door_state);
1987 unsigned int GetDoorState()
1989 return MoveDoor(DOOR_GET_STATE);
1992 unsigned int SetDoorState(unsigned int door_state)
1994 return MoveDoor(door_state | DOOR_SET_STATE);
1997 unsigned int MoveDoor(unsigned int door_state)
1999 static int door1 = DOOR_OPEN_1;
2000 static int door2 = DOOR_CLOSE_2;
2001 static unsigned long door_delay = 0;
2002 int x, start, stepsize = global.door_step_offset;
2003 unsigned long door_delay_value = global.door_step_delay;
2005 if (door_state == DOOR_GET_STATE)
2006 return(door1 | door2);
2008 if (door_state & DOOR_SET_STATE)
2010 if (door_state & DOOR_ACTION_1)
2011 door1 = door_state & DOOR_ACTION_1;
2012 if (door_state & DOOR_ACTION_2)
2013 door2 = door_state & DOOR_ACTION_2;
2015 return(door1 | door2);
2018 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
2019 door_state &= ~DOOR_OPEN_1;
2020 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
2021 door_state &= ~DOOR_CLOSE_1;
2022 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
2023 door_state &= ~DOOR_OPEN_2;
2024 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
2025 door_state &= ~DOOR_CLOSE_2;
2027 if (setup.quick_doors)
2030 door_delay_value = 0;
2032 StopSound(SND_DOOR_OPENING);
2033 StopSound(SND_DOOR_CLOSING);
2036 if (global.autoplay_leveldir)
2038 door_state |= DOOR_NO_DELAY;
2039 door_state &= ~DOOR_CLOSE_ALL;
2042 if (door_state & DOOR_ACTION)
2044 if (!(door_state & DOOR_NO_DELAY))
2046 /* opening door sound has priority over simultaneously closing door */
2047 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
2048 PlaySoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
2049 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
2050 PlaySoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
2053 start = ((door_state & DOOR_NO_DELAY) ? DXSIZE : 0);
2055 for(x=start; x<=DXSIZE; x+=stepsize)
2057 Bitmap *bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
2058 GC gc = bitmap->stored_clip_gc;
2060 if (!(door_state & DOOR_NO_DELAY))
2061 WaitUntilDelayReached(&door_delay, door_delay_value);
2063 if (door_state & DOOR_ACTION_1)
2065 int i = (door_state & DOOR_OPEN_1 ? DXSIZE-x : x);
2066 int j = (DXSIZE - i) / 3;
2068 BlitBitmap(bitmap_db_door, drawto,
2069 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + i/2,
2070 DXSIZE,DYSIZE - i/2, DX, DY);
2072 ClearRectangle(drawto, DX, DY + DYSIZE - i/2, DXSIZE,i/2);
2074 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2075 BlitBitmapMasked(bitmap, drawto,
2076 DXSIZE, DOOR_GFX_PAGEY1, i, 77,
2077 DX + DXSIZE - i, DY + j);
2078 BlitBitmapMasked(bitmap, drawto,
2079 DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63,
2080 DX + DXSIZE - i, DY + 140 + j);
2081 SetClipOrigin(bitmap, gc, DX - DXSIZE + i, DY - (DOOR_GFX_PAGEY1 + j));
2082 BlitBitmapMasked(bitmap, drawto,
2083 DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j,
2085 BlitBitmapMasked(bitmap, drawto,
2086 DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63,
2089 BlitBitmapMasked(bitmap, drawto,
2090 DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
2092 BlitBitmapMasked(bitmap, drawto,
2093 DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
2095 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2096 BlitBitmapMasked(bitmap, drawto,
2097 DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
2098 DX + DXSIZE - i, DY + 77 + j);
2099 BlitBitmapMasked(bitmap, drawto,
2100 DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
2101 DX + DXSIZE - i, DY + 203 + j);
2103 redraw_mask |= REDRAW_DOOR_1;
2106 if (door_state & DOOR_ACTION_2)
2108 int i = (door_state & DOOR_OPEN_2 ? VXSIZE - x : x);
2109 int j = (VXSIZE - i) / 3;
2111 BlitBitmap(bitmap_db_door, drawto,
2112 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + i/2,
2113 VXSIZE, VYSIZE - i/2, VX, VY);
2115 ClearRectangle(drawto, VX, VY + VYSIZE-i/2, VXSIZE, i/2);
2117 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2118 BlitBitmapMasked(bitmap, drawto,
2119 VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2,
2120 VX + VXSIZE-i, VY+j);
2121 SetClipOrigin(bitmap, gc,
2122 VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
2123 BlitBitmapMasked(bitmap, drawto,
2124 VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j,
2127 BlitBitmapMasked(bitmap, drawto,
2128 VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2,
2129 i, VYSIZE / 2, VX, VY + VYSIZE / 2 - j);
2130 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2131 BlitBitmapMasked(bitmap, drawto,
2132 VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2,
2134 VX + VXSIZE - i, VY + VYSIZE / 2 + j);
2136 redraw_mask |= REDRAW_DOOR_2;
2141 if (game_status == MAINMENU)
2146 if (setup.quick_doors)
2148 StopSound(SND_DOOR_OPENING);
2149 StopSound(SND_DOOR_CLOSING);
2152 if (door_state & DOOR_ACTION_1)
2153 door1 = door_state & DOOR_ACTION_1;
2154 if (door_state & DOOR_ACTION_2)
2155 door2 = door_state & DOOR_ACTION_2;
2157 return (door1 | door2);
2160 void DrawSpecialEditorDoor()
2162 /* draw bigger toolbox window */
2163 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
2164 DOOR_GFX_PAGEX7, 0, EXSIZE + 8, 8,
2166 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
2167 EX - 4, VY - 4, EXSIZE + 8, EYSIZE - VYSIZE + 4,
2170 redraw_mask |= REDRAW_ALL;
2173 void UndrawSpecialEditorDoor()
2175 /* draw normal tape recorder window */
2176 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
2177 EX - 4, EY - 12, EXSIZE + 8, EYSIZE - VYSIZE + 12,
2180 redraw_mask |= REDRAW_ALL;
2184 /* ---------- new tool button stuff ---------------------------------------- */
2186 /* graphic position values for tool buttons */
2187 #define TOOL_BUTTON_YES_XPOS 2
2188 #define TOOL_BUTTON_YES_YPOS 250
2189 #define TOOL_BUTTON_YES_GFX_YPOS 0
2190 #define TOOL_BUTTON_YES_XSIZE 46
2191 #define TOOL_BUTTON_YES_YSIZE 28
2192 #define TOOL_BUTTON_NO_XPOS 52
2193 #define TOOL_BUTTON_NO_YPOS TOOL_BUTTON_YES_YPOS
2194 #define TOOL_BUTTON_NO_GFX_YPOS TOOL_BUTTON_YES_GFX_YPOS
2195 #define TOOL_BUTTON_NO_XSIZE TOOL_BUTTON_YES_XSIZE
2196 #define TOOL_BUTTON_NO_YSIZE TOOL_BUTTON_YES_YSIZE
2197 #define TOOL_BUTTON_CONFIRM_XPOS TOOL_BUTTON_YES_XPOS
2198 #define TOOL_BUTTON_CONFIRM_YPOS TOOL_BUTTON_YES_YPOS
2199 #define TOOL_BUTTON_CONFIRM_GFX_YPOS 30
2200 #define TOOL_BUTTON_CONFIRM_XSIZE 96
2201 #define TOOL_BUTTON_CONFIRM_YSIZE TOOL_BUTTON_YES_YSIZE
2202 #define TOOL_BUTTON_PLAYER_XSIZE 30
2203 #define TOOL_BUTTON_PLAYER_YSIZE 30
2204 #define TOOL_BUTTON_PLAYER_GFX_XPOS 5
2205 #define TOOL_BUTTON_PLAYER_GFX_YPOS 185
2206 #define TOOL_BUTTON_PLAYER_XPOS (5 + TOOL_BUTTON_PLAYER_XSIZE / 2)
2207 #define TOOL_BUTTON_PLAYER_YPOS (215 - TOOL_BUTTON_PLAYER_YSIZE / 2)
2208 #define TOOL_BUTTON_PLAYER1_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2209 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2210 #define TOOL_BUTTON_PLAYER2_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2211 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2212 #define TOOL_BUTTON_PLAYER3_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2213 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2214 #define TOOL_BUTTON_PLAYER4_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2215 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2216 #define TOOL_BUTTON_PLAYER1_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2217 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2218 #define TOOL_BUTTON_PLAYER2_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2219 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2220 #define TOOL_BUTTON_PLAYER3_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2221 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2222 #define TOOL_BUTTON_PLAYER4_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2223 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2232 } toolbutton_info[NUM_TOOL_BUTTONS] =
2235 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_GFX_YPOS,
2236 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_YPOS,
2237 TOOL_BUTTON_YES_XSIZE, TOOL_BUTTON_YES_YSIZE,
2242 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_GFX_YPOS,
2243 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_YPOS,
2244 TOOL_BUTTON_NO_XSIZE, TOOL_BUTTON_NO_YSIZE,
2249 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_GFX_YPOS,
2250 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_YPOS,
2251 TOOL_BUTTON_CONFIRM_XSIZE, TOOL_BUTTON_CONFIRM_YSIZE,
2252 TOOL_CTRL_ID_CONFIRM,
2256 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2257 TOOL_BUTTON_PLAYER1_XPOS, TOOL_BUTTON_PLAYER1_YPOS,
2258 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2259 TOOL_CTRL_ID_PLAYER_1,
2263 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2264 TOOL_BUTTON_PLAYER2_XPOS, TOOL_BUTTON_PLAYER2_YPOS,
2265 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2266 TOOL_CTRL_ID_PLAYER_2,
2270 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2271 TOOL_BUTTON_PLAYER3_XPOS, TOOL_BUTTON_PLAYER3_YPOS,
2272 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2273 TOOL_CTRL_ID_PLAYER_3,
2277 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2278 TOOL_BUTTON_PLAYER4_XPOS, TOOL_BUTTON_PLAYER4_YPOS,
2279 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2280 TOOL_CTRL_ID_PLAYER_4,
2285 void CreateToolButtons()
2289 for (i=0; i<NUM_TOOL_BUTTONS; i++)
2291 Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
2292 Bitmap *deco_bitmap = None;
2293 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
2294 struct GadgetInfo *gi;
2295 unsigned long event_mask;
2296 int gd_xoffset, gd_yoffset;
2297 int gd_x1, gd_x2, gd_y;
2300 event_mask = GD_EVENT_RELEASED;
2302 gd_xoffset = toolbutton_info[i].xpos;
2303 gd_yoffset = toolbutton_info[i].ypos;
2304 gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
2305 gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
2306 gd_y = DOOR_GFX_PAGEY1 + gd_yoffset;
2308 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
2310 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
2312 getMiniGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr),
2313 &deco_bitmap, &deco_x, &deco_y);
2314 deco_xpos = (toolbutton_info[i].width - MINI_TILEX) / 2;
2315 deco_ypos = (toolbutton_info[i].height - MINI_TILEY) / 2;
2318 gi = CreateGadget(GDI_CUSTOM_ID, id,
2319 GDI_INFO_TEXT, toolbutton_info[i].infotext,
2320 GDI_X, DX + toolbutton_info[i].x,
2321 GDI_Y, DY + toolbutton_info[i].y,
2322 GDI_WIDTH, toolbutton_info[i].width,
2323 GDI_HEIGHT, toolbutton_info[i].height,
2324 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
2325 GDI_STATE, GD_BUTTON_UNPRESSED,
2326 GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
2327 GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
2328 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
2329 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
2330 GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
2331 GDI_DECORATION_SHIFTING, 1, 1,
2332 GDI_EVENT_MASK, event_mask,
2333 GDI_CALLBACK_ACTION, HandleToolButtons,
2337 Error(ERR_EXIT, "cannot create gadget");
2339 tool_gadget[id] = gi;
2343 void FreeToolButtons()
2347 for (i=0; i<NUM_TOOL_BUTTONS; i++)
2348 FreeGadget(tool_gadget[i]);
2351 static void UnmapToolButtons()
2355 for (i=0; i<NUM_TOOL_BUTTONS; i++)
2356 UnmapGadget(tool_gadget[i]);
2359 static void HandleToolButtons(struct GadgetInfo *gi)
2361 request_gadget_id = gi->custom_id;
2364 int get_next_element(int element)
2368 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
2369 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
2370 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
2371 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
2372 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
2373 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
2374 case EL_AMOEBA_DROPPING: return EL_AMOEBA_WET;
2376 default: return element;
2380 int el_act_dir2img(int element, int action, int direction)
2382 direction = MV_DIR_BIT(direction);
2384 return element_info[element].direction_graphic[action][direction];
2387 int el_act2img(int element, int action)
2389 return element_info[element].graphic[action];
2392 int el_dir2img(int element, int direction)
2394 return el_act_dir2img(element, ACTION_DEFAULT, direction);
2397 int el2img(int element)
2399 return element_info[element].graphic[ACTION_DEFAULT];
2402 int el2edimg(int element)
2404 return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
2407 int el2preimg(int element)
2409 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];