1 /***********************************************************
2 * Rocks'n'Diamonds -- McDuffin Strikes Back! *
3 *----------------------------------------------------------*
4 * (c) 1995-2002 Artsoft Entertainment *
6 * Detmolder Strasse 189 *
9 * e-mail: info@artsoft.org *
10 *----------------------------------------------------------*
12 ***********************************************************/
14 #include "libgame/libgame.h"
23 /* tool button identifiers */
24 #define TOOL_CTRL_ID_YES 0
25 #define TOOL_CTRL_ID_NO 1
26 #define TOOL_CTRL_ID_CONFIRM 2
27 #define TOOL_CTRL_ID_PLAYER_1 3
28 #define TOOL_CTRL_ID_PLAYER_2 4
29 #define TOOL_CTRL_ID_PLAYER_3 5
30 #define TOOL_CTRL_ID_PLAYER_4 6
32 #define NUM_TOOL_BUTTONS 7
34 /* forward declaration for internal use */
35 static void UnmapToolButtons();
36 static void HandleToolButtons(struct GadgetInfo *);
38 static struct GadgetInfo *tool_gadget[NUM_TOOL_BUTTONS];
39 static int request_gadget_id = -1;
41 void SetDrawtoField(int mode)
43 if (mode == DRAW_BUFFERED && setup.soft_scrolling)
54 drawto_field = fieldbuffer;
56 else /* DRAW_DIRECT, DRAW_BACKBUFFER */
67 drawto_field = (mode == DRAW_DIRECT ? window : backbuffer);
71 void RedrawPlayfield(boolean force_redraw, int x, int y, int width, int height)
73 if (game_status == PLAYING)
79 width = gfx.sxsize + 2 * TILEX;
80 height = gfx.sysize + 2 * TILEY;
83 if (force_redraw || setup.direct_draw)
86 int x1 = (x - SX) / TILEX, y1 = (y - SY) / TILEY;
87 int x2 = (x - SX + width) / TILEX, y2 = (y - SY + height) / TILEY;
89 if (setup.direct_draw)
90 SetDrawtoField(DRAW_BACKBUFFER);
92 for(xx=BX1; xx<=BX2; xx++)
93 for(yy=BY1; yy<=BY2; yy++)
94 if (xx >= x1 && xx <= x2 && yy >= y1 && yy <= y2)
95 DrawScreenField(xx, yy);
98 if (setup.direct_draw)
99 SetDrawtoField(DRAW_DIRECT);
102 if (setup.soft_scrolling)
104 int fx = FX, fy = FY;
106 fx += (ScreenMovDir & (MV_LEFT|MV_RIGHT) ? ScreenGfxPos : 0);
107 fy += (ScreenMovDir & (MV_UP|MV_DOWN) ? ScreenGfxPos : 0);
109 BlitBitmap(fieldbuffer, backbuffer, fx,fy, SXSIZE,SYSIZE, SX,SY);
113 BlitBitmap(drawto, window, x, y, width, height, x, y);
119 DrawBuffer *buffer = (drawto_field == window ? backbuffer : drawto_field);
121 if (setup.direct_draw && game_status == PLAYING)
122 redraw_mask &= ~REDRAW_MAIN;
124 if (redraw_mask & REDRAW_TILES && redraw_tiles > REDRAWTILES_THRESHOLD)
125 redraw_mask |= REDRAW_FIELD;
127 if (redraw_mask & REDRAW_FIELD)
128 redraw_mask &= ~REDRAW_TILES;
130 if (redraw_mask == REDRAW_NONE)
133 if (global.fps_slowdown && game_status == PLAYING)
135 static boolean last_frame_skipped = FALSE;
136 boolean skip_even_when_not_scrolling = TRUE;
137 boolean just_scrolling = (ScreenMovDir != 0);
138 boolean verbose = FALSE;
140 if (global.fps_slowdown_factor > 1 &&
141 (FrameCounter % global.fps_slowdown_factor) &&
142 (just_scrolling || skip_even_when_not_scrolling))
144 redraw_mask &= ~REDRAW_MAIN;
146 last_frame_skipped = TRUE;
149 printf("FRAME SKIPPED\n");
153 if (last_frame_skipped)
154 redraw_mask |= REDRAW_FIELD;
156 last_frame_skipped = FALSE;
159 printf("frame not skipped\n");
163 /* synchronize X11 graphics at this point; if we would synchronize the
164 display immediately after the buffer switching (after the XFlush),
165 this could mean that we have to wait for the graphics to complete,
166 although we could go on doing calculations for the next frame */
170 if (redraw_mask & REDRAW_ALL)
172 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
176 if (redraw_mask & REDRAW_FIELD)
178 if (game_status != PLAYING || redraw_mask & REDRAW_FROM_BACKBUFFER)
180 BlitBitmap(backbuffer, window,
181 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE, REAL_SX, REAL_SY);
185 int fx = FX, fy = FY;
187 if (setup.soft_scrolling)
189 fx += (ScreenMovDir & (MV_LEFT | MV_RIGHT) ? ScreenGfxPos : 0);
190 fy += (ScreenMovDir & (MV_UP | MV_DOWN) ? ScreenGfxPos : 0);
193 if (setup.soft_scrolling ||
194 ABS(ScreenMovPos) + ScrollStepSize == TILEX ||
195 ABS(ScreenMovPos) == ScrollStepSize ||
196 redraw_tiles > REDRAWTILES_THRESHOLD)
198 BlitBitmap(buffer, window, fx, fy, SXSIZE, SYSIZE, SX, SY);
202 printf("redrawing all (ScreenGfxPos == %d) because %s\n",
204 (setup.soft_scrolling ?
205 "setup.soft_scrolling" :
206 ABS(ScreenGfxPos) + ScrollStepSize == TILEX ?
207 "ABS(ScreenGfxPos) + ScrollStepSize == TILEX" :
208 ABS(ScreenGfxPos) == ScrollStepSize ?
209 "ABS(ScreenGfxPos) == ScrollStepSize" :
210 "redraw_tiles > REDRAWTILES_THRESHOLD"));
216 redraw_mask &= ~REDRAW_MAIN;
219 if (redraw_mask & REDRAW_DOORS)
221 if (redraw_mask & REDRAW_DOOR_1)
222 BlitBitmap(backbuffer, window, DX, DY, DXSIZE, DYSIZE, DX, DY);
223 if (redraw_mask & REDRAW_DOOR_2)
225 if ((redraw_mask & REDRAW_DOOR_2) == REDRAW_DOOR_2)
226 BlitBitmap(backbuffer, window, VX,VY, VXSIZE,VYSIZE, VX,VY);
229 if (redraw_mask & REDRAW_VIDEO_1)
230 BlitBitmap(backbuffer, window,
231 VX+VIDEO_DISPLAY1_XPOS,VY+VIDEO_DISPLAY1_YPOS,
232 VIDEO_DISPLAY_XSIZE,VIDEO_DISPLAY_YSIZE,
233 VX+VIDEO_DISPLAY1_XPOS,VY+VIDEO_DISPLAY1_YPOS);
234 if (redraw_mask & REDRAW_VIDEO_2)
235 BlitBitmap(backbuffer, window,
236 VX+VIDEO_DISPLAY2_XPOS,VY+VIDEO_DISPLAY2_YPOS,
237 VIDEO_DISPLAY_XSIZE,VIDEO_DISPLAY_YSIZE,
238 VX+VIDEO_DISPLAY2_XPOS,VY+VIDEO_DISPLAY2_YPOS);
239 if (redraw_mask & REDRAW_VIDEO_3)
240 BlitBitmap(backbuffer, window,
241 VX+VIDEO_CONTROL_XPOS,VY+VIDEO_CONTROL_YPOS,
242 VIDEO_CONTROL_XSIZE,VIDEO_CONTROL_YSIZE,
243 VX+VIDEO_CONTROL_XPOS,VY+VIDEO_CONTROL_YPOS);
247 if (redraw_mask & REDRAW_DOOR_3)
248 BlitBitmap(backbuffer, window, EX, EY, EXSIZE, EYSIZE, EX, EY);
250 redraw_mask &= ~REDRAW_DOORS;
253 if (redraw_mask & REDRAW_MICROLEVEL)
255 BlitBitmap(backbuffer, window, SX, SY + 10 * TILEY, SXSIZE, 7 * TILEY,
256 SX, SY + 10 * TILEY);
258 redraw_mask &= ~REDRAW_MICROLEVEL;
261 if (redraw_mask & REDRAW_TILES)
263 for(x=0; x<SCR_FIELDX; x++)
264 for(y=0; y<SCR_FIELDY; y++)
265 if (redraw[redraw_x1 + x][redraw_y1 + y])
266 BlitBitmap(buffer, window,
267 FX + x * TILEX, FX + y * TILEY, TILEX, TILEY,
268 SX + x * TILEX, SY + y * TILEY);
271 if (redraw_mask & REDRAW_FPS) /* display frames per second */
276 sprintf(info1, " (only every %d. frame)", global.fps_slowdown_factor);
277 if (!global.fps_slowdown)
280 sprintf(text, "%.1f fps%s", global.frames_per_second, info1);
281 DrawTextExt(window, SX, SY, text, FONT_TEXT_2, BLIT_OPAQUE);
286 for(x=0; x<MAX_BUF_XSIZE; x++)
287 for(y=0; y<MAX_BUF_YSIZE; y++)
290 redraw_mask = REDRAW_NONE;
296 long fading_delay = 300;
298 if (setup.fading && (redraw_mask & REDRAW_FIELD))
305 ClearRectangle(window, REAL_SX,REAL_SY,FULL_SXSIZE,FULL_SYSIZE);
308 for(i=0;i<2*FULL_SYSIZE;i++)
310 for(y=0;y<FULL_SYSIZE;y++)
312 BlitBitmap(backbuffer, window,
313 REAL_SX,REAL_SY+i, FULL_SXSIZE,1, REAL_SX,REAL_SY+i);
321 for(i=1;i<FULL_SYSIZE;i+=2)
322 BlitBitmap(backbuffer, window,
323 REAL_SX,REAL_SY+i, FULL_SXSIZE,1, REAL_SX,REAL_SY+i);
329 SetClipOrigin(clip_gc[PIX_FADEMASK], 0, 0);
330 BlitBitmapMasked(backbuffer, window,
331 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
336 SetClipOrigin(clip_gc[PIX_FADEMASK], -1, -1);
337 BlitBitmapMasked(backbuffer, window,
338 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
343 SetClipOrigin(clip_gc[PIX_FADEMASK], 0, -1);
344 BlitBitmapMasked(backbuffer, window,
345 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
350 SetClipOrigin(clip_gc[PIX_FADEMASK], -1, 0);
351 BlitBitmapMasked(backbuffer, window,
352 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
357 redraw_mask &= ~REDRAW_MAIN;
364 void SetMainBackgroundImage(int graphic)
366 SetMainBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
367 graphic_info[graphic].bitmap ?
368 graphic_info[graphic].bitmap :
369 graphic_info[IMG_BACKGROUND].bitmap);
372 void SetDoorBackgroundImage(int graphic)
374 SetDoorBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
375 graphic_info[graphic].bitmap ?
376 graphic_info[graphic].bitmap :
377 graphic_info[IMG_BACKGROUND].bitmap);
380 void DrawBackground(int dest_x, int dest_y, int width, int height)
382 ClearRectangleOnBackground(backbuffer, dest_x, dest_y, width, height);
384 redraw_mask |= REDRAW_FIELD;
389 DrawBackground(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
391 if (setup.soft_scrolling && game_status == PLAYING)
393 ClearRectangle(fieldbuffer, 0, 0, FXSIZE, FYSIZE);
394 SetDrawtoField(DRAW_BUFFERED);
397 SetDrawtoField(DRAW_BACKBUFFER);
399 if (setup.direct_draw && game_status == PLAYING)
401 ClearRectangle(window, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
402 SetDrawtoField(DRAW_DIRECT);
406 void MarkTileDirty(int x, int y)
408 int xx = redraw_x1 + x;
409 int yy = redraw_y1 + y;
414 redraw[xx][yy] = TRUE;
415 redraw_mask |= REDRAW_TILES;
418 void SetBorderElement()
422 BorderElement = EL_EMPTY;
424 for(y=0; y<lev_fieldy && BorderElement == EL_EMPTY; y++)
426 for(x=0; x<lev_fieldx; x++)
428 if (!IS_INDESTRUCTIBLE(Feld[x][y]))
429 BorderElement = EL_STEELWALL;
431 if (y != 0 && y != lev_fieldy - 1 && x != lev_fieldx - 1)
437 void SetRandomAnimationValue(int x, int y)
439 gfx.anim_random_frame = GfxRandom[x][y];
442 inline int getGraphicAnimationFrame(int graphic, int sync_frame)
444 /* animation synchronized with global frame counter, not move position */
445 if (graphic_info[graphic].anim_global_sync || sync_frame < 0)
446 sync_frame = FrameCounter;
448 return getAnimationFrame(graphic_info[graphic].anim_frames,
449 graphic_info[graphic].anim_delay,
450 graphic_info[graphic].anim_mode,
451 graphic_info[graphic].anim_start_frame,
455 inline void DrawGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
456 int graphic, int sync_frame, int mask_mode)
458 int frame = getGraphicAnimationFrame(graphic, sync_frame);
460 if (mask_mode == USE_MASKING)
461 DrawGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
463 DrawGraphicExt(dst_bitmap, x, y, graphic, frame);
466 inline void DrawGraphicAnimation(int x, int y, int graphic)
468 int lx = LEVELX(x), ly = LEVELY(y);
470 if (!IN_SCR_FIELD(x, y))
473 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
474 graphic, GfxFrame[lx][ly], NO_MASKING);
478 void DrawLevelGraphicAnimation(int x, int y, int graphic)
480 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
483 void DrawLevelElementAnimation(int x, int y, int element)
485 DrawGraphicAnimation(SCREENX(x), SCREENY(y), el2img(element));
488 inline void DrawLevelGraphicAnimationIfNeeded(int x, int y, int graphic)
490 int sx = SCREENX(x), sy = SCREENY(y);
492 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
495 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
498 DrawGraphicAnimation(sx, sy, graphic);
501 void DrawLevelElementAnimationIfNeeded(int x, int y, int element)
503 int sx = SCREENX(x), sy = SCREENY(y);
506 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
509 graphic = el_act_dir2img(element, GfxAction[x][y], MovDir[x][y]);
511 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
514 DrawGraphicAnimation(sx, sy, graphic);
517 void DrawAllPlayers()
521 for(i=0; i<MAX_PLAYERS; i++)
522 if (stored_player[i].active)
523 DrawPlayer(&stored_player[i]);
526 void DrawPlayerField(int x, int y)
528 if (!IS_PLAYER(x, y))
531 DrawPlayer(PLAYERINFO(x, y));
534 void DrawPlayer(struct PlayerInfo *player)
536 int jx = player->jx, jy = player->jy;
537 int last_jx = player->last_jx, last_jy = player->last_jy;
538 int next_jx = jx + (jx - last_jx), next_jy = jy + (jy - last_jy);
539 int sx = SCREENX(jx), sy = SCREENY(jy);
540 int sxx = 0, syy = 0;
541 int element = Feld[jx][jy], last_element = Feld[last_jx][last_jy];
544 boolean player_is_moving = (last_jx != jx || last_jy != jy ? TRUE : FALSE);
545 int move_dir = player->MovDir;
546 int action = ACTION_DEFAULT;
548 if (!player->active || !IN_SCR_FIELD(SCREENX(last_jx), SCREENY(last_jy)))
552 if (!IN_LEV_FIELD(jx,jy))
554 printf("DrawPlayerField(): x = %d, y = %d\n",jx,jy);
555 printf("DrawPlayerField(): sx = %d, sy = %d\n",sx,sy);
556 printf("DrawPlayerField(): This should never happen!\n");
561 if (element == EL_EXPLOSION)
564 action = (player->Pushing ? ACTION_PUSHING :
565 player->is_digging ? ACTION_DIGGING :
566 player->is_collecting ? ACTION_COLLECTING :
567 player->is_moving ? ACTION_MOVING :
568 player->snapped ? ACTION_SNAPPING : ACTION_DEFAULT);
570 InitPlayerGfxAnimation(player, action, move_dir);
572 /* ----------------------------------------------------------------------- */
573 /* draw things in the field the player is leaving, if needed */
574 /* ----------------------------------------------------------------------- */
576 if (player_is_moving)
578 if (Store[last_jx][last_jy] && IS_DRAWABLE(last_element))
580 DrawLevelElement(last_jx, last_jy, Store[last_jx][last_jy]);
582 if (last_element == EL_DYNAMITE_ACTIVE ||
583 last_element == EL_SP_DISK_RED_ACTIVE)
584 DrawDynamite(last_jx, last_jy);
586 DrawLevelFieldThruMask(last_jx, last_jy);
588 else if (last_element == EL_DYNAMITE_ACTIVE ||
589 last_element == EL_SP_DISK_RED_ACTIVE)
590 DrawDynamite(last_jx, last_jy);
592 DrawLevelField(last_jx, last_jy);
594 if (player->Pushing && IN_SCR_FIELD(SCREENX(next_jx), SCREENY(next_jy)))
598 if (Feld[next_jx][next_jy] == EL_SOKOBAN_FIELD_FULL)
599 DrawLevelElement(next_jx, next_jy, EL_SOKOBAN_FIELD_EMPTY);
601 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
604 DrawLevelField(next_jx, next_jy);
608 if (!IN_SCR_FIELD(sx, sy))
611 if (setup.direct_draw)
612 SetDrawtoField(DRAW_BUFFERED);
614 /* ----------------------------------------------------------------------- */
615 /* draw things behind the player, if needed */
616 /* ----------------------------------------------------------------------- */
619 DrawLevelElement(jx, jy, Store[jx][jy]);
620 else if (IS_ACTIVE_BOMB(element))
621 DrawLevelElement(jx, jy, EL_EMPTY);
624 if (player_is_moving && GfxElement[jx][jy] != EL_UNDEFINED)
626 if (GfxElement[jx][jy] == EL_SAND)
627 DrawLevelFieldCrumbledSandDigging(jx, jy, move_dir, player->StepFrame);
630 int old_element = GfxElement[jx][jy];
631 int old_graphic = el_act_dir2img(old_element, action, move_dir);
632 int frame = getGraphicAnimationFrame(old_graphic, player->StepFrame);
634 DrawGraphic(sx, sy, old_graphic, frame);
639 GfxElement[jx][jy] = EL_UNDEFINED;
641 DrawLevelField(jx, jy);
645 /* ----------------------------------------------------------------------- */
646 /* draw player himself */
647 /* ----------------------------------------------------------------------- */
649 if (player->use_murphy_graphic)
651 static int last_horizontal_dir = MV_LEFT;
654 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
655 last_horizontal_dir = move_dir;
657 direction = (player->snapped ? move_dir : last_horizontal_dir);
659 graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, direction);
662 graphic = el_act_dir2img(player->element_nr, player->GfxAction, move_dir);
664 frame = getGraphicAnimationFrame(graphic, player->Frame);
668 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
669 sxx = player->GfxPos;
671 syy = player->GfxPos;
674 if (!setup.soft_scrolling && ScreenMovPos)
677 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
679 if (SHIELD_ON(player))
681 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
682 IMG_SHIELD_NORMAL_ACTIVE);
683 int frame = getGraphicAnimationFrame(graphic, -1);
685 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
688 /* ----------------------------------------------------------------------- */
689 /* draw things the player is pushing, if needed */
690 /* ----------------------------------------------------------------------- */
692 if (player->Pushing && player_is_moving)
694 int px = SCREENX(next_jx), py = SCREENY(next_jy);
697 (element == EL_SOKOBAN_FIELD_EMPTY ||
698 Feld[next_jx][next_jy] == EL_SOKOBAN_FIELD_FULL))
699 DrawGraphicShiftedThruMask(px, py, sxx, syy, IMG_SOKOBAN_OBJECT, 0,
703 int element = Feld[next_jx][next_jy];
704 int graphic = el2img(element);
707 if ((sxx || syy) && IS_PUSHABLE(element))
709 graphic = el_act_dir2img(element, ACTION_MOVING, move_dir);
710 frame = getGraphicAnimationFrame(graphic, player->Frame);
713 DrawGraphicShifted(px, py, sxx, syy, graphic, frame,
714 NO_CUTTING, NO_MASKING);
718 /* ----------------------------------------------------------------------- */
719 /* draw things in front of player (active dynamite or dynabombs) */
720 /* ----------------------------------------------------------------------- */
722 if (IS_ACTIVE_BOMB(element))
724 graphic = el2img(element);
725 frame = getGraphicAnimationFrame(graphic, GfxFrame[jx][jy]);
727 if (game.emulation == EMU_SUPAPLEX)
728 DrawGraphic(sx, sy, IMG_SP_DISK_RED, frame);
730 DrawGraphicThruMask(sx, sy, graphic, frame);
733 if (player_is_moving && last_element == EL_EXPLOSION)
735 int stored = Store[last_jx][last_jy];
736 int graphic = (game.emulation != EMU_SUPAPLEX ? IMG_EXPLOSION :
737 stored == EL_SP_INFOTRON ? IMG_SP_EXPLOSION_INFOTRON :
739 int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
740 int phase = ExplodePhase[last_jx][last_jy] - 1;
741 int frame = getGraphicAnimationFrame(graphic, phase - delay);
744 DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy), graphic, frame);
747 /* ----------------------------------------------------------------------- */
748 /* draw elements that stay over the player */
749 /* ----------------------------------------------------------------------- */
751 /* handle the field the player is leaving ... */
752 if (player_is_moving && IS_OVER_PLAYER(last_element))
753 DrawLevelField(last_jx, last_jy);
755 /* ... and the field the player is entering */
756 if (IS_OVER_PLAYER(element))
757 DrawLevelField(jx, jy);
759 if (setup.direct_draw)
761 int dest_x = SX + SCREENX(MIN(jx, last_jx)) * TILEX;
762 int dest_y = SY + SCREENY(MIN(jy, last_jy)) * TILEY;
763 int x_size = TILEX * (1 + ABS(jx - last_jx));
764 int y_size = TILEY * (1 + ABS(jy - last_jy));
766 BlitBitmap(drawto_field, window,
767 dest_x, dest_y, x_size, y_size, dest_x, dest_y);
768 SetDrawtoField(DRAW_DIRECT);
771 MarkTileDirty(sx,sy);
774 void getGraphicSource(int graphic, int frame, Bitmap **bitmap, int *x, int *y)
776 struct GraphicInfo *g = &graphic_info[graphic];
780 if (g->offset_y == 0) /* frames are ordered horizontally */
782 int max_width = g->anim_frames_per_line * g->width;
784 *x = (g->src_x + frame * g->offset_x) % max_width;
785 *y = g->src_y + (g->src_x + frame * g->offset_x) / max_width * g->height;
787 else if (g->offset_x == 0) /* frames are ordered vertically */
789 int max_height = g->anim_frames_per_line * g->height;
791 *x = g->src_x + (g->src_y + frame * g->offset_y) / max_height * g->width;
792 *y = (g->src_y + frame * g->offset_y) % max_height;
794 else /* frames are ordered diagonally */
796 *x = g->src_x + frame * g->offset_x;
797 *y = g->src_y + frame * g->offset_y;
801 void DrawGraphic(int x, int y, int graphic, int frame)
804 if (!IN_SCR_FIELD(x, y))
806 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
807 printf("DrawGraphic(): This should never happen!\n");
812 DrawGraphicExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic, frame);
817 void DrawOldGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic)
822 getOldGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
823 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
827 void DrawGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
834 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
836 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
837 int src_x = graphic_info[graphic].src_x;
838 int src_y = graphic_info[graphic].src_y;
839 int offset_x = graphic_info[graphic].offset_x;
840 int offset_y = graphic_info[graphic].offset_y;
842 src_x += frame * offset_x;
843 src_y += frame * offset_y;
846 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
849 void DrawGraphicThruMask(int x, int y, int graphic, int frame)
852 if (!IN_SCR_FIELD(x, y))
854 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
855 printf("DrawGraphicThruMask(): This should never happen!\n");
860 DrawGraphicThruMaskExt(drawto_field, FX + x * TILEX, FY + y *TILEY, graphic,
865 void DrawGraphicThruMaskExt(DrawBuffer *d, int dest_x, int dest_y, int graphic,
873 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
874 drawing_gc = src_bitmap->stored_clip_gc;
876 GC drawing_gc = src_bitmap->stored_clip_gc;
877 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
878 int src_x = graphic_info[graphic].src_x;
879 int src_y = graphic_info[graphic].src_y;
880 int offset_x = graphic_info[graphic].offset_x;
881 int offset_y = graphic_info[graphic].offset_y;
883 src_x += frame * offset_x;
884 src_y += frame * offset_y;
888 SetClipOrigin(src_bitmap, drawing_gc, dest_x - src_x, dest_y - src_y);
889 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX, TILEY, dest_x, dest_y);
892 void DrawMiniGraphic(int x, int y, int graphic)
894 DrawMiniGraphicExt(drawto, SX + x * MINI_TILEX,SY + y * MINI_TILEY, graphic);
895 MarkTileDirty(x / 2, y / 2);
898 void getMiniGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
900 struct GraphicInfo *g = &graphic_info[graphic];
902 int mini_starty = g->bitmap->height * 2 / 3;
905 *x = mini_startx + g->src_x / 2;
906 *y = mini_starty + g->src_y / 2;
909 void DrawMiniGraphicExt(DrawBuffer *d, int x, int y, int graphic)
914 getMiniGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
915 BlitBitmap(src_bitmap, d, src_x, src_y, MINI_TILEX, MINI_TILEY, x, y);
918 void DrawGraphicShifted(int x,int y, int dx,int dy, int graphic, int frame,
919 int cut_mode, int mask_mode)
928 int width = TILEX, height = TILEY;
934 DrawGraphic(x, y, graphic, frame);
938 if (dx || dy) /* shifted graphic */
940 if (x < BX1) /* object enters playfield from the left */
947 else if (x > BX2) /* object enters playfield from the right */
953 else if (x==BX1 && dx < 0) /* object leaves playfield to the left */
959 else if (x==BX2 && dx > 0) /* object leaves playfield to the right */
961 else if (dx) /* general horizontal movement */
962 MarkTileDirty(x + SIGN(dx), y);
964 if (y < BY1) /* object enters playfield from the top */
966 if (cut_mode==CUT_BELOW) /* object completely above top border */
974 else if (y > BY2) /* object enters playfield from the bottom */
980 else if (y==BY1 && dy < 0) /* object leaves playfield to the top */
986 else if (dy > 0 && cut_mode == CUT_ABOVE)
988 if (y == BY2) /* object completely above bottom border */
994 MarkTileDirty(x, y + 1);
995 } /* object leaves playfield to the bottom */
996 else if (dy > 0 && (y == BY2 || cut_mode == CUT_BELOW))
998 else if (dy) /* general vertical movement */
999 MarkTileDirty(x, y + SIGN(dy));
1002 src_bitmap = graphic_info[graphic].bitmap;
1003 src_x = graphic_info[graphic].src_x;
1004 src_y = graphic_info[graphic].src_y;
1005 offset_x = graphic_info[graphic].offset_x;
1006 offset_y = graphic_info[graphic].offset_y;
1008 drawing_gc = src_bitmap->stored_clip_gc;
1010 src_x += frame * offset_x;
1011 src_y += frame * offset_y;
1016 dest_x = FX + x * TILEX + dx;
1017 dest_y = FY + y * TILEY + dy;
1020 if (!IN_SCR_FIELD(x,y))
1022 printf("DrawGraphicShifted(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
1023 printf("DrawGraphicShifted(): This should never happen!\n");
1028 if (mask_mode == USE_MASKING)
1030 SetClipOrigin(src_bitmap, drawing_gc, dest_x - src_x, dest_y - src_y);
1031 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1035 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1041 void DrawGraphicShiftedThruMask(int x, int y, int dx, int dy, int graphic,
1042 int frame, int cut_mode)
1044 DrawGraphicShifted(x,y, dx,dy, graphic, frame, cut_mode, USE_MASKING);
1047 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
1048 int cut_mode, int mask_mode)
1050 int lx = LEVELX(x), ly = LEVELY(y);
1054 if (IN_LEV_FIELD(lx, ly))
1056 SetRandomAnimationValue(lx, ly);
1058 graphic = el_act_dir2img(element, GfxAction[lx][ly], MovDir[lx][ly]);
1059 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1061 else /* border element */
1063 graphic = el2img(element);
1064 frame = getGraphicAnimationFrame(graphic, -1);
1067 if (element == EL_EXPANDABLE_WALL)
1069 boolean left_stopped = FALSE, right_stopped = FALSE;
1071 if (!IN_LEV_FIELD(lx - 1, ly) || IS_MAUER(Feld[lx - 1][ly]))
1072 left_stopped = TRUE;
1073 if (!IN_LEV_FIELD(lx + 1, ly) || IS_MAUER(Feld[lx + 1][ly]))
1074 right_stopped = TRUE;
1076 if (left_stopped && right_stopped)
1078 else if (left_stopped)
1080 graphic = IMG_EXPANDABLE_WALL_GROWING_RIGHT;
1081 frame = graphic_info[graphic].anim_frames - 1;
1083 else if (right_stopped)
1085 graphic = IMG_EXPANDABLE_WALL_GROWING_LEFT;
1086 frame = graphic_info[graphic].anim_frames - 1;
1090 else if (IS_AMOEBOID(element) || element == EL_AMOEBA_DROPPING)
1092 graphic = (element == EL_BD_AMOEBA ? IMG_BD_AMOEBA_PART1 :
1093 element == EL_AMOEBA_WET ? IMG_AMOEBA_WET_PART1 :
1094 element == EL_AMOEBA_DRY ? IMG_AMOEBA_DRY_PART1 :
1095 element == EL_AMOEBA_FULL ? IMG_AMOEBA_FULL_PART1 :
1096 IMG_AMOEBA_DEAD_PART1);
1098 graphic += (x + 2 * y + 4) % 4;
1103 if (IS_AMOEBOID(element) || element == EL_AMOEBA_DROPPING)
1105 if (Feld[lx][ly] == EL_AMOEBA_DROPPING)
1106 printf("---> %d -> %d / %d [%d]\n",
1107 element, graphic, frame, GfxRandom[lx][ly]);
1112 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, mask_mode);
1113 else if (mask_mode == USE_MASKING)
1114 DrawGraphicThruMask(x, y, graphic, frame);
1116 DrawGraphic(x, y, graphic, frame);
1119 void DrawLevelElementExt(int x, int y, int dx, int dy, int element,
1120 int cut_mode, int mask_mode)
1122 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1123 DrawScreenElementExt(SCREENX(x), SCREENY(y), dx, dy, element,
1124 cut_mode, mask_mode);
1127 void DrawScreenElementShifted(int x, int y, int dx, int dy, int element,
1130 DrawScreenElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1133 void DrawLevelElementShifted(int x, int y, int dx, int dy, int element,
1136 DrawLevelElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1140 void DrawOldScreenElementThruMask(int x, int y, int element)
1142 DrawOldScreenElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1145 void DrawScreenElementThruMask(int x, int y, int element)
1147 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1151 void DrawLevelElementThruMask(int x, int y, int element)
1153 DrawLevelElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1156 void DrawLevelFieldThruMask(int x, int y)
1158 DrawLevelElementExt(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
1161 static void DrawLevelFieldCrumbledSandExt(int x, int y, int graphic, int frame)
1165 int sx = SCREENX(x), sy = SCREENY(y);
1167 int width, height, cx, cy, i;
1168 int snip = TILEX / 8; /* number of border pixels from "crumbled graphic" */
1169 static int xy[4][2] =
1177 if (!IN_LEV_FIELD(x, y))
1180 element = (GfxElement[x][y] != EL_UNDEFINED ? GfxElement[x][y] : Feld[x][y]);
1182 /* crumble field itself */
1183 if (CAN_BE_CRUMBLED(element))
1185 if (!IN_SCR_FIELD(sx, sy))
1188 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1192 int xx = x + xy[i][0];
1193 int yy = y + xy[i][1];
1195 element = (IN_LEV_FIELD(xx, yy) ? Feld[xx][yy] : EL_STEELWALL);
1197 if (CAN_BE_CRUMBLED(element)) /* neighbour is of same type */
1200 if (i == 1 || i == 2)
1204 cx = (i == 2 ? TILEX - snip : 0);
1212 cy = (i == 3 ? TILEY - snip : 0);
1215 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1216 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
1219 MarkTileDirty(sx, sy);
1221 else /* crumble neighbour fields */
1223 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1227 int xx = x + xy[i][0];
1228 int yy = y + xy[i][1];
1229 int sxx = sx + xy[i][0];
1230 int syy = sy + xy[i][1];
1232 if (!IN_LEV_FIELD(xx, yy) ||
1233 !IN_SCR_FIELD(sxx, syy) ||
1234 !CAN_BE_CRUMBLED(Feld[xx][yy]))
1237 if (i == 1 || i == 2)
1241 cx = (i == 1 ? TILEX - snip : 0);
1249 cy = (i==0 ? TILEY-snip : 0);
1252 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1253 width, height, FX + sxx * TILEX + cx, FY + syy * TILEY + cy);
1255 MarkTileDirty(sxx, syy);
1260 void DrawLevelFieldCrumbledSand(int x, int y)
1262 DrawLevelFieldCrumbledSandExt(x, y, IMG_SAND_CRUMBLED, 0);
1265 void DrawLevelFieldCrumbledSandDigging(int x, int y, int direction,
1268 int graphic1 = el_act_dir2img(EL_SAND, ACTION_DIGGING, direction);
1269 int graphic2 = el_act_dir2img(EL_SAND_CRUMBLED, ACTION_DIGGING, direction);
1270 int frame1 = getGraphicAnimationFrame(graphic1, step_frame);
1271 int frame2 = getGraphicAnimationFrame(graphic2, step_frame);
1272 int sx = SCREENX(x), sy = SCREENY(y);
1274 DrawGraphic(sx, sy, graphic1, frame1);
1275 DrawLevelFieldCrumbledSandExt(x, y, graphic2, frame2);
1278 static int getBorderElement(int x, int y)
1282 { EL_STEELWALL_TOPLEFT, EL_INVISIBLE_STEELWALL_TOPLEFT },
1283 { EL_STEELWALL_TOPRIGHT, EL_INVISIBLE_STEELWALL_TOPRIGHT },
1284 { EL_STEELWALL_BOTTOMLEFT, EL_INVISIBLE_STEELWALL_BOTTOMLEFT },
1285 { EL_STEELWALL_BOTTOMRIGHT, EL_INVISIBLE_STEELWALL_BOTTOMRIGHT },
1286 { EL_STEELWALL_VERTICAL, EL_INVISIBLE_STEELWALL_VERTICAL },
1287 { EL_STEELWALL_HORIZONTAL, EL_INVISIBLE_STEELWALL_HORIZONTAL },
1288 { EL_STEELWALL, EL_INVISIBLE_STEELWALL }
1290 int steel_type = (BorderElement == EL_STEELWALL ? 0 : 1);
1291 int steel_position = (x == -1 && y == -1 ? 0 :
1292 x == lev_fieldx && y == -1 ? 1 :
1293 x == -1 && y == lev_fieldy ? 2 :
1294 x == lev_fieldx && y == lev_fieldy ? 3 :
1295 x == -1 || x == lev_fieldx ? 4 :
1296 y == -1 || y == lev_fieldy ? 5 : 6);
1298 return border[steel_position][steel_type];
1301 void DrawScreenElement(int x, int y, int element)
1303 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
1304 DrawLevelFieldCrumbledSand(LEVELX(x), LEVELY(y));
1307 void DrawLevelElement(int x, int y, int element)
1309 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1310 DrawScreenElement(SCREENX(x), SCREENY(y), element);
1313 void DrawScreenField(int x, int y)
1315 int lx = LEVELX(x), ly = LEVELY(y);
1316 int element, content;
1318 if (!IN_LEV_FIELD(lx, ly))
1320 if (lx < -1 || lx > lev_fieldx || ly < -1 || ly > lev_fieldy)
1323 element = getBorderElement(lx, ly);
1325 DrawScreenElement(x, y, element);
1329 element = Feld[lx][ly];
1330 content = Store[lx][ly];
1332 if (IS_MOVING(lx, ly))
1334 int horiz_move = (MovDir[lx][ly] == MV_LEFT || MovDir[lx][ly] == MV_RIGHT);
1335 boolean cut_mode = NO_CUTTING;
1337 if (element == EL_QUICKSAND_EMPTYING ||
1338 element == EL_MAGIC_WALL_EMPTYING ||
1339 element == EL_BD_MAGIC_WALL_EMPTYING ||
1340 element == EL_AMOEBA_DROPPING)
1341 cut_mode = CUT_ABOVE;
1342 else if (element == EL_QUICKSAND_FILLING ||
1343 element == EL_MAGIC_WALL_FILLING ||
1344 element == EL_BD_MAGIC_WALL_FILLING)
1345 cut_mode = CUT_BELOW;
1347 if (cut_mode == CUT_ABOVE)
1348 DrawScreenElementShifted(x, y, 0, 0, element, NO_CUTTING);
1350 DrawScreenElement(x, y, EL_EMPTY);
1353 DrawScreenElementShifted(x, y, MovPos[lx][ly], 0, element, NO_CUTTING);
1354 else if (cut_mode == NO_CUTTING)
1355 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], element, cut_mode);
1357 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], content, cut_mode);
1359 if (content == EL_ACID)
1360 DrawLevelElementThruMask(lx, ly + 1, EL_ACID);
1362 else if (IS_BLOCKED(lx, ly))
1367 boolean cut_mode = NO_CUTTING;
1368 int element_old, content_old;
1370 Blocked2Moving(lx, ly, &oldx, &oldy);
1373 horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
1374 MovDir[oldx][oldy] == MV_RIGHT);
1376 element_old = Feld[oldx][oldy];
1377 content_old = Store[oldx][oldy];
1379 if (element_old == EL_QUICKSAND_EMPTYING ||
1380 element_old == EL_MAGIC_WALL_EMPTYING ||
1381 element_old == EL_BD_MAGIC_WALL_EMPTYING ||
1382 element_old == EL_AMOEBA_DROPPING)
1383 cut_mode = CUT_ABOVE;
1385 DrawScreenElement(x, y, EL_EMPTY);
1388 DrawScreenElementShifted(sx, sy, MovPos[oldx][oldy], 0, element_old,
1390 else if (cut_mode == NO_CUTTING)
1391 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], element_old,
1394 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], content_old,
1397 else if (IS_DRAWABLE(element))
1398 DrawScreenElement(x, y, element);
1400 DrawScreenElement(x, y, EL_EMPTY);
1403 void DrawLevelField(int x, int y)
1405 if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1406 DrawScreenField(SCREENX(x), SCREENY(y));
1407 else if (IS_MOVING(x, y))
1411 Moving2Blocked(x, y, &newx, &newy);
1412 if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
1413 DrawScreenField(SCREENX(newx), SCREENY(newy));
1415 else if (IS_BLOCKED(x, y))
1419 Blocked2Moving(x, y, &oldx, &oldy);
1420 if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
1421 DrawScreenField(SCREENX(oldx), SCREENY(oldy));
1425 void DrawMiniElement(int x, int y, int element)
1429 graphic = el2edimg(element);
1430 DrawMiniGraphic(x, y, graphic);
1433 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
1435 int x = sx + scroll_x, y = sy + scroll_y;
1437 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
1438 DrawMiniElement(sx, sy, EL_EMPTY);
1439 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
1440 DrawMiniElement(sx, sy, Feld[x][y]);
1442 DrawMiniGraphic(sx, sy, el2edimg(getBorderElement(x, y)));
1445 void getMicroGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
1447 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
1448 int mini_startx = src_bitmap->width * 3 / 4;
1449 int mini_starty = src_bitmap->height * 2 / 3;
1450 int src_x = mini_startx + graphic_info[graphic].src_x / 8;
1451 int src_y = mini_starty + graphic_info[graphic].src_y / 8;
1453 if (src_x + MICRO_TILEX > src_bitmap->width ||
1454 src_y + MICRO_TILEY > src_bitmap->height)
1456 /* graphic of desired size seems not to be contained in this image;
1457 dirty workaround: get it from the middle of the normal sized image */
1459 getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
1460 src_x += (TILEX / 2 - MICRO_TILEX / 2);
1461 src_y += (TILEY / 2 - MICRO_TILEY / 2);
1464 *bitmap = src_bitmap;
1469 void DrawMicroElement(int xpos, int ypos, int element)
1473 int graphic = el2preimg(element);
1475 getMicroGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
1476 BlitBitmap(src_bitmap, drawto, src_x, src_y, MICRO_TILEX, MICRO_TILEY,
1484 SetDrawBackgroundMask(REDRAW_NONE);
1487 for(x=BX1; x<=BX2; x++)
1488 for(y=BY1; y<=BY2; y++)
1489 DrawScreenField(x, y);
1491 redraw_mask |= REDRAW_FIELD;
1494 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
1498 for(x=0; x<size_x; x++)
1499 for(y=0; y<size_y; y++)
1500 DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
1502 redraw_mask |= REDRAW_FIELD;
1505 static void DrawMicroLevelExt(int xpos, int ypos, int from_x, int from_y)
1509 DrawBackground(xpos, ypos, MICROLEV_XSIZE, MICROLEV_YSIZE);
1511 if (lev_fieldx < STD_LEV_FIELDX)
1512 xpos += (STD_LEV_FIELDX - lev_fieldx) / 2 * MICRO_TILEX;
1513 if (lev_fieldy < STD_LEV_FIELDY)
1514 ypos += (STD_LEV_FIELDY - lev_fieldy) / 2 * MICRO_TILEY;
1516 xpos += MICRO_TILEX;
1517 ypos += MICRO_TILEY;
1519 for(x=-1; x<=STD_LEV_FIELDX; x++)
1521 for(y=-1; y<=STD_LEV_FIELDY; y++)
1523 int lx = from_x + x, ly = from_y + y;
1525 if (lx >= 0 && lx < lev_fieldx && ly >= 0 && ly < lev_fieldy)
1526 DrawMicroElement(xpos + x * MICRO_TILEX, ypos + y * MICRO_TILEY,
1528 else if (lx >= -1 && lx < lev_fieldx+1 && ly >= -1 && ly < lev_fieldy+1
1529 && BorderElement != EL_EMPTY)
1530 DrawMicroElement(xpos + x * MICRO_TILEX, ypos + y * MICRO_TILEY,
1531 getBorderElement(lx, ly));
1535 redraw_mask |= REDRAW_MICROLEVEL;
1538 #define MICROLABEL_EMPTY 0
1539 #define MICROLABEL_LEVEL_NAME 1
1540 #define MICROLABEL_CREATED_BY 2
1541 #define MICROLABEL_LEVEL_AUTHOR 3
1542 #define MICROLABEL_IMPORTED_FROM 4
1543 #define MICROLABEL_LEVEL_IMPORT_INFO 5
1545 static void DrawMicroLevelLabelExt(int mode)
1547 char label_text[MAX_OUTPUT_LINESIZE + 1];
1548 int max_len_label_text;
1549 int font_nr = FONT_TEXT_2;
1551 if (mode == MICROLABEL_CREATED_BY || mode == MICROLABEL_IMPORTED_FROM)
1552 font_nr = FONT_TEXT_3;
1554 max_len_label_text = SXSIZE / getFontWidth(font_nr);
1556 DrawBackground(SX, MICROLABEL_YPOS, SXSIZE, getFontHeight(font_nr));
1558 strncpy(label_text, (mode == MICROLABEL_LEVEL_NAME ? level.name :
1559 mode == MICROLABEL_CREATED_BY ? "created by" :
1560 mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
1561 mode == MICROLABEL_IMPORTED_FROM ? "imported from" :
1562 mode == MICROLABEL_LEVEL_IMPORT_INFO ?
1563 leveldir_current->imported_from : ""),
1564 max_len_label_text);
1565 label_text[max_len_label_text] = '\0';
1567 if (strlen(label_text) > 0)
1569 int text_width = strlen(label_text) * getFontWidth(font_nr);
1570 int lxpos = SX + (SXSIZE - text_width) / 2;
1571 int lypos = MICROLABEL_YPOS;
1573 DrawText(lxpos, lypos, label_text, font_nr);
1576 redraw_mask |= REDRAW_MICROLEVEL;
1579 void DrawMicroLevel(int xpos, int ypos, boolean restart)
1581 static unsigned long scroll_delay = 0;
1582 static unsigned long label_delay = 0;
1583 static int from_x, from_y, scroll_direction;
1584 static int label_state, label_counter;
1585 int last_game_status = game_status; /* save current game status */
1587 game_status = PSEUDO_PREVIEW; /* force PREVIEW font on preview level */
1591 from_x = from_y = 0;
1592 scroll_direction = MV_RIGHT;
1596 DrawMicroLevelExt(xpos, ypos, from_x, from_y);
1597 DrawMicroLevelLabelExt(label_state);
1599 /* initialize delay counters */
1600 DelayReached(&scroll_delay, 0);
1601 DelayReached(&label_delay, 0);
1603 if (leveldir_current->name)
1605 int len = strlen(leveldir_current->name);
1606 int lxpos = SX + (SXSIZE - len * getFontWidth(FONT_TEXT_1)) / 2;
1607 int lypos = SY + 352;
1609 DrawText(lxpos, lypos, leveldir_current->name, FONT_TEXT_1);
1612 game_status = last_game_status; /* restore current game status */
1617 /* scroll micro level, if needed */
1618 if ((lev_fieldx > STD_LEV_FIELDX || lev_fieldy > STD_LEV_FIELDY) &&
1619 DelayReached(&scroll_delay, MICROLEVEL_SCROLL_DELAY))
1621 switch (scroll_direction)
1627 scroll_direction = MV_UP;
1631 if (from_x < lev_fieldx - STD_LEV_FIELDX)
1634 scroll_direction = MV_DOWN;
1641 scroll_direction = MV_RIGHT;
1645 if (from_y < lev_fieldy - STD_LEV_FIELDY)
1648 scroll_direction = MV_LEFT;
1655 DrawMicroLevelExt(xpos, ypos, from_x, from_y);
1658 /* redraw micro level label, if needed */
1659 if (strcmp(level.name, NAMELESS_LEVEL_NAME) != 0 &&
1660 strcmp(level.author, ANONYMOUS_NAME) != 0 &&
1661 strcmp(level.author, leveldir_current->name) != 0 &&
1662 DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
1664 int max_label_counter = 23;
1666 if (leveldir_current->imported_from != NULL)
1667 max_label_counter += 14;
1669 label_counter = (label_counter + 1) % max_label_counter;
1670 label_state = (label_counter >= 0 && label_counter <= 7 ?
1671 MICROLABEL_LEVEL_NAME :
1672 label_counter >= 9 && label_counter <= 12 ?
1673 MICROLABEL_CREATED_BY :
1674 label_counter >= 14 && label_counter <= 21 ?
1675 MICROLABEL_LEVEL_AUTHOR :
1676 label_counter >= 23 && label_counter <= 26 ?
1677 MICROLABEL_IMPORTED_FROM :
1678 label_counter >= 28 && label_counter <= 35 ?
1679 MICROLABEL_LEVEL_IMPORT_INFO : MICROLABEL_EMPTY);
1680 DrawMicroLevelLabelExt(label_state);
1683 game_status = last_game_status; /* restore current game status */
1686 int REQ_in_range(int x, int y)
1688 if (y > DY+249 && y < DY+278)
1690 if (x > DX+1 && x < DX+48)
1692 else if (x > DX+51 && x < DX+98)
1698 #define MAX_REQUEST_LINES 13
1699 #define MAX_REQUEST_LINE_LEN 7
1701 boolean Request(char *text, unsigned int req_state)
1703 int mx, my, ty, result = -1;
1704 unsigned int old_door_state;
1705 int last_game_status = game_status; /* save current game status */
1707 #if defined(PLATFORM_UNIX)
1708 /* pause network game while waiting for request to answer */
1709 if (options.network &&
1710 game_status == PLAYING &&
1711 req_state & REQUEST_WAIT_FOR)
1712 SendToServer_PausePlaying();
1715 old_door_state = GetDoorState();
1719 CloseDoor(DOOR_CLOSE_1);
1721 /* save old door content */
1722 BlitBitmap(bitmap_db_door, bitmap_db_door,
1723 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
1724 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
1726 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
1728 /* clear door drawing field */
1729 DrawBackground(DX, DY, DXSIZE, DYSIZE);
1731 game_status = PSEUDO_DOOR; /* force DOOR font on preview level */
1733 /* write text for request */
1734 for(ty=0; ty < MAX_REQUEST_LINES; ty++)
1736 char text_line[MAX_REQUEST_LINE_LEN + 1];
1742 for(tl=0,tx=0; tx < MAX_REQUEST_LINE_LEN; tl++,tx++)
1745 if (!tc || tc == ' ')
1756 strncpy(text_line, text, tl);
1759 DrawText(DX + (DXSIZE - tl * getFontWidth(FONT_TEXT_2)) / 2,
1760 DY + 8 + ty * (getFontHeight(FONT_TEXT_2) + 2),
1761 text_line, FONT_TEXT_2);
1763 text += tl + (tc == ' ' ? 1 : 0);
1766 game_status = last_game_status; /* restore current game status */
1768 if (req_state & REQ_ASK)
1770 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
1771 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
1773 else if (req_state & REQ_CONFIRM)
1775 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
1777 else if (req_state & REQ_PLAYER)
1779 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
1780 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
1781 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
1782 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
1785 /* copy request gadgets to door backbuffer */
1786 BlitBitmap(drawto, bitmap_db_door,
1787 DX, DY, DXSIZE, DYSIZE,
1788 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
1790 OpenDoor(DOOR_OPEN_1);
1796 if (!(req_state & REQUEST_WAIT_FOR))
1798 SetDrawBackgroundMask(REDRAW_FIELD);
1803 if (game_status != MAINMENU)
1806 button_status = MB_RELEASED;
1808 request_gadget_id = -1;
1810 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
1822 case EVENT_BUTTONPRESS:
1823 case EVENT_BUTTONRELEASE:
1824 case EVENT_MOTIONNOTIFY:
1826 if (event.type == EVENT_MOTIONNOTIFY)
1828 if (!PointerInWindow(window))
1829 continue; /* window and pointer are on different screens */
1834 motion_status = TRUE;
1835 mx = ((MotionEvent *) &event)->x;
1836 my = ((MotionEvent *) &event)->y;
1840 motion_status = FALSE;
1841 mx = ((ButtonEvent *) &event)->x;
1842 my = ((ButtonEvent *) &event)->y;
1843 if (event.type == EVENT_BUTTONPRESS)
1844 button_status = ((ButtonEvent *) &event)->button;
1846 button_status = MB_RELEASED;
1849 /* this sets 'request_gadget_id' */
1850 HandleGadgets(mx, my, button_status);
1852 switch(request_gadget_id)
1854 case TOOL_CTRL_ID_YES:
1857 case TOOL_CTRL_ID_NO:
1860 case TOOL_CTRL_ID_CONFIRM:
1861 result = TRUE | FALSE;
1864 case TOOL_CTRL_ID_PLAYER_1:
1867 case TOOL_CTRL_ID_PLAYER_2:
1870 case TOOL_CTRL_ID_PLAYER_3:
1873 case TOOL_CTRL_ID_PLAYER_4:
1884 case EVENT_KEYPRESS:
1885 switch(GetEventKey((KeyEvent *)&event, TRUE))
1898 if (req_state & REQ_PLAYER)
1902 case EVENT_KEYRELEASE:
1903 ClearPlayerAction();
1907 HandleOtherEvents(&event);
1911 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
1913 int joy = AnyJoystick();
1915 if (joy & JOY_BUTTON_1)
1917 else if (joy & JOY_BUTTON_2)
1923 /* don't eat all CPU time */
1927 if (game_status != MAINMENU)
1932 if (!(req_state & REQ_STAY_OPEN))
1934 CloseDoor(DOOR_CLOSE_1);
1936 if (!(req_state & REQ_STAY_CLOSED) && (old_door_state & DOOR_OPEN_1))
1938 BlitBitmap(bitmap_db_door, bitmap_db_door,
1939 DOOR_GFX_PAGEX2,DOOR_GFX_PAGEY1, DXSIZE,DYSIZE,
1940 DOOR_GFX_PAGEX1,DOOR_GFX_PAGEY1);
1941 OpenDoor(DOOR_OPEN_1);
1947 SetDrawBackgroundMask(REDRAW_FIELD);
1949 #if defined(PLATFORM_UNIX)
1950 /* continue network game after request */
1951 if (options.network &&
1952 game_status == PLAYING &&
1953 req_state & REQUEST_WAIT_FOR)
1954 SendToServer_ContinuePlaying();
1960 unsigned int OpenDoor(unsigned int door_state)
1962 unsigned int new_door_state;
1964 if (door_state & DOOR_COPY_BACK)
1966 BlitBitmap(bitmap_db_door, bitmap_db_door,
1967 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE + VYSIZE,
1968 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
1969 door_state &= ~DOOR_COPY_BACK;
1972 new_door_state = MoveDoor(door_state);
1974 return(new_door_state);
1977 unsigned int CloseDoor(unsigned int door_state)
1979 unsigned int new_door_state;
1981 BlitBitmap(backbuffer, bitmap_db_door,
1982 DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
1983 BlitBitmap(backbuffer, bitmap_db_door,
1984 VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
1986 new_door_state = MoveDoor(door_state);
1988 return(new_door_state);
1991 unsigned int GetDoorState()
1993 return MoveDoor(DOOR_GET_STATE);
1996 unsigned int SetDoorState(unsigned int door_state)
1998 return MoveDoor(door_state | DOOR_SET_STATE);
2001 unsigned int MoveDoor(unsigned int door_state)
2003 static int door1 = DOOR_OPEN_1;
2004 static int door2 = DOOR_CLOSE_2;
2005 static unsigned long door_delay = 0;
2006 int x, start, stepsize = global.door_step_offset;
2007 unsigned long door_delay_value = global.door_step_delay;
2009 if (door_state == DOOR_GET_STATE)
2010 return(door1 | door2);
2012 if (door_state & DOOR_SET_STATE)
2014 if (door_state & DOOR_ACTION_1)
2015 door1 = door_state & DOOR_ACTION_1;
2016 if (door_state & DOOR_ACTION_2)
2017 door2 = door_state & DOOR_ACTION_2;
2019 return(door1 | door2);
2022 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
2023 door_state &= ~DOOR_OPEN_1;
2024 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
2025 door_state &= ~DOOR_CLOSE_1;
2026 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
2027 door_state &= ~DOOR_OPEN_2;
2028 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
2029 door_state &= ~DOOR_CLOSE_2;
2031 if (setup.quick_doors)
2034 door_delay_value = 0;
2036 StopSound(SND_DOOR_OPENING);
2037 StopSound(SND_DOOR_CLOSING);
2040 if (global.autoplay_leveldir)
2042 door_state |= DOOR_NO_DELAY;
2043 door_state &= ~DOOR_CLOSE_ALL;
2046 if (door_state & DOOR_ACTION)
2048 if (!(door_state & DOOR_NO_DELAY))
2050 /* opening door sound has priority over simultaneously closing door */
2051 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
2052 PlaySoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
2053 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
2054 PlaySoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
2057 start = ((door_state & DOOR_NO_DELAY) ? DXSIZE : 0);
2059 for(x=start; x<=DXSIZE; x+=stepsize)
2061 Bitmap *bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
2062 GC gc = bitmap->stored_clip_gc;
2064 if (!(door_state & DOOR_NO_DELAY))
2065 WaitUntilDelayReached(&door_delay, door_delay_value);
2067 if (door_state & DOOR_ACTION_1)
2069 int i = (door_state & DOOR_OPEN_1 ? DXSIZE-x : x);
2070 int j = (DXSIZE - i) / 3;
2072 BlitBitmap(bitmap_db_door, drawto,
2073 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + i/2,
2074 DXSIZE,DYSIZE - i/2, DX, DY);
2076 ClearRectangle(drawto, DX, DY + DYSIZE - i/2, DXSIZE,i/2);
2078 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2079 BlitBitmapMasked(bitmap, drawto,
2080 DXSIZE, DOOR_GFX_PAGEY1, i, 77,
2081 DX + DXSIZE - i, DY + j);
2082 BlitBitmapMasked(bitmap, drawto,
2083 DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63,
2084 DX + DXSIZE - i, DY + 140 + j);
2085 SetClipOrigin(bitmap, gc, DX - DXSIZE + i, DY - (DOOR_GFX_PAGEY1 + j));
2086 BlitBitmapMasked(bitmap, drawto,
2087 DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j,
2089 BlitBitmapMasked(bitmap, drawto,
2090 DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63,
2093 BlitBitmapMasked(bitmap, drawto,
2094 DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
2096 BlitBitmapMasked(bitmap, drawto,
2097 DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
2099 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2100 BlitBitmapMasked(bitmap, drawto,
2101 DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
2102 DX + DXSIZE - i, DY + 77 + j);
2103 BlitBitmapMasked(bitmap, drawto,
2104 DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
2105 DX + DXSIZE - i, DY + 203 + j);
2107 redraw_mask |= REDRAW_DOOR_1;
2110 if (door_state & DOOR_ACTION_2)
2112 int i = (door_state & DOOR_OPEN_2 ? VXSIZE - x : x);
2113 int j = (VXSIZE - i) / 3;
2115 BlitBitmap(bitmap_db_door, drawto,
2116 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + i/2,
2117 VXSIZE, VYSIZE - i/2, VX, VY);
2119 ClearRectangle(drawto, VX, VY + VYSIZE-i/2, VXSIZE, i/2);
2121 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2122 BlitBitmapMasked(bitmap, drawto,
2123 VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2,
2124 VX + VXSIZE-i, VY+j);
2125 SetClipOrigin(bitmap, gc,
2126 VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
2127 BlitBitmapMasked(bitmap, drawto,
2128 VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j,
2131 BlitBitmapMasked(bitmap, drawto,
2132 VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2,
2133 i, VYSIZE / 2, VX, VY + VYSIZE / 2 - j);
2134 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2135 BlitBitmapMasked(bitmap, drawto,
2136 VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2,
2138 VX + VXSIZE - i, VY + VYSIZE / 2 + j);
2140 redraw_mask |= REDRAW_DOOR_2;
2145 if (game_status == MAINMENU)
2150 if (setup.quick_doors)
2152 StopSound(SND_DOOR_OPENING);
2153 StopSound(SND_DOOR_CLOSING);
2156 if (door_state & DOOR_ACTION_1)
2157 door1 = door_state & DOOR_ACTION_1;
2158 if (door_state & DOOR_ACTION_2)
2159 door2 = door_state & DOOR_ACTION_2;
2161 return (door1 | door2);
2164 void DrawSpecialEditorDoor()
2166 /* draw bigger toolbox window */
2167 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
2168 DOOR_GFX_PAGEX7, 0, EXSIZE + 8, 8,
2170 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
2171 EX - 4, VY - 4, EXSIZE + 8, EYSIZE - VYSIZE + 4,
2174 redraw_mask |= REDRAW_ALL;
2177 void UndrawSpecialEditorDoor()
2179 /* draw normal tape recorder window */
2180 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
2181 EX - 4, EY - 12, EXSIZE + 8, EYSIZE - VYSIZE + 12,
2184 redraw_mask |= REDRAW_ALL;
2188 /* ---------- new tool button stuff ---------------------------------------- */
2190 /* graphic position values for tool buttons */
2191 #define TOOL_BUTTON_YES_XPOS 2
2192 #define TOOL_BUTTON_YES_YPOS 250
2193 #define TOOL_BUTTON_YES_GFX_YPOS 0
2194 #define TOOL_BUTTON_YES_XSIZE 46
2195 #define TOOL_BUTTON_YES_YSIZE 28
2196 #define TOOL_BUTTON_NO_XPOS 52
2197 #define TOOL_BUTTON_NO_YPOS TOOL_BUTTON_YES_YPOS
2198 #define TOOL_BUTTON_NO_GFX_YPOS TOOL_BUTTON_YES_GFX_YPOS
2199 #define TOOL_BUTTON_NO_XSIZE TOOL_BUTTON_YES_XSIZE
2200 #define TOOL_BUTTON_NO_YSIZE TOOL_BUTTON_YES_YSIZE
2201 #define TOOL_BUTTON_CONFIRM_XPOS TOOL_BUTTON_YES_XPOS
2202 #define TOOL_BUTTON_CONFIRM_YPOS TOOL_BUTTON_YES_YPOS
2203 #define TOOL_BUTTON_CONFIRM_GFX_YPOS 30
2204 #define TOOL_BUTTON_CONFIRM_XSIZE 96
2205 #define TOOL_BUTTON_CONFIRM_YSIZE TOOL_BUTTON_YES_YSIZE
2206 #define TOOL_BUTTON_PLAYER_XSIZE 30
2207 #define TOOL_BUTTON_PLAYER_YSIZE 30
2208 #define TOOL_BUTTON_PLAYER_GFX_XPOS 5
2209 #define TOOL_BUTTON_PLAYER_GFX_YPOS 185
2210 #define TOOL_BUTTON_PLAYER_XPOS (5 + TOOL_BUTTON_PLAYER_XSIZE / 2)
2211 #define TOOL_BUTTON_PLAYER_YPOS (215 - TOOL_BUTTON_PLAYER_YSIZE / 2)
2212 #define TOOL_BUTTON_PLAYER1_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2213 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2214 #define TOOL_BUTTON_PLAYER2_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2215 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2216 #define TOOL_BUTTON_PLAYER3_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2217 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2218 #define TOOL_BUTTON_PLAYER4_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2219 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2220 #define TOOL_BUTTON_PLAYER1_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2221 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2222 #define TOOL_BUTTON_PLAYER2_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2223 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2224 #define TOOL_BUTTON_PLAYER3_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2225 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2226 #define TOOL_BUTTON_PLAYER4_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2227 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2236 } toolbutton_info[NUM_TOOL_BUTTONS] =
2239 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_GFX_YPOS,
2240 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_YPOS,
2241 TOOL_BUTTON_YES_XSIZE, TOOL_BUTTON_YES_YSIZE,
2246 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_GFX_YPOS,
2247 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_YPOS,
2248 TOOL_BUTTON_NO_XSIZE, TOOL_BUTTON_NO_YSIZE,
2253 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_GFX_YPOS,
2254 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_YPOS,
2255 TOOL_BUTTON_CONFIRM_XSIZE, TOOL_BUTTON_CONFIRM_YSIZE,
2256 TOOL_CTRL_ID_CONFIRM,
2260 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2261 TOOL_BUTTON_PLAYER1_XPOS, TOOL_BUTTON_PLAYER1_YPOS,
2262 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2263 TOOL_CTRL_ID_PLAYER_1,
2267 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2268 TOOL_BUTTON_PLAYER2_XPOS, TOOL_BUTTON_PLAYER2_YPOS,
2269 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2270 TOOL_CTRL_ID_PLAYER_2,
2274 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2275 TOOL_BUTTON_PLAYER3_XPOS, TOOL_BUTTON_PLAYER3_YPOS,
2276 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2277 TOOL_CTRL_ID_PLAYER_3,
2281 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2282 TOOL_BUTTON_PLAYER4_XPOS, TOOL_BUTTON_PLAYER4_YPOS,
2283 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2284 TOOL_CTRL_ID_PLAYER_4,
2289 void CreateToolButtons()
2293 for (i=0; i<NUM_TOOL_BUTTONS; i++)
2295 Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
2296 Bitmap *deco_bitmap = None;
2297 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
2298 struct GadgetInfo *gi;
2299 unsigned long event_mask;
2300 int gd_xoffset, gd_yoffset;
2301 int gd_x1, gd_x2, gd_y;
2304 event_mask = GD_EVENT_RELEASED;
2306 gd_xoffset = toolbutton_info[i].xpos;
2307 gd_yoffset = toolbutton_info[i].ypos;
2308 gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
2309 gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
2310 gd_y = DOOR_GFX_PAGEY1 + gd_yoffset;
2312 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
2314 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
2316 getMiniGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr),
2317 &deco_bitmap, &deco_x, &deco_y);
2318 deco_xpos = (toolbutton_info[i].width - MINI_TILEX) / 2;
2319 deco_ypos = (toolbutton_info[i].height - MINI_TILEY) / 2;
2322 gi = CreateGadget(GDI_CUSTOM_ID, id,
2323 GDI_INFO_TEXT, toolbutton_info[i].infotext,
2324 GDI_X, DX + toolbutton_info[i].x,
2325 GDI_Y, DY + toolbutton_info[i].y,
2326 GDI_WIDTH, toolbutton_info[i].width,
2327 GDI_HEIGHT, toolbutton_info[i].height,
2328 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
2329 GDI_STATE, GD_BUTTON_UNPRESSED,
2330 GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
2331 GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
2332 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
2333 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
2334 GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
2335 GDI_DECORATION_SHIFTING, 1, 1,
2336 GDI_EVENT_MASK, event_mask,
2337 GDI_CALLBACK_ACTION, HandleToolButtons,
2341 Error(ERR_EXIT, "cannot create gadget");
2343 tool_gadget[id] = gi;
2347 void FreeToolButtons()
2351 for (i=0; i<NUM_TOOL_BUTTONS; i++)
2352 FreeGadget(tool_gadget[i]);
2355 static void UnmapToolButtons()
2359 for (i=0; i<NUM_TOOL_BUTTONS; i++)
2360 UnmapGadget(tool_gadget[i]);
2363 static void HandleToolButtons(struct GadgetInfo *gi)
2365 request_gadget_id = gi->custom_id;
2368 int get_next_element(int element)
2372 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
2373 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
2374 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
2375 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
2376 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
2377 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
2378 case EL_AMOEBA_DROPPING: return EL_AMOEBA_WET;
2380 default: return element;
2384 int el_act_dir2img(int element, int action, int direction)
2386 direction = MV_DIR_BIT(direction);
2388 return element_info[element].direction_graphic[action][direction];
2391 int el_act2img(int element, int action)
2393 return element_info[element].graphic[action];
2396 int el_dir2img(int element, int direction)
2398 return el_act_dir2img(element, ACTION_DEFAULT, direction);
2401 int el2img(int element)
2403 return element_info[element].graphic[ACTION_DEFAULT];
2406 int el2edimg(int element)
2408 return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
2411 int el2preimg(int element)
2413 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];