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 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
777 int offset_x = graphic_info[graphic].offset_x;
778 int offset_y = graphic_info[graphic].offset_y;
779 int src_x = graphic_info[graphic].src_x + frame * offset_x;
780 int src_y = graphic_info[graphic].src_y + frame * offset_y;
782 *bitmap = src_bitmap;
787 void DrawGraphic(int x, int y, int graphic, int frame)
790 if (!IN_SCR_FIELD(x, y))
792 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
793 printf("DrawGraphic(): This should never happen!\n");
798 DrawGraphicExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic, frame);
803 void DrawOldGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic)
808 getOldGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
809 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
813 void DrawGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
820 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
822 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
823 int src_x = graphic_info[graphic].src_x;
824 int src_y = graphic_info[graphic].src_y;
825 int offset_x = graphic_info[graphic].offset_x;
826 int offset_y = graphic_info[graphic].offset_y;
828 src_x += frame * offset_x;
829 src_y += frame * offset_y;
832 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
835 void DrawGraphicThruMask(int x, int y, int graphic, int frame)
838 if (!IN_SCR_FIELD(x, y))
840 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
841 printf("DrawGraphicThruMask(): This should never happen!\n");
846 DrawGraphicThruMaskExt(drawto_field, FX + x * TILEX, FY + y *TILEY, graphic,
851 void DrawGraphicThruMaskExt(DrawBuffer *d, int dest_x, int dest_y, int graphic,
859 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
860 drawing_gc = src_bitmap->stored_clip_gc;
862 GC drawing_gc = src_bitmap->stored_clip_gc;
863 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
864 int src_x = graphic_info[graphic].src_x;
865 int src_y = graphic_info[graphic].src_y;
866 int offset_x = graphic_info[graphic].offset_x;
867 int offset_y = graphic_info[graphic].offset_y;
869 src_x += frame * offset_x;
870 src_y += frame * offset_y;
874 SetClipOrigin(src_bitmap, drawing_gc, dest_x - src_x, dest_y - src_y);
875 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX, TILEY, dest_x, dest_y);
878 void DrawMiniGraphic(int x, int y, int graphic)
880 DrawMiniGraphicExt(drawto, SX + x * MINI_TILEX,SY + y * MINI_TILEY, graphic);
881 MarkTileDirty(x / 2, y / 2);
884 void getMiniGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
886 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
888 int mini_starty = src_bitmap->height * 2 / 3;
889 int src_x = mini_startx + graphic_info[graphic].src_x / 2;
890 int src_y = mini_starty + graphic_info[graphic].src_y / 2;
893 /* !!! not needed anymore, because of automatically created mini graphics */
894 if (src_x + MINI_TILEX > src_bitmap->width ||
895 src_y + MINI_TILEY > src_bitmap->height)
897 /* graphic of desired size seems not to be contained in this image;
898 dirty workaround: get it from the middle of the normal sized image */
900 printf("::: using dirty workaround for %d (%d, %d)\n",
901 graphic, src_bitmap->width, src_bitmap->height);
903 getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
904 src_x += (TILEX / 2 - MINI_TILEX / 2);
905 src_y += (TILEY / 2 - MINI_TILEY / 2);
909 *bitmap = src_bitmap;
914 void DrawMiniGraphicExt(DrawBuffer *d, int x, int y, int graphic)
919 getMiniGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
920 BlitBitmap(src_bitmap, d, src_x, src_y, MINI_TILEX, MINI_TILEY, x, y);
923 void DrawGraphicShifted(int x,int y, int dx,int dy, int graphic, int frame,
924 int cut_mode, int mask_mode)
933 int width = TILEX, height = TILEY;
939 DrawGraphic(x, y, graphic, frame);
943 if (dx || dy) /* shifted graphic */
945 if (x < BX1) /* object enters playfield from the left */
952 else if (x > BX2) /* object enters playfield from the right */
958 else if (x==BX1 && dx < 0) /* object leaves playfield to the left */
964 else if (x==BX2 && dx > 0) /* object leaves playfield to the right */
966 else if (dx) /* general horizontal movement */
967 MarkTileDirty(x + SIGN(dx), y);
969 if (y < BY1) /* object enters playfield from the top */
971 if (cut_mode==CUT_BELOW) /* object completely above top border */
979 else if (y > BY2) /* object enters playfield from the bottom */
985 else if (y==BY1 && dy < 0) /* object leaves playfield to the top */
991 else if (dy > 0 && cut_mode == CUT_ABOVE)
993 if (y == BY2) /* object completely above bottom border */
999 MarkTileDirty(x, y + 1);
1000 } /* object leaves playfield to the bottom */
1001 else if (dy > 0 && (y == BY2 || cut_mode == CUT_BELOW))
1003 else if (dy) /* general vertical movement */
1004 MarkTileDirty(x, y + SIGN(dy));
1007 src_bitmap = graphic_info[graphic].bitmap;
1008 src_x = graphic_info[graphic].src_x;
1009 src_y = graphic_info[graphic].src_y;
1010 offset_x = graphic_info[graphic].offset_x;
1011 offset_y = graphic_info[graphic].offset_y;
1013 drawing_gc = src_bitmap->stored_clip_gc;
1015 src_x += frame * offset_x;
1016 src_y += frame * offset_y;
1021 dest_x = FX + x * TILEX + dx;
1022 dest_y = FY + y * TILEY + dy;
1025 if (!IN_SCR_FIELD(x,y))
1027 printf("DrawGraphicShifted(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
1028 printf("DrawGraphicShifted(): This should never happen!\n");
1033 if (mask_mode == USE_MASKING)
1035 SetClipOrigin(src_bitmap, drawing_gc, dest_x - src_x, dest_y - src_y);
1036 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1040 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1046 void DrawGraphicShiftedThruMask(int x, int y, int dx, int dy, int graphic,
1047 int frame, int cut_mode)
1049 DrawGraphicShifted(x,y, dx,dy, graphic, frame, cut_mode, USE_MASKING);
1052 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
1053 int cut_mode, int mask_mode)
1055 int lx = LEVELX(x), ly = LEVELY(y);
1059 if (IN_LEV_FIELD(lx, ly))
1061 SetRandomAnimationValue(lx, ly);
1063 graphic = el_act_dir2img(element, GfxAction[lx][ly], MovDir[lx][ly]);
1064 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1066 else /* border element */
1068 graphic = el2img(element);
1069 frame = getGraphicAnimationFrame(graphic, -1);
1072 if (element == EL_EXPANDABLE_WALL)
1074 boolean left_stopped = FALSE, right_stopped = FALSE;
1076 if (!IN_LEV_FIELD(lx - 1, ly) || IS_MAUER(Feld[lx - 1][ly]))
1077 left_stopped = TRUE;
1078 if (!IN_LEV_FIELD(lx + 1, ly) || IS_MAUER(Feld[lx + 1][ly]))
1079 right_stopped = TRUE;
1081 if (left_stopped && right_stopped)
1083 else if (left_stopped)
1085 graphic = IMG_EXPANDABLE_WALL_GROWING_RIGHT;
1086 frame = graphic_info[graphic].anim_frames - 1;
1088 else if (right_stopped)
1090 graphic = IMG_EXPANDABLE_WALL_GROWING_LEFT;
1091 frame = graphic_info[graphic].anim_frames - 1;
1095 else if (IS_AMOEBOID(element) || element == EL_AMOEBA_DROPPING)
1097 graphic = (element == EL_BD_AMOEBA ? IMG_BD_AMOEBA_PART1 :
1098 element == EL_AMOEBA_WET ? IMG_AMOEBA_WET_PART1 :
1099 element == EL_AMOEBA_DRY ? IMG_AMOEBA_DRY_PART1 :
1100 element == EL_AMOEBA_FULL ? IMG_AMOEBA_FULL_PART1 :
1101 IMG_AMOEBA_DEAD_PART1);
1103 graphic += (x + 2 * y + 4) % 4;
1108 if (IS_AMOEBOID(element) || element == EL_AMOEBA_DROPPING)
1110 if (Feld[lx][ly] == EL_AMOEBA_DROPPING)
1111 printf("---> %d -> %d / %d [%d]\n",
1112 element, graphic, frame, GfxRandom[lx][ly]);
1117 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, mask_mode);
1118 else if (mask_mode == USE_MASKING)
1119 DrawGraphicThruMask(x, y, graphic, frame);
1121 DrawGraphic(x, y, graphic, frame);
1124 void DrawLevelElementExt(int x, int y, int dx, int dy, int element,
1125 int cut_mode, int mask_mode)
1127 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1128 DrawScreenElementExt(SCREENX(x), SCREENY(y), dx, dy, element,
1129 cut_mode, mask_mode);
1132 void DrawScreenElementShifted(int x, int y, int dx, int dy, int element,
1135 DrawScreenElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1138 void DrawLevelElementShifted(int x, int y, int dx, int dy, int element,
1141 DrawLevelElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1145 void DrawOldScreenElementThruMask(int x, int y, int element)
1147 DrawOldScreenElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1150 void DrawScreenElementThruMask(int x, int y, int element)
1152 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1156 void DrawLevelElementThruMask(int x, int y, int element)
1158 DrawLevelElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1161 void DrawLevelFieldThruMask(int x, int y)
1163 DrawLevelElementExt(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
1166 static void DrawLevelFieldCrumbledSandExt(int x, int y, int graphic, int frame)
1170 int sx = SCREENX(x), sy = SCREENY(y);
1172 int width, height, cx, cy, i;
1173 int snip = TILEX / 8; /* number of border pixels from "crumbled graphic" */
1174 static int xy[4][2] =
1182 if (!IN_LEV_FIELD(x, y))
1185 element = (GfxElement[x][y] != EL_UNDEFINED ? GfxElement[x][y] : Feld[x][y]);
1187 /* crumble field itself */
1188 if (CAN_BE_CRUMBLED(element))
1190 if (!IN_SCR_FIELD(sx, sy))
1193 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1197 int xx = x + xy[i][0];
1198 int yy = y + xy[i][1];
1200 element = (IN_LEV_FIELD(xx, yy) ? Feld[xx][yy] : EL_STEELWALL);
1202 if (CAN_BE_CRUMBLED(element)) /* neighbour is of same type */
1205 if (i == 1 || i == 2)
1209 cx = (i == 2 ? TILEX - snip : 0);
1217 cy = (i == 3 ? TILEY - snip : 0);
1220 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1221 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
1224 MarkTileDirty(sx, sy);
1226 else /* crumble neighbour fields */
1228 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1232 int xx = x + xy[i][0];
1233 int yy = y + xy[i][1];
1234 int sxx = sx + xy[i][0];
1235 int syy = sy + xy[i][1];
1237 if (!IN_LEV_FIELD(xx, yy) ||
1238 !IN_SCR_FIELD(sxx, syy) ||
1239 !CAN_BE_CRUMBLED(Feld[xx][yy]))
1242 if (i == 1 || i == 2)
1246 cx = (i == 1 ? TILEX - snip : 0);
1254 cy = (i==0 ? TILEY-snip : 0);
1257 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1258 width, height, FX + sxx * TILEX + cx, FY + syy * TILEY + cy);
1260 MarkTileDirty(sxx, syy);
1265 void DrawLevelFieldCrumbledSand(int x, int y)
1267 DrawLevelFieldCrumbledSandExt(x, y, IMG_SAND_CRUMBLED, 0);
1270 void DrawLevelFieldCrumbledSandDigging(int x, int y, int direction,
1273 int graphic1 = el_act_dir2img(EL_SAND, ACTION_DIGGING, direction);
1274 int graphic2 = el_act_dir2img(EL_SAND_CRUMBLED, ACTION_DIGGING, direction);
1275 int frame1 = getGraphicAnimationFrame(graphic1, step_frame);
1276 int frame2 = getGraphicAnimationFrame(graphic2, step_frame);
1277 int sx = SCREENX(x), sy = SCREENY(y);
1279 DrawGraphic(sx, sy, graphic1, frame1);
1280 DrawLevelFieldCrumbledSandExt(x, y, graphic2, frame2);
1283 static int getBorderElement(int x, int y)
1287 { EL_STEELWALL_TOPLEFT, EL_INVISIBLE_STEELWALL_TOPLEFT },
1288 { EL_STEELWALL_TOPRIGHT, EL_INVISIBLE_STEELWALL_TOPRIGHT },
1289 { EL_STEELWALL_BOTTOMLEFT, EL_INVISIBLE_STEELWALL_BOTTOMLEFT },
1290 { EL_STEELWALL_BOTTOMRIGHT, EL_INVISIBLE_STEELWALL_BOTTOMRIGHT },
1291 { EL_STEELWALL_VERTICAL, EL_INVISIBLE_STEELWALL_VERTICAL },
1292 { EL_STEELWALL_HORIZONTAL, EL_INVISIBLE_STEELWALL_HORIZONTAL },
1293 { EL_STEELWALL, EL_INVISIBLE_STEELWALL }
1295 int steel_type = (BorderElement == EL_STEELWALL ? 0 : 1);
1296 int steel_position = (x == -1 && y == -1 ? 0 :
1297 x == lev_fieldx && y == -1 ? 1 :
1298 x == -1 && y == lev_fieldy ? 2 :
1299 x == lev_fieldx && y == lev_fieldy ? 3 :
1300 x == -1 || x == lev_fieldx ? 4 :
1301 y == -1 || y == lev_fieldy ? 5 : 6);
1303 return border[steel_position][steel_type];
1306 void DrawScreenElement(int x, int y, int element)
1308 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
1309 DrawLevelFieldCrumbledSand(LEVELX(x), LEVELY(y));
1312 void DrawLevelElement(int x, int y, int element)
1314 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1315 DrawScreenElement(SCREENX(x), SCREENY(y), element);
1318 void DrawScreenField(int x, int y)
1320 int lx = LEVELX(x), ly = LEVELY(y);
1321 int element, content;
1323 if (!IN_LEV_FIELD(lx, ly))
1325 if (lx < -1 || lx > lev_fieldx || ly < -1 || ly > lev_fieldy)
1328 element = getBorderElement(lx, ly);
1330 DrawScreenElement(x, y, element);
1334 element = Feld[lx][ly];
1335 content = Store[lx][ly];
1337 if (IS_MOVING(lx, ly))
1339 int horiz_move = (MovDir[lx][ly] == MV_LEFT || MovDir[lx][ly] == MV_RIGHT);
1340 boolean cut_mode = NO_CUTTING;
1342 if (element == EL_QUICKSAND_EMPTYING ||
1343 element == EL_MAGIC_WALL_EMPTYING ||
1344 element == EL_BD_MAGIC_WALL_EMPTYING ||
1345 element == EL_AMOEBA_DROPPING)
1346 cut_mode = CUT_ABOVE;
1347 else if (element == EL_QUICKSAND_FILLING ||
1348 element == EL_MAGIC_WALL_FILLING ||
1349 element == EL_BD_MAGIC_WALL_FILLING)
1350 cut_mode = CUT_BELOW;
1352 if (cut_mode == CUT_ABOVE)
1353 DrawScreenElementShifted(x, y, 0, 0, element, NO_CUTTING);
1355 DrawScreenElement(x, y, EL_EMPTY);
1358 DrawScreenElementShifted(x, y, MovPos[lx][ly], 0, element, NO_CUTTING);
1359 else if (cut_mode == NO_CUTTING)
1360 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], element, cut_mode);
1362 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], content, cut_mode);
1364 if (content == EL_ACID)
1365 DrawLevelElementThruMask(lx, ly + 1, EL_ACID);
1367 else if (IS_BLOCKED(lx, ly))
1372 boolean cut_mode = NO_CUTTING;
1373 int element_old, content_old;
1375 Blocked2Moving(lx, ly, &oldx, &oldy);
1378 horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
1379 MovDir[oldx][oldy] == MV_RIGHT);
1381 element_old = Feld[oldx][oldy];
1382 content_old = Store[oldx][oldy];
1384 if (element_old == EL_QUICKSAND_EMPTYING ||
1385 element_old == EL_MAGIC_WALL_EMPTYING ||
1386 element_old == EL_BD_MAGIC_WALL_EMPTYING ||
1387 element_old == EL_AMOEBA_DROPPING)
1388 cut_mode = CUT_ABOVE;
1390 DrawScreenElement(x, y, EL_EMPTY);
1393 DrawScreenElementShifted(sx, sy, MovPos[oldx][oldy], 0, element_old,
1395 else if (cut_mode == NO_CUTTING)
1396 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], element_old,
1399 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], content_old,
1402 else if (IS_DRAWABLE(element))
1403 DrawScreenElement(x, y, element);
1405 DrawScreenElement(x, y, EL_EMPTY);
1408 void DrawLevelField(int x, int y)
1410 if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1411 DrawScreenField(SCREENX(x), SCREENY(y));
1412 else if (IS_MOVING(x, y))
1416 Moving2Blocked(x, y, &newx, &newy);
1417 if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
1418 DrawScreenField(SCREENX(newx), SCREENY(newy));
1420 else if (IS_BLOCKED(x, y))
1424 Blocked2Moving(x, y, &oldx, &oldy);
1425 if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
1426 DrawScreenField(SCREENX(oldx), SCREENY(oldy));
1430 void DrawMiniElement(int x, int y, int element)
1434 graphic = el2edimg(element);
1435 DrawMiniGraphic(x, y, graphic);
1438 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
1440 int x = sx + scroll_x, y = sy + scroll_y;
1442 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
1443 DrawMiniElement(sx, sy, EL_EMPTY);
1444 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
1445 DrawMiniElement(sx, sy, Feld[x][y]);
1447 DrawMiniGraphic(sx, sy, el2edimg(getBorderElement(x, y)));
1450 void getMicroGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
1452 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
1453 int mini_startx = src_bitmap->width * 3 / 4;
1454 int mini_starty = src_bitmap->height * 2 / 3;
1455 int src_x = mini_startx + graphic_info[graphic].src_x / 8;
1456 int src_y = mini_starty + graphic_info[graphic].src_y / 8;
1458 if (src_x + MICRO_TILEX > src_bitmap->width ||
1459 src_y + MICRO_TILEY > src_bitmap->height)
1461 /* graphic of desired size seems not to be contained in this image;
1462 dirty workaround: get it from the middle of the normal sized image */
1464 getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
1465 src_x += (TILEX / 2 - MICRO_TILEX / 2);
1466 src_y += (TILEY / 2 - MICRO_TILEY / 2);
1469 *bitmap = src_bitmap;
1474 void DrawMicroElement(int xpos, int ypos, int element)
1478 int graphic = el2preimg(element);
1480 getMicroGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
1481 BlitBitmap(src_bitmap, drawto, src_x, src_y, MICRO_TILEX, MICRO_TILEY,
1489 SetDrawBackgroundMask(REDRAW_NONE);
1492 for(x=BX1; x<=BX2; x++)
1493 for(y=BY1; y<=BY2; y++)
1494 DrawScreenField(x, y);
1496 redraw_mask |= REDRAW_FIELD;
1499 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
1503 for(x=0; x<size_x; x++)
1504 for(y=0; y<size_y; y++)
1505 DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
1507 redraw_mask |= REDRAW_FIELD;
1510 static void DrawMicroLevelExt(int xpos, int ypos, int from_x, int from_y)
1514 DrawBackground(xpos, ypos, MICROLEV_XSIZE, MICROLEV_YSIZE);
1516 if (lev_fieldx < STD_LEV_FIELDX)
1517 xpos += (STD_LEV_FIELDX - lev_fieldx) / 2 * MICRO_TILEX;
1518 if (lev_fieldy < STD_LEV_FIELDY)
1519 ypos += (STD_LEV_FIELDY - lev_fieldy) / 2 * MICRO_TILEY;
1521 xpos += MICRO_TILEX;
1522 ypos += MICRO_TILEY;
1524 for(x=-1; x<=STD_LEV_FIELDX; x++)
1526 for(y=-1; y<=STD_LEV_FIELDY; y++)
1528 int lx = from_x + x, ly = from_y + y;
1530 if (lx >= 0 && lx < lev_fieldx && ly >= 0 && ly < lev_fieldy)
1531 DrawMicroElement(xpos + x * MICRO_TILEX, ypos + y * MICRO_TILEY,
1533 else if (lx >= -1 && lx < lev_fieldx+1 && ly >= -1 && ly < lev_fieldy+1
1534 && BorderElement != EL_EMPTY)
1535 DrawMicroElement(xpos + x * MICRO_TILEX, ypos + y * MICRO_TILEY,
1536 getBorderElement(lx, ly));
1540 redraw_mask |= REDRAW_MICROLEVEL;
1543 #define MICROLABEL_EMPTY 0
1544 #define MICROLABEL_LEVEL_NAME 1
1545 #define MICROLABEL_CREATED_BY 2
1546 #define MICROLABEL_LEVEL_AUTHOR 3
1547 #define MICROLABEL_IMPORTED_FROM 4
1548 #define MICROLABEL_LEVEL_IMPORT_INFO 5
1550 static void DrawMicroLevelLabelExt(int mode)
1552 char label_text[MAX_OUTPUT_LINESIZE + 1];
1553 int max_len_label_text;
1554 int font_nr = FONT_TEXT_2;
1556 if (mode == MICROLABEL_CREATED_BY || mode == MICROLABEL_IMPORTED_FROM)
1557 font_nr = FONT_TEXT_3;
1559 max_len_label_text = SXSIZE / getFontWidth(font_nr);
1561 DrawBackground(SX, MICROLABEL_YPOS, SXSIZE, getFontHeight(font_nr));
1563 strncpy(label_text, (mode == MICROLABEL_LEVEL_NAME ? level.name :
1564 mode == MICROLABEL_CREATED_BY ? "created by" :
1565 mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
1566 mode == MICROLABEL_IMPORTED_FROM ? "imported from" :
1567 mode == MICROLABEL_LEVEL_IMPORT_INFO ?
1568 leveldir_current->imported_from : ""),
1569 max_len_label_text);
1570 label_text[max_len_label_text] = '\0';
1572 if (strlen(label_text) > 0)
1574 int text_width = strlen(label_text) * getFontWidth(font_nr);
1575 int lxpos = SX + (SXSIZE - text_width) / 2;
1576 int lypos = MICROLABEL_YPOS;
1578 DrawText(lxpos, lypos, label_text, font_nr);
1581 redraw_mask |= REDRAW_MICROLEVEL;
1584 void DrawMicroLevel(int xpos, int ypos, boolean restart)
1586 static unsigned long scroll_delay = 0;
1587 static unsigned long label_delay = 0;
1588 static int from_x, from_y, scroll_direction;
1589 static int label_state, label_counter;
1590 int last_game_status = game_status; /* save current game status */
1592 game_status = PSEUDO_PREVIEW; /* force PREVIEW font on preview level */
1596 from_x = from_y = 0;
1597 scroll_direction = MV_RIGHT;
1601 DrawMicroLevelExt(xpos, ypos, from_x, from_y);
1602 DrawMicroLevelLabelExt(label_state);
1604 /* initialize delay counters */
1605 DelayReached(&scroll_delay, 0);
1606 DelayReached(&label_delay, 0);
1608 if (leveldir_current->name)
1610 int len = strlen(leveldir_current->name);
1611 int lxpos = SX + (SXSIZE - len * getFontWidth(FONT_TEXT_1)) / 2;
1612 int lypos = SY + 352;
1614 DrawText(lxpos, lypos, leveldir_current->name, FONT_TEXT_1);
1617 game_status = last_game_status; /* restore current game status */
1622 /* scroll micro level, if needed */
1623 if ((lev_fieldx > STD_LEV_FIELDX || lev_fieldy > STD_LEV_FIELDY) &&
1624 DelayReached(&scroll_delay, MICROLEVEL_SCROLL_DELAY))
1626 switch (scroll_direction)
1632 scroll_direction = MV_UP;
1636 if (from_x < lev_fieldx - STD_LEV_FIELDX)
1639 scroll_direction = MV_DOWN;
1646 scroll_direction = MV_RIGHT;
1650 if (from_y < lev_fieldy - STD_LEV_FIELDY)
1653 scroll_direction = MV_LEFT;
1660 DrawMicroLevelExt(xpos, ypos, from_x, from_y);
1663 /* redraw micro level label, if needed */
1664 if (strcmp(level.name, NAMELESS_LEVEL_NAME) != 0 &&
1665 strcmp(level.author, ANONYMOUS_NAME) != 0 &&
1666 strcmp(level.author, leveldir_current->name) != 0 &&
1667 DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
1669 int max_label_counter = 23;
1671 if (leveldir_current->imported_from != NULL)
1672 max_label_counter += 14;
1674 label_counter = (label_counter + 1) % max_label_counter;
1675 label_state = (label_counter >= 0 && label_counter <= 7 ?
1676 MICROLABEL_LEVEL_NAME :
1677 label_counter >= 9 && label_counter <= 12 ?
1678 MICROLABEL_CREATED_BY :
1679 label_counter >= 14 && label_counter <= 21 ?
1680 MICROLABEL_LEVEL_AUTHOR :
1681 label_counter >= 23 && label_counter <= 26 ?
1682 MICROLABEL_IMPORTED_FROM :
1683 label_counter >= 28 && label_counter <= 35 ?
1684 MICROLABEL_LEVEL_IMPORT_INFO : MICROLABEL_EMPTY);
1685 DrawMicroLevelLabelExt(label_state);
1688 game_status = last_game_status; /* restore current game status */
1691 int REQ_in_range(int x, int y)
1693 if (y > DY+249 && y < DY+278)
1695 if (x > DX+1 && x < DX+48)
1697 else if (x > DX+51 && x < DX+98)
1703 #define MAX_REQUEST_LINES 13
1704 #define MAX_REQUEST_LINE_LEN 7
1706 boolean Request(char *text, unsigned int req_state)
1708 int mx, my, ty, result = -1;
1709 unsigned int old_door_state;
1710 int last_game_status = game_status; /* save current game status */
1712 #if defined(PLATFORM_UNIX)
1713 /* pause network game while waiting for request to answer */
1714 if (options.network &&
1715 game_status == PLAYING &&
1716 req_state & REQUEST_WAIT_FOR)
1717 SendToServer_PausePlaying();
1720 old_door_state = GetDoorState();
1724 CloseDoor(DOOR_CLOSE_1);
1726 /* save old door content */
1727 BlitBitmap(bitmap_db_door, bitmap_db_door,
1728 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
1729 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
1731 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
1733 /* clear door drawing field */
1734 DrawBackground(DX, DY, DXSIZE, DYSIZE);
1736 game_status = PSEUDO_DOOR; /* force DOOR font on preview level */
1738 /* write text for request */
1739 for(ty=0; ty < MAX_REQUEST_LINES; ty++)
1741 char text_line[MAX_REQUEST_LINE_LEN + 1];
1747 for(tl=0,tx=0; tx < MAX_REQUEST_LINE_LEN; tl++,tx++)
1750 if (!tc || tc == ' ')
1761 strncpy(text_line, text, tl);
1764 DrawText(DX + (DXSIZE - tl * getFontWidth(FONT_TEXT_2)) / 2,
1765 DY + 8 + ty * (getFontHeight(FONT_TEXT_2) + 2),
1766 text_line, FONT_TEXT_2);
1768 text += tl + (tc == ' ' ? 1 : 0);
1771 game_status = last_game_status; /* restore current game status */
1773 if (req_state & REQ_ASK)
1775 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
1776 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
1778 else if (req_state & REQ_CONFIRM)
1780 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
1782 else if (req_state & REQ_PLAYER)
1784 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
1785 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
1786 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
1787 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
1790 /* copy request gadgets to door backbuffer */
1791 BlitBitmap(drawto, bitmap_db_door,
1792 DX, DY, DXSIZE, DYSIZE,
1793 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
1795 OpenDoor(DOOR_OPEN_1);
1801 if (!(req_state & REQUEST_WAIT_FOR))
1803 SetDrawBackgroundMask(REDRAW_FIELD);
1808 if (game_status != MAINMENU)
1811 button_status = MB_RELEASED;
1813 request_gadget_id = -1;
1815 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
1827 case EVENT_BUTTONPRESS:
1828 case EVENT_BUTTONRELEASE:
1829 case EVENT_MOTIONNOTIFY:
1831 if (event.type == EVENT_MOTIONNOTIFY)
1833 if (!PointerInWindow(window))
1834 continue; /* window and pointer are on different screens */
1839 motion_status = TRUE;
1840 mx = ((MotionEvent *) &event)->x;
1841 my = ((MotionEvent *) &event)->y;
1845 motion_status = FALSE;
1846 mx = ((ButtonEvent *) &event)->x;
1847 my = ((ButtonEvent *) &event)->y;
1848 if (event.type == EVENT_BUTTONPRESS)
1849 button_status = ((ButtonEvent *) &event)->button;
1851 button_status = MB_RELEASED;
1854 /* this sets 'request_gadget_id' */
1855 HandleGadgets(mx, my, button_status);
1857 switch(request_gadget_id)
1859 case TOOL_CTRL_ID_YES:
1862 case TOOL_CTRL_ID_NO:
1865 case TOOL_CTRL_ID_CONFIRM:
1866 result = TRUE | FALSE;
1869 case TOOL_CTRL_ID_PLAYER_1:
1872 case TOOL_CTRL_ID_PLAYER_2:
1875 case TOOL_CTRL_ID_PLAYER_3:
1878 case TOOL_CTRL_ID_PLAYER_4:
1889 case EVENT_KEYPRESS:
1890 switch(GetEventKey((KeyEvent *)&event, TRUE))
1903 if (req_state & REQ_PLAYER)
1907 case EVENT_KEYRELEASE:
1908 ClearPlayerAction();
1912 HandleOtherEvents(&event);
1916 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
1918 int joy = AnyJoystick();
1920 if (joy & JOY_BUTTON_1)
1922 else if (joy & JOY_BUTTON_2)
1928 /* don't eat all CPU time */
1932 if (game_status != MAINMENU)
1937 if (!(req_state & REQ_STAY_OPEN))
1939 CloseDoor(DOOR_CLOSE_1);
1941 if (!(req_state & REQ_STAY_CLOSED) && (old_door_state & DOOR_OPEN_1))
1943 BlitBitmap(bitmap_db_door, bitmap_db_door,
1944 DOOR_GFX_PAGEX2,DOOR_GFX_PAGEY1, DXSIZE,DYSIZE,
1945 DOOR_GFX_PAGEX1,DOOR_GFX_PAGEY1);
1946 OpenDoor(DOOR_OPEN_1);
1952 SetDrawBackgroundMask(REDRAW_FIELD);
1954 #if defined(PLATFORM_UNIX)
1955 /* continue network game after request */
1956 if (options.network &&
1957 game_status == PLAYING &&
1958 req_state & REQUEST_WAIT_FOR)
1959 SendToServer_ContinuePlaying();
1965 unsigned int OpenDoor(unsigned int door_state)
1967 unsigned int new_door_state;
1969 if (door_state & DOOR_COPY_BACK)
1971 BlitBitmap(bitmap_db_door, bitmap_db_door,
1972 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE + VYSIZE,
1973 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
1974 door_state &= ~DOOR_COPY_BACK;
1977 new_door_state = MoveDoor(door_state);
1979 return(new_door_state);
1982 unsigned int CloseDoor(unsigned int door_state)
1984 unsigned int new_door_state;
1986 BlitBitmap(backbuffer, bitmap_db_door,
1987 DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
1988 BlitBitmap(backbuffer, bitmap_db_door,
1989 VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
1991 new_door_state = MoveDoor(door_state);
1993 return(new_door_state);
1996 unsigned int GetDoorState()
1998 return MoveDoor(DOOR_GET_STATE);
2001 unsigned int SetDoorState(unsigned int door_state)
2003 return MoveDoor(door_state | DOOR_SET_STATE);
2006 unsigned int MoveDoor(unsigned int door_state)
2008 static int door1 = DOOR_OPEN_1;
2009 static int door2 = DOOR_CLOSE_2;
2010 static unsigned long door_delay = 0;
2011 int x, start, stepsize = global.door_step_offset;
2012 unsigned long door_delay_value = global.door_step_delay;
2014 if (door_state == DOOR_GET_STATE)
2015 return(door1 | door2);
2017 if (door_state & DOOR_SET_STATE)
2019 if (door_state & DOOR_ACTION_1)
2020 door1 = door_state & DOOR_ACTION_1;
2021 if (door_state & DOOR_ACTION_2)
2022 door2 = door_state & DOOR_ACTION_2;
2024 return(door1 | door2);
2027 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
2028 door_state &= ~DOOR_OPEN_1;
2029 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
2030 door_state &= ~DOOR_CLOSE_1;
2031 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
2032 door_state &= ~DOOR_OPEN_2;
2033 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
2034 door_state &= ~DOOR_CLOSE_2;
2036 if (setup.quick_doors)
2039 door_delay_value = 0;
2041 StopSound(SND_DOOR_OPENING);
2042 StopSound(SND_DOOR_CLOSING);
2045 if (global.autoplay_leveldir)
2047 door_state |= DOOR_NO_DELAY;
2048 door_state &= ~DOOR_CLOSE_ALL;
2051 if (door_state & DOOR_ACTION)
2053 if (!(door_state & DOOR_NO_DELAY))
2055 /* opening door sound has priority over simultaneously closing door */
2056 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
2057 PlaySoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
2058 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
2059 PlaySoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
2062 start = ((door_state & DOOR_NO_DELAY) ? DXSIZE : 0);
2064 for(x=start; x<=DXSIZE; x+=stepsize)
2066 Bitmap *bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
2067 GC gc = bitmap->stored_clip_gc;
2069 if (!(door_state & DOOR_NO_DELAY))
2070 WaitUntilDelayReached(&door_delay, door_delay_value);
2072 if (door_state & DOOR_ACTION_1)
2074 int i = (door_state & DOOR_OPEN_1 ? DXSIZE-x : x);
2075 int j = (DXSIZE - i) / 3;
2077 BlitBitmap(bitmap_db_door, drawto,
2078 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + i/2,
2079 DXSIZE,DYSIZE - i/2, DX, DY);
2081 ClearRectangle(drawto, DX, DY + DYSIZE - i/2, DXSIZE,i/2);
2083 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2084 BlitBitmapMasked(bitmap, drawto,
2085 DXSIZE, DOOR_GFX_PAGEY1, i, 77,
2086 DX + DXSIZE - i, DY + j);
2087 BlitBitmapMasked(bitmap, drawto,
2088 DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63,
2089 DX + DXSIZE - i, DY + 140 + j);
2090 SetClipOrigin(bitmap, gc, DX - DXSIZE + i, DY - (DOOR_GFX_PAGEY1 + j));
2091 BlitBitmapMasked(bitmap, drawto,
2092 DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j,
2094 BlitBitmapMasked(bitmap, drawto,
2095 DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63,
2098 BlitBitmapMasked(bitmap, drawto,
2099 DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
2101 BlitBitmapMasked(bitmap, drawto,
2102 DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
2104 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2105 BlitBitmapMasked(bitmap, drawto,
2106 DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
2107 DX + DXSIZE - i, DY + 77 + j);
2108 BlitBitmapMasked(bitmap, drawto,
2109 DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
2110 DX + DXSIZE - i, DY + 203 + j);
2112 redraw_mask |= REDRAW_DOOR_1;
2115 if (door_state & DOOR_ACTION_2)
2117 int i = (door_state & DOOR_OPEN_2 ? VXSIZE - x : x);
2118 int j = (VXSIZE - i) / 3;
2120 BlitBitmap(bitmap_db_door, drawto,
2121 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + i/2,
2122 VXSIZE, VYSIZE - i/2, VX, VY);
2124 ClearRectangle(drawto, VX, VY + VYSIZE-i/2, VXSIZE, i/2);
2126 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2127 BlitBitmapMasked(bitmap, drawto,
2128 VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2,
2129 VX + VXSIZE-i, VY+j);
2130 SetClipOrigin(bitmap, gc,
2131 VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
2132 BlitBitmapMasked(bitmap, drawto,
2133 VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j,
2136 BlitBitmapMasked(bitmap, drawto,
2137 VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2,
2138 i, VYSIZE / 2, VX, VY + VYSIZE / 2 - j);
2139 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2140 BlitBitmapMasked(bitmap, drawto,
2141 VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2,
2143 VX + VXSIZE - i, VY + VYSIZE / 2 + j);
2145 redraw_mask |= REDRAW_DOOR_2;
2150 if (game_status == MAINMENU)
2155 if (setup.quick_doors)
2157 StopSound(SND_DOOR_OPENING);
2158 StopSound(SND_DOOR_CLOSING);
2161 if (door_state & DOOR_ACTION_1)
2162 door1 = door_state & DOOR_ACTION_1;
2163 if (door_state & DOOR_ACTION_2)
2164 door2 = door_state & DOOR_ACTION_2;
2166 return (door1 | door2);
2169 void DrawSpecialEditorDoor()
2171 /* draw bigger toolbox window */
2172 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
2173 DOOR_GFX_PAGEX7, 0, EXSIZE + 8, 8,
2175 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
2176 EX - 4, VY - 4, EXSIZE + 8, EYSIZE - VYSIZE + 4,
2179 redraw_mask |= REDRAW_ALL;
2182 void UndrawSpecialEditorDoor()
2184 /* draw normal tape recorder window */
2185 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
2186 EX - 4, EY - 12, EXSIZE + 8, EYSIZE - VYSIZE + 12,
2189 redraw_mask |= REDRAW_ALL;
2193 /* ---------- new tool button stuff ---------------------------------------- */
2195 /* graphic position values for tool buttons */
2196 #define TOOL_BUTTON_YES_XPOS 2
2197 #define TOOL_BUTTON_YES_YPOS 250
2198 #define TOOL_BUTTON_YES_GFX_YPOS 0
2199 #define TOOL_BUTTON_YES_XSIZE 46
2200 #define TOOL_BUTTON_YES_YSIZE 28
2201 #define TOOL_BUTTON_NO_XPOS 52
2202 #define TOOL_BUTTON_NO_YPOS TOOL_BUTTON_YES_YPOS
2203 #define TOOL_BUTTON_NO_GFX_YPOS TOOL_BUTTON_YES_GFX_YPOS
2204 #define TOOL_BUTTON_NO_XSIZE TOOL_BUTTON_YES_XSIZE
2205 #define TOOL_BUTTON_NO_YSIZE TOOL_BUTTON_YES_YSIZE
2206 #define TOOL_BUTTON_CONFIRM_XPOS TOOL_BUTTON_YES_XPOS
2207 #define TOOL_BUTTON_CONFIRM_YPOS TOOL_BUTTON_YES_YPOS
2208 #define TOOL_BUTTON_CONFIRM_GFX_YPOS 30
2209 #define TOOL_BUTTON_CONFIRM_XSIZE 96
2210 #define TOOL_BUTTON_CONFIRM_YSIZE TOOL_BUTTON_YES_YSIZE
2211 #define TOOL_BUTTON_PLAYER_XSIZE 30
2212 #define TOOL_BUTTON_PLAYER_YSIZE 30
2213 #define TOOL_BUTTON_PLAYER_GFX_XPOS 5
2214 #define TOOL_BUTTON_PLAYER_GFX_YPOS 185
2215 #define TOOL_BUTTON_PLAYER_XPOS (5 + TOOL_BUTTON_PLAYER_XSIZE / 2)
2216 #define TOOL_BUTTON_PLAYER_YPOS (215 - TOOL_BUTTON_PLAYER_YSIZE / 2)
2217 #define TOOL_BUTTON_PLAYER1_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2218 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2219 #define TOOL_BUTTON_PLAYER2_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2220 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2221 #define TOOL_BUTTON_PLAYER3_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2222 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2223 #define TOOL_BUTTON_PLAYER4_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2224 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2225 #define TOOL_BUTTON_PLAYER1_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2226 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2227 #define TOOL_BUTTON_PLAYER2_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2228 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2229 #define TOOL_BUTTON_PLAYER3_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2230 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2231 #define TOOL_BUTTON_PLAYER4_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2232 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2241 } toolbutton_info[NUM_TOOL_BUTTONS] =
2244 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_GFX_YPOS,
2245 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_YPOS,
2246 TOOL_BUTTON_YES_XSIZE, TOOL_BUTTON_YES_YSIZE,
2251 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_GFX_YPOS,
2252 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_YPOS,
2253 TOOL_BUTTON_NO_XSIZE, TOOL_BUTTON_NO_YSIZE,
2258 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_GFX_YPOS,
2259 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_YPOS,
2260 TOOL_BUTTON_CONFIRM_XSIZE, TOOL_BUTTON_CONFIRM_YSIZE,
2261 TOOL_CTRL_ID_CONFIRM,
2265 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2266 TOOL_BUTTON_PLAYER1_XPOS, TOOL_BUTTON_PLAYER1_YPOS,
2267 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2268 TOOL_CTRL_ID_PLAYER_1,
2272 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2273 TOOL_BUTTON_PLAYER2_XPOS, TOOL_BUTTON_PLAYER2_YPOS,
2274 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2275 TOOL_CTRL_ID_PLAYER_2,
2279 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2280 TOOL_BUTTON_PLAYER3_XPOS, TOOL_BUTTON_PLAYER3_YPOS,
2281 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2282 TOOL_CTRL_ID_PLAYER_3,
2286 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2287 TOOL_BUTTON_PLAYER4_XPOS, TOOL_BUTTON_PLAYER4_YPOS,
2288 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2289 TOOL_CTRL_ID_PLAYER_4,
2294 void CreateToolButtons()
2298 for (i=0; i<NUM_TOOL_BUTTONS; i++)
2300 Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
2301 Bitmap *deco_bitmap = None;
2302 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
2303 struct GadgetInfo *gi;
2304 unsigned long event_mask;
2305 int gd_xoffset, gd_yoffset;
2306 int gd_x1, gd_x2, gd_y;
2309 event_mask = GD_EVENT_RELEASED;
2311 gd_xoffset = toolbutton_info[i].xpos;
2312 gd_yoffset = toolbutton_info[i].ypos;
2313 gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
2314 gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
2315 gd_y = DOOR_GFX_PAGEY1 + gd_yoffset;
2317 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
2319 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
2321 getMiniGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr),
2322 &deco_bitmap, &deco_x, &deco_y);
2323 deco_xpos = (toolbutton_info[i].width - MINI_TILEX) / 2;
2324 deco_ypos = (toolbutton_info[i].height - MINI_TILEY) / 2;
2327 gi = CreateGadget(GDI_CUSTOM_ID, id,
2328 GDI_INFO_TEXT, toolbutton_info[i].infotext,
2329 GDI_X, DX + toolbutton_info[i].x,
2330 GDI_Y, DY + toolbutton_info[i].y,
2331 GDI_WIDTH, toolbutton_info[i].width,
2332 GDI_HEIGHT, toolbutton_info[i].height,
2333 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
2334 GDI_STATE, GD_BUTTON_UNPRESSED,
2335 GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
2336 GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
2337 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
2338 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
2339 GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
2340 GDI_DECORATION_SHIFTING, 1, 1,
2341 GDI_EVENT_MASK, event_mask,
2342 GDI_CALLBACK_ACTION, HandleToolButtons,
2346 Error(ERR_EXIT, "cannot create gadget");
2348 tool_gadget[id] = gi;
2352 void FreeToolButtons()
2356 for (i=0; i<NUM_TOOL_BUTTONS; i++)
2357 FreeGadget(tool_gadget[i]);
2360 static void UnmapToolButtons()
2364 for (i=0; i<NUM_TOOL_BUTTONS; i++)
2365 UnmapGadget(tool_gadget[i]);
2368 static void HandleToolButtons(struct GadgetInfo *gi)
2370 request_gadget_id = gi->custom_id;
2373 int get_next_element(int element)
2377 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
2378 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
2379 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
2380 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
2381 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
2382 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
2383 case EL_AMOEBA_DROPPING: return EL_AMOEBA_WET;
2385 default: return element;
2389 int el_act_dir2img(int element, int action, int direction)
2391 direction = MV_DIR_BIT(direction);
2393 return element_info[element].direction_graphic[action][direction];
2396 int el_act2img(int element, int action)
2398 return element_info[element].graphic[action];
2401 int el_dir2img(int element, int direction)
2403 return el_act_dir2img(element, ACTION_DEFAULT, direction);
2406 int el2img(int element)
2408 return element_info[element].graphic[ACTION_DEFAULT];
2411 int el2edimg(int element)
2413 return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
2416 int el2preimg(int element)
2418 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];