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 the player is just walking/passing through/under */
749 /* ----------------------------------------------------------------------- */
751 /* handle the field the player is leaving ... */
752 if (player_is_moving && IS_ACCESSIBLE_INSIDE(last_element))
753 DrawLevelField(last_jx, last_jy);
754 else if (player_is_moving && IS_ACCESSIBLE_UNDER(last_element))
755 DrawLevelFieldThruMask(last_jx, last_jy);
757 /* ... and the field the player is entering */
758 if (IS_ACCESSIBLE_INSIDE(element))
759 DrawLevelField(jx, jy);
760 else if (IS_ACCESSIBLE_UNDER(element))
761 DrawLevelFieldThruMask(jx, jy);
763 if (setup.direct_draw)
765 int dest_x = SX + SCREENX(MIN(jx, last_jx)) * TILEX;
766 int dest_y = SY + SCREENY(MIN(jy, last_jy)) * TILEY;
767 int x_size = TILEX * (1 + ABS(jx - last_jx));
768 int y_size = TILEY * (1 + ABS(jy - last_jy));
770 BlitBitmap(drawto_field, window,
771 dest_x, dest_y, x_size, y_size, dest_x, dest_y);
772 SetDrawtoField(DRAW_DIRECT);
775 MarkTileDirty(sx,sy);
778 void getGraphicSource(int graphic, int frame, Bitmap **bitmap, int *x, int *y)
780 struct GraphicInfo *g = &graphic_info[graphic];
784 if (g->offset_y == 0) /* frames are ordered horizontally */
786 int max_width = g->anim_frames_per_line * g->width;
788 *x = (g->src_x + frame * g->offset_x) % max_width;
789 *y = g->src_y + (g->src_x + frame * g->offset_x) / max_width * g->height;
791 else if (g->offset_x == 0) /* frames are ordered vertically */
793 int max_height = g->anim_frames_per_line * g->height;
795 *x = g->src_x + (g->src_y + frame * g->offset_y) / max_height * g->width;
796 *y = (g->src_y + frame * g->offset_y) % max_height;
798 else /* frames are ordered diagonally */
800 *x = g->src_x + frame * g->offset_x;
801 *y = g->src_y + frame * g->offset_y;
805 void DrawGraphic(int x, int y, int graphic, int frame)
808 if (!IN_SCR_FIELD(x, y))
810 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
811 printf("DrawGraphic(): This should never happen!\n");
816 DrawGraphicExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic, frame);
821 void DrawOldGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic)
826 getOldGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
827 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
831 void DrawGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
838 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
840 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
841 int src_x = graphic_info[graphic].src_x;
842 int src_y = graphic_info[graphic].src_y;
843 int offset_x = graphic_info[graphic].offset_x;
844 int offset_y = graphic_info[graphic].offset_y;
846 src_x += frame * offset_x;
847 src_y += frame * offset_y;
850 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
853 void DrawGraphicThruMask(int x, int y, int graphic, int frame)
856 if (!IN_SCR_FIELD(x, y))
858 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
859 printf("DrawGraphicThruMask(): This should never happen!\n");
864 DrawGraphicThruMaskExt(drawto_field, FX + x * TILEX, FY + y *TILEY, graphic,
869 void DrawGraphicThruMaskExt(DrawBuffer *d, int dest_x, int dest_y, int graphic,
877 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
878 drawing_gc = src_bitmap->stored_clip_gc;
880 GC drawing_gc = src_bitmap->stored_clip_gc;
881 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
882 int src_x = graphic_info[graphic].src_x;
883 int src_y = graphic_info[graphic].src_y;
884 int offset_x = graphic_info[graphic].offset_x;
885 int offset_y = graphic_info[graphic].offset_y;
887 src_x += frame * offset_x;
888 src_y += frame * offset_y;
892 SetClipOrigin(src_bitmap, drawing_gc, dest_x - src_x, dest_y - src_y);
893 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX, TILEY, dest_x, dest_y);
896 void DrawMiniGraphic(int x, int y, int graphic)
898 DrawMiniGraphicExt(drawto, SX + x * MINI_TILEX,SY + y * MINI_TILEY, graphic);
899 MarkTileDirty(x / 2, y / 2);
902 void getMiniGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
904 struct GraphicInfo *g = &graphic_info[graphic];
906 int mini_starty = g->bitmap->height * 2 / 3;
909 *x = mini_startx + g->src_x / 2;
910 *y = mini_starty + g->src_y / 2;
913 void DrawMiniGraphicExt(DrawBuffer *d, int x, int y, int graphic)
918 getMiniGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
919 BlitBitmap(src_bitmap, d, src_x, src_y, MINI_TILEX, MINI_TILEY, x, y);
922 void DrawGraphicShifted(int x,int y, int dx,int dy, int graphic, int frame,
923 int cut_mode, int mask_mode)
932 int width = TILEX, height = TILEY;
938 DrawGraphic(x, y, graphic, frame);
942 if (dx || dy) /* shifted graphic */
944 if (x < BX1) /* object enters playfield from the left */
951 else if (x > BX2) /* object enters playfield from the right */
957 else if (x==BX1 && dx < 0) /* object leaves playfield to the left */
963 else if (x==BX2 && dx > 0) /* object leaves playfield to the right */
965 else if (dx) /* general horizontal movement */
966 MarkTileDirty(x + SIGN(dx), y);
968 if (y < BY1) /* object enters playfield from the top */
970 if (cut_mode==CUT_BELOW) /* object completely above top border */
978 else if (y > BY2) /* object enters playfield from the bottom */
984 else if (y==BY1 && dy < 0) /* object leaves playfield to the top */
990 else if (dy > 0 && cut_mode == CUT_ABOVE)
992 if (y == BY2) /* object completely above bottom border */
998 MarkTileDirty(x, y + 1);
999 } /* object leaves playfield to the bottom */
1000 else if (dy > 0 && (y == BY2 || cut_mode == CUT_BELOW))
1002 else if (dy) /* general vertical movement */
1003 MarkTileDirty(x, y + SIGN(dy));
1006 src_bitmap = graphic_info[graphic].bitmap;
1007 src_x = graphic_info[graphic].src_x;
1008 src_y = graphic_info[graphic].src_y;
1009 offset_x = graphic_info[graphic].offset_x;
1010 offset_y = graphic_info[graphic].offset_y;
1012 drawing_gc = src_bitmap->stored_clip_gc;
1014 src_x += frame * offset_x;
1015 src_y += frame * offset_y;
1020 dest_x = FX + x * TILEX + dx;
1021 dest_y = FY + y * TILEY + dy;
1024 if (!IN_SCR_FIELD(x,y))
1026 printf("DrawGraphicShifted(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
1027 printf("DrawGraphicShifted(): This should never happen!\n");
1032 if (mask_mode == USE_MASKING)
1034 SetClipOrigin(src_bitmap, drawing_gc, dest_x - src_x, dest_y - src_y);
1035 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1039 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1045 void DrawGraphicShiftedThruMask(int x, int y, int dx, int dy, int graphic,
1046 int frame, int cut_mode)
1048 DrawGraphicShifted(x,y, dx,dy, graphic, frame, cut_mode, USE_MASKING);
1051 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
1052 int cut_mode, int mask_mode)
1054 int lx = LEVELX(x), ly = LEVELY(y);
1058 if (IN_LEV_FIELD(lx, ly))
1060 SetRandomAnimationValue(lx, ly);
1062 graphic = el_act_dir2img(element, GfxAction[lx][ly], MovDir[lx][ly]);
1063 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1065 else /* border element */
1067 graphic = el2img(element);
1068 frame = getGraphicAnimationFrame(graphic, -1);
1071 if (element == EL_EXPANDABLE_WALL)
1073 boolean left_stopped = FALSE, right_stopped = FALSE;
1075 if (!IN_LEV_FIELD(lx - 1, ly) || IS_MAUER(Feld[lx - 1][ly]))
1076 left_stopped = TRUE;
1077 if (!IN_LEV_FIELD(lx + 1, ly) || IS_MAUER(Feld[lx + 1][ly]))
1078 right_stopped = TRUE;
1080 if (left_stopped && right_stopped)
1082 else if (left_stopped)
1084 graphic = IMG_EXPANDABLE_WALL_GROWING_RIGHT;
1085 frame = graphic_info[graphic].anim_frames - 1;
1087 else if (right_stopped)
1089 graphic = IMG_EXPANDABLE_WALL_GROWING_LEFT;
1090 frame = graphic_info[graphic].anim_frames - 1;
1094 else if (IS_AMOEBOID(element) || element == EL_AMOEBA_DROPPING)
1096 graphic = (element == EL_BD_AMOEBA ? IMG_BD_AMOEBA_PART1 :
1097 element == EL_AMOEBA_WET ? IMG_AMOEBA_WET_PART1 :
1098 element == EL_AMOEBA_DRY ? IMG_AMOEBA_DRY_PART1 :
1099 element == EL_AMOEBA_FULL ? IMG_AMOEBA_FULL_PART1 :
1100 IMG_AMOEBA_DEAD_PART1);
1102 graphic += (x + 2 * y + 4) % 4;
1107 if (IS_AMOEBOID(element) || element == EL_AMOEBA_DROPPING)
1109 if (Feld[lx][ly] == EL_AMOEBA_DROPPING)
1110 printf("---> %d -> %d / %d [%d]\n",
1111 element, graphic, frame, GfxRandom[lx][ly]);
1116 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, mask_mode);
1117 else if (mask_mode == USE_MASKING)
1118 DrawGraphicThruMask(x, y, graphic, frame);
1120 DrawGraphic(x, y, graphic, frame);
1123 void DrawLevelElementExt(int x, int y, int dx, int dy, int element,
1124 int cut_mode, int mask_mode)
1126 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1127 DrawScreenElementExt(SCREENX(x), SCREENY(y), dx, dy, element,
1128 cut_mode, mask_mode);
1131 void DrawScreenElementShifted(int x, int y, int dx, int dy, int element,
1134 DrawScreenElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1137 void DrawLevelElementShifted(int x, int y, int dx, int dy, int element,
1140 DrawLevelElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1144 void DrawOldScreenElementThruMask(int x, int y, int element)
1146 DrawOldScreenElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1149 void DrawScreenElementThruMask(int x, int y, int element)
1151 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1155 void DrawLevelElementThruMask(int x, int y, int element)
1157 DrawLevelElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1160 void DrawLevelFieldThruMask(int x, int y)
1162 DrawLevelElementExt(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
1165 static void DrawLevelFieldCrumbledSandExt(int x, int y, int graphic, int frame)
1169 int sx = SCREENX(x), sy = SCREENY(y);
1171 int width, height, cx, cy, i;
1172 int snip = TILEX / 8; /* number of border pixels from "crumbled graphic" */
1173 static int xy[4][2] =
1181 if (!IN_LEV_FIELD(x, y))
1184 element = (GfxElement[x][y] != EL_UNDEFINED ? GfxElement[x][y] : Feld[x][y]);
1186 /* crumble field itself */
1187 if (CAN_BE_CRUMBLED(element))
1189 if (!IN_SCR_FIELD(sx, sy))
1192 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1196 int xx = x + xy[i][0];
1197 int yy = y + xy[i][1];
1199 element = (IN_LEV_FIELD(xx, yy) ? Feld[xx][yy] : EL_STEELWALL);
1201 if (CAN_BE_CRUMBLED(element)) /* neighbour is of same type */
1204 if (i == 1 || i == 2)
1208 cx = (i == 2 ? TILEX - snip : 0);
1216 cy = (i == 3 ? TILEY - snip : 0);
1219 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1220 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
1223 MarkTileDirty(sx, sy);
1225 else /* crumble neighbour fields */
1227 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1231 int xx = x + xy[i][0];
1232 int yy = y + xy[i][1];
1233 int sxx = sx + xy[i][0];
1234 int syy = sy + xy[i][1];
1236 if (!IN_LEV_FIELD(xx, yy) ||
1237 !IN_SCR_FIELD(sxx, syy) ||
1238 !CAN_BE_CRUMBLED(Feld[xx][yy]))
1241 if (i == 1 || i == 2)
1245 cx = (i == 1 ? TILEX - snip : 0);
1253 cy = (i==0 ? TILEY-snip : 0);
1256 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1257 width, height, FX + sxx * TILEX + cx, FY + syy * TILEY + cy);
1259 MarkTileDirty(sxx, syy);
1264 void DrawLevelFieldCrumbledSand(int x, int y)
1266 DrawLevelFieldCrumbledSandExt(x, y, IMG_SAND_CRUMBLED, 0);
1269 void DrawLevelFieldCrumbledSandDigging(int x, int y, int direction,
1272 int graphic1 = el_act_dir2img(EL_SAND, ACTION_DIGGING, direction);
1273 int graphic2 = el_act_dir2img(EL_SAND_CRUMBLED, ACTION_DIGGING, direction);
1274 int frame1 = getGraphicAnimationFrame(graphic1, step_frame);
1275 int frame2 = getGraphicAnimationFrame(graphic2, step_frame);
1276 int sx = SCREENX(x), sy = SCREENY(y);
1278 DrawGraphic(sx, sy, graphic1, frame1);
1279 DrawLevelFieldCrumbledSandExt(x, y, graphic2, frame2);
1282 static int getBorderElement(int x, int y)
1286 { EL_STEELWALL_TOPLEFT, EL_INVISIBLE_STEELWALL_TOPLEFT },
1287 { EL_STEELWALL_TOPRIGHT, EL_INVISIBLE_STEELWALL_TOPRIGHT },
1288 { EL_STEELWALL_BOTTOMLEFT, EL_INVISIBLE_STEELWALL_BOTTOMLEFT },
1289 { EL_STEELWALL_BOTTOMRIGHT, EL_INVISIBLE_STEELWALL_BOTTOMRIGHT },
1290 { EL_STEELWALL_VERTICAL, EL_INVISIBLE_STEELWALL_VERTICAL },
1291 { EL_STEELWALL_HORIZONTAL, EL_INVISIBLE_STEELWALL_HORIZONTAL },
1292 { EL_STEELWALL, EL_INVISIBLE_STEELWALL }
1294 int steel_type = (BorderElement == EL_STEELWALL ? 0 : 1);
1295 int steel_position = (x == -1 && y == -1 ? 0 :
1296 x == lev_fieldx && y == -1 ? 1 :
1297 x == -1 && y == lev_fieldy ? 2 :
1298 x == lev_fieldx && y == lev_fieldy ? 3 :
1299 x == -1 || x == lev_fieldx ? 4 :
1300 y == -1 || y == lev_fieldy ? 5 : 6);
1302 return border[steel_position][steel_type];
1305 void DrawScreenElement(int x, int y, int element)
1307 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
1308 DrawLevelFieldCrumbledSand(LEVELX(x), LEVELY(y));
1311 void DrawLevelElement(int x, int y, int element)
1313 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1314 DrawScreenElement(SCREENX(x), SCREENY(y), element);
1317 void DrawScreenField(int x, int y)
1319 int lx = LEVELX(x), ly = LEVELY(y);
1320 int element, content;
1322 if (!IN_LEV_FIELD(lx, ly))
1324 if (lx < -1 || lx > lev_fieldx || ly < -1 || ly > lev_fieldy)
1327 element = getBorderElement(lx, ly);
1329 DrawScreenElement(x, y, element);
1333 element = Feld[lx][ly];
1334 content = Store[lx][ly];
1336 if (IS_MOVING(lx, ly))
1338 int horiz_move = (MovDir[lx][ly] == MV_LEFT || MovDir[lx][ly] == MV_RIGHT);
1339 boolean cut_mode = NO_CUTTING;
1341 if (element == EL_QUICKSAND_EMPTYING ||
1342 element == EL_MAGIC_WALL_EMPTYING ||
1343 element == EL_BD_MAGIC_WALL_EMPTYING ||
1344 element == EL_AMOEBA_DROPPING)
1345 cut_mode = CUT_ABOVE;
1346 else if (element == EL_QUICKSAND_FILLING ||
1347 element == EL_MAGIC_WALL_FILLING ||
1348 element == EL_BD_MAGIC_WALL_FILLING)
1349 cut_mode = CUT_BELOW;
1351 if (cut_mode == CUT_ABOVE)
1352 DrawScreenElementShifted(x, y, 0, 0, element, NO_CUTTING);
1354 DrawScreenElement(x, y, EL_EMPTY);
1357 DrawScreenElementShifted(x, y, MovPos[lx][ly], 0, element, NO_CUTTING);
1358 else if (cut_mode == NO_CUTTING)
1359 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], element, cut_mode);
1361 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], content, cut_mode);
1363 if (content == EL_ACID)
1364 DrawLevelElementThruMask(lx, ly + 1, EL_ACID);
1366 else if (IS_BLOCKED(lx, ly))
1371 boolean cut_mode = NO_CUTTING;
1372 int element_old, content_old;
1374 Blocked2Moving(lx, ly, &oldx, &oldy);
1377 horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
1378 MovDir[oldx][oldy] == MV_RIGHT);
1380 element_old = Feld[oldx][oldy];
1381 content_old = Store[oldx][oldy];
1383 if (element_old == EL_QUICKSAND_EMPTYING ||
1384 element_old == EL_MAGIC_WALL_EMPTYING ||
1385 element_old == EL_BD_MAGIC_WALL_EMPTYING ||
1386 element_old == EL_AMOEBA_DROPPING)
1387 cut_mode = CUT_ABOVE;
1389 DrawScreenElement(x, y, EL_EMPTY);
1392 DrawScreenElementShifted(sx, sy, MovPos[oldx][oldy], 0, element_old,
1394 else if (cut_mode == NO_CUTTING)
1395 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], element_old,
1398 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], content_old,
1401 else if (IS_DRAWABLE(element))
1402 DrawScreenElement(x, y, element);
1404 DrawScreenElement(x, y, EL_EMPTY);
1407 void DrawLevelField(int x, int y)
1409 if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1410 DrawScreenField(SCREENX(x), SCREENY(y));
1411 else if (IS_MOVING(x, y))
1415 Moving2Blocked(x, y, &newx, &newy);
1416 if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
1417 DrawScreenField(SCREENX(newx), SCREENY(newy));
1419 else if (IS_BLOCKED(x, y))
1423 Blocked2Moving(x, y, &oldx, &oldy);
1424 if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
1425 DrawScreenField(SCREENX(oldx), SCREENY(oldy));
1429 void DrawMiniElement(int x, int y, int element)
1433 graphic = el2edimg(element);
1434 DrawMiniGraphic(x, y, graphic);
1437 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
1439 int x = sx + scroll_x, y = sy + scroll_y;
1441 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
1442 DrawMiniElement(sx, sy, EL_EMPTY);
1443 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
1444 DrawMiniElement(sx, sy, Feld[x][y]);
1446 DrawMiniGraphic(sx, sy, el2edimg(getBorderElement(x, y)));
1449 void getMicroGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
1451 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
1452 int mini_startx = src_bitmap->width * 3 / 4;
1453 int mini_starty = src_bitmap->height * 2 / 3;
1454 int src_x = mini_startx + graphic_info[graphic].src_x / 8;
1455 int src_y = mini_starty + graphic_info[graphic].src_y / 8;
1457 if (src_x + MICRO_TILEX > src_bitmap->width ||
1458 src_y + MICRO_TILEY > src_bitmap->height)
1460 /* graphic of desired size seems not to be contained in this image;
1461 dirty workaround: get it from the middle of the normal sized image */
1463 getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
1464 src_x += (TILEX / 2 - MICRO_TILEX / 2);
1465 src_y += (TILEY / 2 - MICRO_TILEY / 2);
1468 *bitmap = src_bitmap;
1473 void DrawMicroElement(int xpos, int ypos, int element)
1477 int graphic = el2preimg(element);
1479 getMicroGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
1480 BlitBitmap(src_bitmap, drawto, src_x, src_y, MICRO_TILEX, MICRO_TILEY,
1488 SetDrawBackgroundMask(REDRAW_NONE);
1491 for(x=BX1; x<=BX2; x++)
1492 for(y=BY1; y<=BY2; y++)
1493 DrawScreenField(x, y);
1495 redraw_mask |= REDRAW_FIELD;
1498 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
1502 for(x=0; x<size_x; x++)
1503 for(y=0; y<size_y; y++)
1504 DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
1506 redraw_mask |= REDRAW_FIELD;
1509 static void DrawMicroLevelExt(int xpos, int ypos, int from_x, int from_y)
1513 DrawBackground(xpos, ypos, MICROLEV_XSIZE, MICROLEV_YSIZE);
1515 if (lev_fieldx < STD_LEV_FIELDX)
1516 xpos += (STD_LEV_FIELDX - lev_fieldx) / 2 * MICRO_TILEX;
1517 if (lev_fieldy < STD_LEV_FIELDY)
1518 ypos += (STD_LEV_FIELDY - lev_fieldy) / 2 * MICRO_TILEY;
1520 xpos += MICRO_TILEX;
1521 ypos += MICRO_TILEY;
1523 for(x=-1; x<=STD_LEV_FIELDX; x++)
1525 for(y=-1; y<=STD_LEV_FIELDY; y++)
1527 int lx = from_x + x, ly = from_y + y;
1529 if (lx >= 0 && lx < lev_fieldx && ly >= 0 && ly < lev_fieldy)
1530 DrawMicroElement(xpos + x * MICRO_TILEX, ypos + y * MICRO_TILEY,
1532 else if (lx >= -1 && lx < lev_fieldx+1 && ly >= -1 && ly < lev_fieldy+1
1533 && BorderElement != EL_EMPTY)
1534 DrawMicroElement(xpos + x * MICRO_TILEX, ypos + y * MICRO_TILEY,
1535 getBorderElement(lx, ly));
1539 redraw_mask |= REDRAW_MICROLEVEL;
1542 #define MICROLABEL_EMPTY 0
1543 #define MICROLABEL_LEVEL_NAME 1
1544 #define MICROLABEL_CREATED_BY 2
1545 #define MICROLABEL_LEVEL_AUTHOR 3
1546 #define MICROLABEL_IMPORTED_FROM 4
1547 #define MICROLABEL_LEVEL_IMPORT_INFO 5
1549 static void DrawMicroLevelLabelExt(int mode)
1551 char label_text[MAX_OUTPUT_LINESIZE + 1];
1552 int max_len_label_text;
1553 int font_nr = FONT_TEXT_2;
1555 if (mode == MICROLABEL_CREATED_BY || mode == MICROLABEL_IMPORTED_FROM)
1556 font_nr = FONT_TEXT_3;
1558 max_len_label_text = SXSIZE / getFontWidth(font_nr);
1560 DrawBackground(SX, MICROLABEL_YPOS, SXSIZE, getFontHeight(font_nr));
1562 strncpy(label_text, (mode == MICROLABEL_LEVEL_NAME ? level.name :
1563 mode == MICROLABEL_CREATED_BY ? "created by" :
1564 mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
1565 mode == MICROLABEL_IMPORTED_FROM ? "imported from" :
1566 mode == MICROLABEL_LEVEL_IMPORT_INFO ?
1567 leveldir_current->imported_from : ""),
1568 max_len_label_text);
1569 label_text[max_len_label_text] = '\0';
1571 if (strlen(label_text) > 0)
1573 int text_width = strlen(label_text) * getFontWidth(font_nr);
1574 int lxpos = SX + (SXSIZE - text_width) / 2;
1575 int lypos = MICROLABEL_YPOS;
1577 DrawText(lxpos, lypos, label_text, font_nr);
1580 redraw_mask |= REDRAW_MICROLEVEL;
1583 void DrawMicroLevel(int xpos, int ypos, boolean restart)
1585 static unsigned long scroll_delay = 0;
1586 static unsigned long label_delay = 0;
1587 static int from_x, from_y, scroll_direction;
1588 static int label_state, label_counter;
1589 int last_game_status = game_status; /* save current game status */
1591 game_status = PSEUDO_PREVIEW; /* force PREVIEW font on preview level */
1595 from_x = from_y = 0;
1596 scroll_direction = MV_RIGHT;
1600 DrawMicroLevelExt(xpos, ypos, from_x, from_y);
1601 DrawMicroLevelLabelExt(label_state);
1603 /* initialize delay counters */
1604 DelayReached(&scroll_delay, 0);
1605 DelayReached(&label_delay, 0);
1607 if (leveldir_current->name)
1609 int len = strlen(leveldir_current->name);
1610 int lxpos = SX + (SXSIZE - len * getFontWidth(FONT_TEXT_1)) / 2;
1611 int lypos = SY + 352;
1613 DrawText(lxpos, lypos, leveldir_current->name, FONT_TEXT_1);
1616 game_status = last_game_status; /* restore current game status */
1621 /* scroll micro level, if needed */
1622 if ((lev_fieldx > STD_LEV_FIELDX || lev_fieldy > STD_LEV_FIELDY) &&
1623 DelayReached(&scroll_delay, MICROLEVEL_SCROLL_DELAY))
1625 switch (scroll_direction)
1631 scroll_direction = MV_UP;
1635 if (from_x < lev_fieldx - STD_LEV_FIELDX)
1638 scroll_direction = MV_DOWN;
1645 scroll_direction = MV_RIGHT;
1649 if (from_y < lev_fieldy - STD_LEV_FIELDY)
1652 scroll_direction = MV_LEFT;
1659 DrawMicroLevelExt(xpos, ypos, from_x, from_y);
1662 /* redraw micro level label, if needed */
1663 if (strcmp(level.name, NAMELESS_LEVEL_NAME) != 0 &&
1664 strcmp(level.author, ANONYMOUS_NAME) != 0 &&
1665 strcmp(level.author, leveldir_current->name) != 0 &&
1666 DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
1668 int max_label_counter = 23;
1670 if (leveldir_current->imported_from != NULL)
1671 max_label_counter += 14;
1673 label_counter = (label_counter + 1) % max_label_counter;
1674 label_state = (label_counter >= 0 && label_counter <= 7 ?
1675 MICROLABEL_LEVEL_NAME :
1676 label_counter >= 9 && label_counter <= 12 ?
1677 MICROLABEL_CREATED_BY :
1678 label_counter >= 14 && label_counter <= 21 ?
1679 MICROLABEL_LEVEL_AUTHOR :
1680 label_counter >= 23 && label_counter <= 26 ?
1681 MICROLABEL_IMPORTED_FROM :
1682 label_counter >= 28 && label_counter <= 35 ?
1683 MICROLABEL_LEVEL_IMPORT_INFO : MICROLABEL_EMPTY);
1684 DrawMicroLevelLabelExt(label_state);
1687 game_status = last_game_status; /* restore current game status */
1690 int REQ_in_range(int x, int y)
1692 if (y > DY+249 && y < DY+278)
1694 if (x > DX+1 && x < DX+48)
1696 else if (x > DX+51 && x < DX+98)
1702 #define MAX_REQUEST_LINES 13
1703 #define MAX_REQUEST_LINE_LEN 7
1705 boolean Request(char *text, unsigned int req_state)
1707 int mx, my, ty, result = -1;
1708 unsigned int old_door_state;
1709 int last_game_status = game_status; /* save current game status */
1711 #if defined(PLATFORM_UNIX)
1712 /* pause network game while waiting for request to answer */
1713 if (options.network &&
1714 game_status == PLAYING &&
1715 req_state & REQUEST_WAIT_FOR)
1716 SendToServer_PausePlaying();
1719 old_door_state = GetDoorState();
1723 CloseDoor(DOOR_CLOSE_1);
1725 /* save old door content */
1726 BlitBitmap(bitmap_db_door, bitmap_db_door,
1727 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
1728 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
1730 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
1732 /* clear door drawing field */
1733 DrawBackground(DX, DY, DXSIZE, DYSIZE);
1735 game_status = PSEUDO_DOOR; /* force DOOR font on preview level */
1737 /* write text for request */
1738 for(ty=0; ty < MAX_REQUEST_LINES; ty++)
1740 char text_line[MAX_REQUEST_LINE_LEN + 1];
1746 for(tl=0,tx=0; tx < MAX_REQUEST_LINE_LEN; tl++,tx++)
1749 if (!tc || tc == ' ')
1760 strncpy(text_line, text, tl);
1763 DrawText(DX + (DXSIZE - tl * getFontWidth(FONT_TEXT_2)) / 2,
1764 DY + 8 + ty * (getFontHeight(FONT_TEXT_2) + 2),
1765 text_line, FONT_TEXT_2);
1767 text += tl + (tc == ' ' ? 1 : 0);
1770 game_status = last_game_status; /* restore current game status */
1772 if (req_state & REQ_ASK)
1774 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
1775 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
1777 else if (req_state & REQ_CONFIRM)
1779 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
1781 else if (req_state & REQ_PLAYER)
1783 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
1784 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
1785 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
1786 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
1789 /* copy request gadgets to door backbuffer */
1790 BlitBitmap(drawto, bitmap_db_door,
1791 DX, DY, DXSIZE, DYSIZE,
1792 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
1794 OpenDoor(DOOR_OPEN_1);
1800 if (!(req_state & REQUEST_WAIT_FOR))
1802 SetDrawBackgroundMask(REDRAW_FIELD);
1807 if (game_status != MAINMENU)
1810 button_status = MB_RELEASED;
1812 request_gadget_id = -1;
1814 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
1826 case EVENT_BUTTONPRESS:
1827 case EVENT_BUTTONRELEASE:
1828 case EVENT_MOTIONNOTIFY:
1830 if (event.type == EVENT_MOTIONNOTIFY)
1832 if (!PointerInWindow(window))
1833 continue; /* window and pointer are on different screens */
1838 motion_status = TRUE;
1839 mx = ((MotionEvent *) &event)->x;
1840 my = ((MotionEvent *) &event)->y;
1844 motion_status = FALSE;
1845 mx = ((ButtonEvent *) &event)->x;
1846 my = ((ButtonEvent *) &event)->y;
1847 if (event.type == EVENT_BUTTONPRESS)
1848 button_status = ((ButtonEvent *) &event)->button;
1850 button_status = MB_RELEASED;
1853 /* this sets 'request_gadget_id' */
1854 HandleGadgets(mx, my, button_status);
1856 switch(request_gadget_id)
1858 case TOOL_CTRL_ID_YES:
1861 case TOOL_CTRL_ID_NO:
1864 case TOOL_CTRL_ID_CONFIRM:
1865 result = TRUE | FALSE;
1868 case TOOL_CTRL_ID_PLAYER_1:
1871 case TOOL_CTRL_ID_PLAYER_2:
1874 case TOOL_CTRL_ID_PLAYER_3:
1877 case TOOL_CTRL_ID_PLAYER_4:
1888 case EVENT_KEYPRESS:
1889 switch(GetEventKey((KeyEvent *)&event, TRUE))
1902 if (req_state & REQ_PLAYER)
1906 case EVENT_KEYRELEASE:
1907 ClearPlayerAction();
1911 HandleOtherEvents(&event);
1915 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
1917 int joy = AnyJoystick();
1919 if (joy & JOY_BUTTON_1)
1921 else if (joy & JOY_BUTTON_2)
1927 /* don't eat all CPU time */
1931 if (game_status != MAINMENU)
1936 if (!(req_state & REQ_STAY_OPEN))
1938 CloseDoor(DOOR_CLOSE_1);
1940 if (!(req_state & REQ_STAY_CLOSED) && (old_door_state & DOOR_OPEN_1))
1942 BlitBitmap(bitmap_db_door, bitmap_db_door,
1943 DOOR_GFX_PAGEX2,DOOR_GFX_PAGEY1, DXSIZE,DYSIZE,
1944 DOOR_GFX_PAGEX1,DOOR_GFX_PAGEY1);
1945 OpenDoor(DOOR_OPEN_1);
1951 SetDrawBackgroundMask(REDRAW_FIELD);
1953 #if defined(PLATFORM_UNIX)
1954 /* continue network game after request */
1955 if (options.network &&
1956 game_status == PLAYING &&
1957 req_state & REQUEST_WAIT_FOR)
1958 SendToServer_ContinuePlaying();
1964 unsigned int OpenDoor(unsigned int door_state)
1966 unsigned int new_door_state;
1968 if (door_state & DOOR_COPY_BACK)
1970 BlitBitmap(bitmap_db_door, bitmap_db_door,
1971 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE + VYSIZE,
1972 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
1973 door_state &= ~DOOR_COPY_BACK;
1976 new_door_state = MoveDoor(door_state);
1978 return(new_door_state);
1981 unsigned int CloseDoor(unsigned int door_state)
1983 unsigned int new_door_state;
1985 BlitBitmap(backbuffer, bitmap_db_door,
1986 DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
1987 BlitBitmap(backbuffer, bitmap_db_door,
1988 VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
1990 new_door_state = MoveDoor(door_state);
1992 return(new_door_state);
1995 unsigned int GetDoorState()
1997 return MoveDoor(DOOR_GET_STATE);
2000 unsigned int SetDoorState(unsigned int door_state)
2002 return MoveDoor(door_state | DOOR_SET_STATE);
2005 unsigned int MoveDoor(unsigned int door_state)
2007 static int door1 = DOOR_OPEN_1;
2008 static int door2 = DOOR_CLOSE_2;
2009 static unsigned long door_delay = 0;
2010 int x, start, stepsize = global.door_step_offset;
2011 unsigned long door_delay_value = global.door_step_delay;
2013 if (door_state == DOOR_GET_STATE)
2014 return(door1 | door2);
2016 if (door_state & DOOR_SET_STATE)
2018 if (door_state & DOOR_ACTION_1)
2019 door1 = door_state & DOOR_ACTION_1;
2020 if (door_state & DOOR_ACTION_2)
2021 door2 = door_state & DOOR_ACTION_2;
2023 return(door1 | door2);
2026 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
2027 door_state &= ~DOOR_OPEN_1;
2028 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
2029 door_state &= ~DOOR_CLOSE_1;
2030 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
2031 door_state &= ~DOOR_OPEN_2;
2032 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
2033 door_state &= ~DOOR_CLOSE_2;
2035 if (setup.quick_doors)
2038 door_delay_value = 0;
2040 StopSound(SND_DOOR_OPENING);
2041 StopSound(SND_DOOR_CLOSING);
2044 if (global.autoplay_leveldir)
2046 door_state |= DOOR_NO_DELAY;
2047 door_state &= ~DOOR_CLOSE_ALL;
2050 if (door_state & DOOR_ACTION)
2052 if (!(door_state & DOOR_NO_DELAY))
2054 /* opening door sound has priority over simultaneously closing door */
2055 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
2056 PlaySoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
2057 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
2058 PlaySoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
2061 start = ((door_state & DOOR_NO_DELAY) ? DXSIZE : 0);
2063 for(x=start; x<=DXSIZE; x+=stepsize)
2065 Bitmap *bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
2066 GC gc = bitmap->stored_clip_gc;
2068 if (!(door_state & DOOR_NO_DELAY))
2069 WaitUntilDelayReached(&door_delay, door_delay_value);
2071 if (door_state & DOOR_ACTION_1)
2073 int i = (door_state & DOOR_OPEN_1 ? DXSIZE-x : x);
2074 int j = (DXSIZE - i) / 3;
2076 BlitBitmap(bitmap_db_door, drawto,
2077 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + i/2,
2078 DXSIZE,DYSIZE - i/2, DX, DY);
2080 ClearRectangle(drawto, DX, DY + DYSIZE - i/2, DXSIZE,i/2);
2082 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2083 BlitBitmapMasked(bitmap, drawto,
2084 DXSIZE, DOOR_GFX_PAGEY1, i, 77,
2085 DX + DXSIZE - i, DY + j);
2086 BlitBitmapMasked(bitmap, drawto,
2087 DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63,
2088 DX + DXSIZE - i, DY + 140 + j);
2089 SetClipOrigin(bitmap, gc, DX - DXSIZE + i, DY - (DOOR_GFX_PAGEY1 + j));
2090 BlitBitmapMasked(bitmap, drawto,
2091 DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j,
2093 BlitBitmapMasked(bitmap, drawto,
2094 DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63,
2097 BlitBitmapMasked(bitmap, drawto,
2098 DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
2100 BlitBitmapMasked(bitmap, drawto,
2101 DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
2103 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2104 BlitBitmapMasked(bitmap, drawto,
2105 DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
2106 DX + DXSIZE - i, DY + 77 + j);
2107 BlitBitmapMasked(bitmap, drawto,
2108 DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
2109 DX + DXSIZE - i, DY + 203 + j);
2111 redraw_mask |= REDRAW_DOOR_1;
2114 if (door_state & DOOR_ACTION_2)
2116 int i = (door_state & DOOR_OPEN_2 ? VXSIZE - x : x);
2117 int j = (VXSIZE - i) / 3;
2119 BlitBitmap(bitmap_db_door, drawto,
2120 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + i/2,
2121 VXSIZE, VYSIZE - i/2, VX, VY);
2123 ClearRectangle(drawto, VX, VY + VYSIZE-i/2, VXSIZE, i/2);
2125 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2126 BlitBitmapMasked(bitmap, drawto,
2127 VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2,
2128 VX + VXSIZE-i, VY+j);
2129 SetClipOrigin(bitmap, gc,
2130 VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
2131 BlitBitmapMasked(bitmap, drawto,
2132 VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j,
2135 BlitBitmapMasked(bitmap, drawto,
2136 VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2,
2137 i, VYSIZE / 2, VX, VY + VYSIZE / 2 - j);
2138 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2139 BlitBitmapMasked(bitmap, drawto,
2140 VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2,
2142 VX + VXSIZE - i, VY + VYSIZE / 2 + j);
2144 redraw_mask |= REDRAW_DOOR_2;
2149 if (game_status == MAINMENU)
2154 if (setup.quick_doors)
2156 StopSound(SND_DOOR_OPENING);
2157 StopSound(SND_DOOR_CLOSING);
2160 if (door_state & DOOR_ACTION_1)
2161 door1 = door_state & DOOR_ACTION_1;
2162 if (door_state & DOOR_ACTION_2)
2163 door2 = door_state & DOOR_ACTION_2;
2165 return (door1 | door2);
2168 void DrawSpecialEditorDoor()
2170 /* draw bigger toolbox window */
2171 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
2172 DOOR_GFX_PAGEX7, 0, EXSIZE + 8, 8,
2174 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
2175 EX - 4, VY - 4, EXSIZE + 8, EYSIZE - VYSIZE + 4,
2178 redraw_mask |= REDRAW_ALL;
2181 void UndrawSpecialEditorDoor()
2183 /* draw normal tape recorder window */
2184 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
2185 EX - 4, EY - 12, EXSIZE + 8, EYSIZE - VYSIZE + 12,
2188 redraw_mask |= REDRAW_ALL;
2192 /* ---------- new tool button stuff ---------------------------------------- */
2194 /* graphic position values for tool buttons */
2195 #define TOOL_BUTTON_YES_XPOS 2
2196 #define TOOL_BUTTON_YES_YPOS 250
2197 #define TOOL_BUTTON_YES_GFX_YPOS 0
2198 #define TOOL_BUTTON_YES_XSIZE 46
2199 #define TOOL_BUTTON_YES_YSIZE 28
2200 #define TOOL_BUTTON_NO_XPOS 52
2201 #define TOOL_BUTTON_NO_YPOS TOOL_BUTTON_YES_YPOS
2202 #define TOOL_BUTTON_NO_GFX_YPOS TOOL_BUTTON_YES_GFX_YPOS
2203 #define TOOL_BUTTON_NO_XSIZE TOOL_BUTTON_YES_XSIZE
2204 #define TOOL_BUTTON_NO_YSIZE TOOL_BUTTON_YES_YSIZE
2205 #define TOOL_BUTTON_CONFIRM_XPOS TOOL_BUTTON_YES_XPOS
2206 #define TOOL_BUTTON_CONFIRM_YPOS TOOL_BUTTON_YES_YPOS
2207 #define TOOL_BUTTON_CONFIRM_GFX_YPOS 30
2208 #define TOOL_BUTTON_CONFIRM_XSIZE 96
2209 #define TOOL_BUTTON_CONFIRM_YSIZE TOOL_BUTTON_YES_YSIZE
2210 #define TOOL_BUTTON_PLAYER_XSIZE 30
2211 #define TOOL_BUTTON_PLAYER_YSIZE 30
2212 #define TOOL_BUTTON_PLAYER_GFX_XPOS 5
2213 #define TOOL_BUTTON_PLAYER_GFX_YPOS 185
2214 #define TOOL_BUTTON_PLAYER_XPOS (5 + TOOL_BUTTON_PLAYER_XSIZE / 2)
2215 #define TOOL_BUTTON_PLAYER_YPOS (215 - TOOL_BUTTON_PLAYER_YSIZE / 2)
2216 #define TOOL_BUTTON_PLAYER1_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2217 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2218 #define TOOL_BUTTON_PLAYER2_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2219 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2220 #define TOOL_BUTTON_PLAYER3_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2221 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2222 #define TOOL_BUTTON_PLAYER4_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2223 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2224 #define TOOL_BUTTON_PLAYER1_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2225 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2226 #define TOOL_BUTTON_PLAYER2_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2227 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2228 #define TOOL_BUTTON_PLAYER3_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2229 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2230 #define TOOL_BUTTON_PLAYER4_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2231 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2240 } toolbutton_info[NUM_TOOL_BUTTONS] =
2243 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_GFX_YPOS,
2244 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_YPOS,
2245 TOOL_BUTTON_YES_XSIZE, TOOL_BUTTON_YES_YSIZE,
2250 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_GFX_YPOS,
2251 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_YPOS,
2252 TOOL_BUTTON_NO_XSIZE, TOOL_BUTTON_NO_YSIZE,
2257 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_GFX_YPOS,
2258 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_YPOS,
2259 TOOL_BUTTON_CONFIRM_XSIZE, TOOL_BUTTON_CONFIRM_YSIZE,
2260 TOOL_CTRL_ID_CONFIRM,
2264 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2265 TOOL_BUTTON_PLAYER1_XPOS, TOOL_BUTTON_PLAYER1_YPOS,
2266 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2267 TOOL_CTRL_ID_PLAYER_1,
2271 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2272 TOOL_BUTTON_PLAYER2_XPOS, TOOL_BUTTON_PLAYER2_YPOS,
2273 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2274 TOOL_CTRL_ID_PLAYER_2,
2278 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2279 TOOL_BUTTON_PLAYER3_XPOS, TOOL_BUTTON_PLAYER3_YPOS,
2280 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2281 TOOL_CTRL_ID_PLAYER_3,
2285 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2286 TOOL_BUTTON_PLAYER4_XPOS, TOOL_BUTTON_PLAYER4_YPOS,
2287 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2288 TOOL_CTRL_ID_PLAYER_4,
2293 void CreateToolButtons()
2297 for (i=0; i<NUM_TOOL_BUTTONS; i++)
2299 Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
2300 Bitmap *deco_bitmap = None;
2301 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
2302 struct GadgetInfo *gi;
2303 unsigned long event_mask;
2304 int gd_xoffset, gd_yoffset;
2305 int gd_x1, gd_x2, gd_y;
2308 event_mask = GD_EVENT_RELEASED;
2310 gd_xoffset = toolbutton_info[i].xpos;
2311 gd_yoffset = toolbutton_info[i].ypos;
2312 gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
2313 gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
2314 gd_y = DOOR_GFX_PAGEY1 + gd_yoffset;
2316 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
2318 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
2320 getMiniGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr),
2321 &deco_bitmap, &deco_x, &deco_y);
2322 deco_xpos = (toolbutton_info[i].width - MINI_TILEX) / 2;
2323 deco_ypos = (toolbutton_info[i].height - MINI_TILEY) / 2;
2326 gi = CreateGadget(GDI_CUSTOM_ID, id,
2327 GDI_INFO_TEXT, toolbutton_info[i].infotext,
2328 GDI_X, DX + toolbutton_info[i].x,
2329 GDI_Y, DY + toolbutton_info[i].y,
2330 GDI_WIDTH, toolbutton_info[i].width,
2331 GDI_HEIGHT, toolbutton_info[i].height,
2332 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
2333 GDI_STATE, GD_BUTTON_UNPRESSED,
2334 GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
2335 GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
2336 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
2337 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
2338 GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
2339 GDI_DECORATION_SHIFTING, 1, 1,
2340 GDI_EVENT_MASK, event_mask,
2341 GDI_CALLBACK_ACTION, HandleToolButtons,
2345 Error(ERR_EXIT, "cannot create gadget");
2347 tool_gadget[id] = gi;
2351 void FreeToolButtons()
2355 for (i=0; i<NUM_TOOL_BUTTONS; i++)
2356 FreeGadget(tool_gadget[i]);
2359 static void UnmapToolButtons()
2363 for (i=0; i<NUM_TOOL_BUTTONS; i++)
2364 UnmapGadget(tool_gadget[i]);
2367 static void HandleToolButtons(struct GadgetInfo *gi)
2369 request_gadget_id = gi->custom_id;
2372 int get_next_element(int element)
2376 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
2377 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
2378 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
2379 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
2380 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
2381 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
2382 case EL_AMOEBA_DROPPING: return EL_AMOEBA_WET;
2384 default: return element;
2388 int el_act_dir2img(int element, int action, int direction)
2390 direction = MV_DIR_BIT(direction);
2392 return element_info[element].direction_graphic[action][direction];
2395 int el_act2img(int element, int action)
2397 return element_info[element].graphic[action];
2400 int el_dir2img(int element, int direction)
2402 return el_act_dir2img(element, ACTION_DEFAULT, direction);
2405 int el2img(int element)
2407 return element_info[element].graphic[ACTION_DEFAULT];
2410 int el2edimg(int element)
2412 return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
2415 int el2preimg(int element)
2417 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];