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 == GAME_MODE_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 == GAME_MODE_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 == GAME_MODE_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 != GAME_MODE_PLAYING ||
179 redraw_mask & REDRAW_FROM_BACKBUFFER)
181 BlitBitmap(backbuffer, window,
182 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE, REAL_SX, REAL_SY);
186 int fx = FX, fy = FY;
188 if (setup.soft_scrolling)
190 fx += (ScreenMovDir & (MV_LEFT | MV_RIGHT) ? ScreenGfxPos : 0);
191 fy += (ScreenMovDir & (MV_UP | MV_DOWN) ? ScreenGfxPos : 0);
194 if (setup.soft_scrolling ||
195 ABS(ScreenMovPos) + ScrollStepSize == TILEX ||
196 ABS(ScreenMovPos) == ScrollStepSize ||
197 redraw_tiles > REDRAWTILES_THRESHOLD)
199 BlitBitmap(buffer, window, fx, fy, SXSIZE, SYSIZE, SX, SY);
203 printf("redrawing all (ScreenGfxPos == %d) because %s\n",
205 (setup.soft_scrolling ?
206 "setup.soft_scrolling" :
207 ABS(ScreenGfxPos) + ScrollStepSize == TILEX ?
208 "ABS(ScreenGfxPos) + ScrollStepSize == TILEX" :
209 ABS(ScreenGfxPos) == ScrollStepSize ?
210 "ABS(ScreenGfxPos) == ScrollStepSize" :
211 "redraw_tiles > REDRAWTILES_THRESHOLD"));
217 redraw_mask &= ~REDRAW_MAIN;
220 if (redraw_mask & REDRAW_DOORS)
222 if (redraw_mask & REDRAW_DOOR_1)
223 BlitBitmap(backbuffer, window, DX, DY, DXSIZE, DYSIZE, DX, DY);
224 if (redraw_mask & REDRAW_DOOR_2)
226 if ((redraw_mask & REDRAW_DOOR_2) == REDRAW_DOOR_2)
227 BlitBitmap(backbuffer, window, VX,VY, VXSIZE,VYSIZE, VX,VY);
230 if (redraw_mask & REDRAW_VIDEO_1)
231 BlitBitmap(backbuffer, window,
232 VX+VIDEO_DISPLAY1_XPOS,VY+VIDEO_DISPLAY1_YPOS,
233 VIDEO_DISPLAY_XSIZE,VIDEO_DISPLAY_YSIZE,
234 VX+VIDEO_DISPLAY1_XPOS,VY+VIDEO_DISPLAY1_YPOS);
235 if (redraw_mask & REDRAW_VIDEO_2)
236 BlitBitmap(backbuffer, window,
237 VX+VIDEO_DISPLAY2_XPOS,VY+VIDEO_DISPLAY2_YPOS,
238 VIDEO_DISPLAY_XSIZE,VIDEO_DISPLAY_YSIZE,
239 VX+VIDEO_DISPLAY2_XPOS,VY+VIDEO_DISPLAY2_YPOS);
240 if (redraw_mask & REDRAW_VIDEO_3)
241 BlitBitmap(backbuffer, window,
242 VX+VIDEO_CONTROL_XPOS,VY+VIDEO_CONTROL_YPOS,
243 VIDEO_CONTROL_XSIZE,VIDEO_CONTROL_YSIZE,
244 VX+VIDEO_CONTROL_XPOS,VY+VIDEO_CONTROL_YPOS);
248 if (redraw_mask & REDRAW_DOOR_3)
249 BlitBitmap(backbuffer, window, EX, EY, EXSIZE, EYSIZE, EX, EY);
251 redraw_mask &= ~REDRAW_DOORS;
254 if (redraw_mask & REDRAW_MICROLEVEL)
256 BlitBitmap(backbuffer, window, SX, SY + 10 * TILEY, SXSIZE, 7 * TILEY,
257 SX, SY + 10 * TILEY);
259 redraw_mask &= ~REDRAW_MICROLEVEL;
262 if (redraw_mask & REDRAW_TILES)
264 for(x=0; x<SCR_FIELDX; x++)
265 for(y=0; y<SCR_FIELDY; y++)
266 if (redraw[redraw_x1 + x][redraw_y1 + y])
267 BlitBitmap(buffer, window,
268 FX + x * TILEX, FX + y * TILEY, TILEX, TILEY,
269 SX + x * TILEX, SY + y * TILEY);
272 if (redraw_mask & REDRAW_FPS) /* display frames per second */
277 sprintf(info1, " (only every %d. frame)", global.fps_slowdown_factor);
278 if (!global.fps_slowdown)
281 sprintf(text, "%.1f fps%s", global.frames_per_second, info1);
282 DrawTextExt(window, SX, SY, text, FONT_TEXT_2, BLIT_OPAQUE);
287 for(x=0; x<MAX_BUF_XSIZE; x++)
288 for(y=0; y<MAX_BUF_YSIZE; y++)
291 redraw_mask = REDRAW_NONE;
297 long fading_delay = 300;
299 if (setup.fading && (redraw_mask & REDRAW_FIELD))
306 ClearRectangle(window, REAL_SX,REAL_SY,FULL_SXSIZE,FULL_SYSIZE);
309 for(i=0;i<2*FULL_SYSIZE;i++)
311 for(y=0;y<FULL_SYSIZE;y++)
313 BlitBitmap(backbuffer, window,
314 REAL_SX,REAL_SY+i, FULL_SXSIZE,1, REAL_SX,REAL_SY+i);
322 for(i=1;i<FULL_SYSIZE;i+=2)
323 BlitBitmap(backbuffer, window,
324 REAL_SX,REAL_SY+i, FULL_SXSIZE,1, REAL_SX,REAL_SY+i);
330 SetClipOrigin(clip_gc[PIX_FADEMASK], 0, 0);
331 BlitBitmapMasked(backbuffer, window,
332 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
337 SetClipOrigin(clip_gc[PIX_FADEMASK], -1, -1);
338 BlitBitmapMasked(backbuffer, window,
339 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
344 SetClipOrigin(clip_gc[PIX_FADEMASK], 0, -1);
345 BlitBitmapMasked(backbuffer, window,
346 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
351 SetClipOrigin(clip_gc[PIX_FADEMASK], -1, 0);
352 BlitBitmapMasked(backbuffer, window,
353 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
358 redraw_mask &= ~REDRAW_MAIN;
365 void SetMainBackgroundImage(int graphic)
367 SetMainBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
368 graphic_info[graphic].bitmap ?
369 graphic_info[graphic].bitmap :
370 graphic_info[IMG_BACKGROUND].bitmap);
373 void SetDoorBackgroundImage(int graphic)
375 SetDoorBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
376 graphic_info[graphic].bitmap ?
377 graphic_info[graphic].bitmap :
378 graphic_info[IMG_BACKGROUND].bitmap);
381 void DrawBackground(int dest_x, int dest_y, int width, int height)
383 ClearRectangleOnBackground(backbuffer, dest_x, dest_y, width, height);
385 redraw_mask |= REDRAW_FIELD;
390 DrawBackground(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
392 if (setup.soft_scrolling && game_status == GAME_MODE_PLAYING)
394 ClearRectangle(fieldbuffer, 0, 0, FXSIZE, FYSIZE);
395 SetDrawtoField(DRAW_BUFFERED);
398 SetDrawtoField(DRAW_BACKBUFFER);
400 if (setup.direct_draw && game_status == GAME_MODE_PLAYING)
402 ClearRectangle(window, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
403 SetDrawtoField(DRAW_DIRECT);
407 void MarkTileDirty(int x, int y)
409 int xx = redraw_x1 + x;
410 int yy = redraw_y1 + y;
415 redraw[xx][yy] = TRUE;
416 redraw_mask |= REDRAW_TILES;
419 void SetBorderElement()
423 BorderElement = EL_EMPTY;
425 for(y=0; y<lev_fieldy && BorderElement == EL_EMPTY; y++)
427 for(x=0; x<lev_fieldx; x++)
429 if (!IS_INDESTRUCTIBLE(Feld[x][y]))
430 BorderElement = EL_STEELWALL;
432 if (y != 0 && y != lev_fieldy - 1 && x != lev_fieldx - 1)
438 void SetRandomAnimationValue(int x, int y)
440 gfx.anim_random_frame = GfxRandom[x][y];
443 inline int getGraphicAnimationFrame(int graphic, int sync_frame)
445 /* animation synchronized with global frame counter, not move position */
446 if (graphic_info[graphic].anim_global_sync || sync_frame < 0)
447 sync_frame = FrameCounter;
449 return getAnimationFrame(graphic_info[graphic].anim_frames,
450 graphic_info[graphic].anim_delay,
451 graphic_info[graphic].anim_mode,
452 graphic_info[graphic].anim_start_frame,
456 inline void DrawGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
457 int graphic, int sync_frame, int mask_mode)
459 int frame = getGraphicAnimationFrame(graphic, sync_frame);
461 if (mask_mode == USE_MASKING)
462 DrawGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
464 DrawGraphicExt(dst_bitmap, x, y, graphic, frame);
467 inline void DrawGraphicAnimation(int x, int y, int graphic)
469 int lx = LEVELX(x), ly = LEVELY(y);
471 if (!IN_SCR_FIELD(x, y))
474 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
475 graphic, GfxFrame[lx][ly], NO_MASKING);
479 void DrawLevelGraphicAnimation(int x, int y, int graphic)
481 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
484 void DrawLevelElementAnimation(int x, int y, int element)
487 int graphic = el_act_dir2img(element, GfxAction[x][y], MovDir[x][y]);
489 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
491 DrawGraphicAnimation(SCREENX(x), SCREENY(y), el2img(element));
495 inline void DrawLevelGraphicAnimationIfNeeded(int x, int y, int graphic)
497 int sx = SCREENX(x), sy = SCREENY(y);
499 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
502 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
505 DrawGraphicAnimation(sx, sy, graphic);
508 void DrawLevelElementAnimationIfNeeded(int x, int y, int element)
510 int sx = SCREENX(x), sy = SCREENY(y);
513 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
516 graphic = el_act_dir2img(element, GfxAction[x][y], MovDir[x][y]);
518 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
521 DrawGraphicAnimation(sx, sy, graphic);
524 void DrawAllPlayers()
528 for(i=0; i<MAX_PLAYERS; i++)
529 if (stored_player[i].active)
530 DrawPlayer(&stored_player[i]);
533 void DrawPlayerField(int x, int y)
535 if (!IS_PLAYER(x, y))
538 DrawPlayer(PLAYERINFO(x, y));
541 void DrawPlayer(struct PlayerInfo *player)
543 int jx = player->jx, jy = player->jy;
544 int last_jx = player->last_jx, last_jy = player->last_jy;
545 int next_jx = jx + (jx - last_jx), next_jy = jy + (jy - last_jy);
546 int sx = SCREENX(jx), sy = SCREENY(jy);
547 int sxx = 0, syy = 0;
548 int element = Feld[jx][jy], last_element = Feld[last_jx][last_jy];
551 boolean player_is_moving = (last_jx != jx || last_jy != jy ? TRUE : FALSE);
552 int move_dir = player->MovDir;
553 int action = ACTION_DEFAULT;
555 if (!player->active || !IN_SCR_FIELD(SCREENX(last_jx), SCREENY(last_jy)))
559 if (!IN_LEV_FIELD(jx,jy))
561 printf("DrawPlayerField(): x = %d, y = %d\n",jx,jy);
562 printf("DrawPlayerField(): sx = %d, sy = %d\n",sx,sy);
563 printf("DrawPlayerField(): This should never happen!\n");
568 if (element == EL_EXPLOSION)
571 action = (player->Pushing ? ACTION_PUSHING :
572 player->is_digging ? ACTION_DIGGING :
573 player->is_collecting ? ACTION_COLLECTING :
574 player->is_moving ? ACTION_MOVING :
575 player->snapped ? ACTION_SNAPPING : ACTION_DEFAULT);
577 InitPlayerGfxAnimation(player, action, move_dir);
579 /* ----------------------------------------------------------------------- */
580 /* draw things in the field the player is leaving, if needed */
581 /* ----------------------------------------------------------------------- */
583 if (player_is_moving)
585 if (Back[last_jx][last_jy] && IS_DRAWABLE(last_element))
587 DrawLevelElement(last_jx, last_jy, Back[last_jx][last_jy]);
589 if (last_element == EL_DYNAMITE_ACTIVE ||
590 last_element == EL_SP_DISK_RED_ACTIVE)
591 DrawDynamite(last_jx, last_jy);
593 DrawLevelFieldThruMask(last_jx, last_jy);
595 else if (last_element == EL_DYNAMITE_ACTIVE ||
596 last_element == EL_SP_DISK_RED_ACTIVE)
597 DrawDynamite(last_jx, last_jy);
599 DrawLevelField(last_jx, last_jy);
601 if (player->Pushing && IN_SCR_FIELD(SCREENX(next_jx), SCREENY(next_jy)))
604 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
608 if (Feld[next_jx][next_jy] == EL_SOKOBAN_FIELD_FULL)
609 DrawLevelElement(next_jx, next_jy, EL_SOKOBAN_FIELD_EMPTY);
611 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
614 DrawLevelField(next_jx, next_jy);
619 if (!IN_SCR_FIELD(sx, sy))
622 if (setup.direct_draw)
623 SetDrawtoField(DRAW_BUFFERED);
625 /* ----------------------------------------------------------------------- */
626 /* draw things behind the player, if needed */
627 /* ----------------------------------------------------------------------- */
630 DrawLevelElement(jx, jy, Back[jx][jy]);
631 else if (IS_ACTIVE_BOMB(element))
632 DrawLevelElement(jx, jy, EL_EMPTY);
635 if (player_is_moving && GfxElement[jx][jy] != EL_UNDEFINED)
637 if (GfxElement[jx][jy] == EL_SAND)
638 DrawLevelFieldCrumbledSandDigging(jx, jy, move_dir, player->StepFrame);
641 int old_element = GfxElement[jx][jy];
642 int old_graphic = el_act_dir2img(old_element, action, move_dir);
643 int frame = getGraphicAnimationFrame(old_graphic, player->StepFrame);
645 DrawGraphic(sx, sy, old_graphic, frame);
650 GfxElement[jx][jy] = EL_UNDEFINED;
652 DrawLevelField(jx, jy);
656 /* ----------------------------------------------------------------------- */
657 /* draw player himself */
658 /* ----------------------------------------------------------------------- */
660 if (player->use_murphy_graphic)
662 static int last_horizontal_dir = MV_LEFT;
665 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
666 last_horizontal_dir = move_dir;
668 direction = (player->snapped ? move_dir : last_horizontal_dir);
670 graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, direction);
673 graphic = el_act_dir2img(player->element_nr, player->GfxAction, move_dir);
675 frame = getGraphicAnimationFrame(graphic, player->Frame);
679 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
680 sxx = player->GfxPos;
682 syy = player->GfxPos;
685 if (!setup.soft_scrolling && ScreenMovPos)
688 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
690 if (SHIELD_ON(player))
692 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
693 IMG_SHIELD_NORMAL_ACTIVE);
694 int frame = getGraphicAnimationFrame(graphic, -1);
696 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
699 /* ----------------------------------------------------------------------- */
700 /* draw things the player is pushing, if needed */
701 /* ----------------------------------------------------------------------- */
703 if (player->Pushing && player_is_moving)
705 int px = SCREENX(next_jx), py = SCREENY(next_jy);
707 if (Back[next_jx][next_jy])
708 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
711 if ((sxx || syy) && element == EL_SOKOBAN_OBJECT)
712 DrawGraphicShiftedThruMask(px, py, sxx, syy, IMG_SOKOBAN_OBJECT, 0,
716 (element == EL_SOKOBAN_FIELD_EMPTY ||
717 Feld[next_jx][next_jy] == EL_SOKOBAN_FIELD_FULL))
718 DrawGraphicShiftedThruMask(px, py, sxx, syy, IMG_SOKOBAN_OBJECT, 0,
724 int element = Feld[jx][jy];
726 int element = Feld[next_jx][next_jy];
729 int graphic = el2img(element);
732 if ((sxx || syy) && IS_PUSHABLE(element))
734 graphic = el_act_dir2img(element, ACTION_MOVING, move_dir);
735 frame = getGraphicAnimationFrame(graphic, player->Frame);
738 DrawGraphicShifted(px, py, sxx, syy, graphic, frame,
739 NO_CUTTING, NO_MASKING);
743 /* ----------------------------------------------------------------------- */
744 /* draw things in front of player (active dynamite or dynabombs) */
745 /* ----------------------------------------------------------------------- */
747 if (IS_ACTIVE_BOMB(element))
749 graphic = el2img(element);
750 frame = getGraphicAnimationFrame(graphic, GfxFrame[jx][jy]);
752 if (game.emulation == EMU_SUPAPLEX)
753 DrawGraphic(sx, sy, IMG_SP_DISK_RED, frame);
755 DrawGraphicThruMask(sx, sy, graphic, frame);
758 if (player_is_moving && last_element == EL_EXPLOSION)
761 int graphic = el_act2img(GfxElement[last_jx][last_jy], ACTION_EXPLODING);
763 int stored = Store[last_jx][last_jy];
764 int graphic = (game.emulation != EMU_SUPAPLEX ? IMG_EXPLOSION :
765 stored == EL_SP_INFOTRON ? IMG_SP_EXPLOSION_INFOTRON :
768 int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
769 int phase = ExplodePhase[last_jx][last_jy] - 1;
770 int frame = getGraphicAnimationFrame(graphic, phase - delay);
773 DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy), graphic, frame);
776 /* ----------------------------------------------------------------------- */
777 /* draw elements the player is just walking/passing through/under */
778 /* ----------------------------------------------------------------------- */
780 /* handle the field the player is leaving ... */
781 if (player_is_moving && IS_ACCESSIBLE_INSIDE(last_element))
782 DrawLevelField(last_jx, last_jy);
783 else if (player_is_moving && IS_ACCESSIBLE_UNDER(last_element))
784 DrawLevelFieldThruMask(last_jx, last_jy);
786 /* ... and the field the player is entering */
787 if (IS_ACCESSIBLE_INSIDE(element))
788 DrawLevelField(jx, jy);
789 else if (IS_ACCESSIBLE_UNDER(element))
790 DrawLevelFieldThruMask(jx, jy);
792 if (setup.direct_draw)
794 int dest_x = SX + SCREENX(MIN(jx, last_jx)) * TILEX;
795 int dest_y = SY + SCREENY(MIN(jy, last_jy)) * TILEY;
796 int x_size = TILEX * (1 + ABS(jx - last_jx));
797 int y_size = TILEY * (1 + ABS(jy - last_jy));
799 BlitBitmap(drawto_field, window,
800 dest_x, dest_y, x_size, y_size, dest_x, dest_y);
801 SetDrawtoField(DRAW_DIRECT);
804 MarkTileDirty(sx,sy);
807 void getGraphicSource(int graphic, int frame, Bitmap **bitmap, int *x, int *y)
809 struct GraphicInfo *g = &graphic_info[graphic];
813 if (g->offset_y == 0) /* frames are ordered horizontally */
815 int max_width = g->anim_frames_per_line * g->width;
817 *x = (g->src_x + frame * g->offset_x) % max_width;
818 *y = g->src_y + (g->src_x + frame * g->offset_x) / max_width * g->height;
820 else if (g->offset_x == 0) /* frames are ordered vertically */
822 int max_height = g->anim_frames_per_line * g->height;
824 *x = g->src_x + (g->src_y + frame * g->offset_y) / max_height * g->width;
825 *y = (g->src_y + frame * g->offset_y) % max_height;
827 else /* frames are ordered diagonally */
829 *x = g->src_x + frame * g->offset_x;
830 *y = g->src_y + frame * g->offset_y;
834 void DrawGraphic(int x, int y, int graphic, int frame)
837 if (!IN_SCR_FIELD(x, y))
839 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
840 printf("DrawGraphic(): This should never happen!\n");
845 DrawGraphicExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic, frame);
849 void DrawGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
855 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
856 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
859 void DrawGraphicThruMask(int x, int y, int graphic, int frame)
862 if (!IN_SCR_FIELD(x, y))
864 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
865 printf("DrawGraphicThruMask(): This should never happen!\n");
870 DrawGraphicThruMaskExt(drawto_field, FX + x * TILEX, FY + y *TILEY, graphic,
875 void DrawGraphicThruMaskExt(DrawBuffer *d, int dest_x, int dest_y, int graphic,
883 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
884 drawing_gc = src_bitmap->stored_clip_gc;
886 GC drawing_gc = src_bitmap->stored_clip_gc;
887 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
888 int src_x = graphic_info[graphic].src_x;
889 int src_y = graphic_info[graphic].src_y;
890 int offset_x = graphic_info[graphic].offset_x;
891 int offset_y = graphic_info[graphic].offset_y;
893 src_x += frame * offset_x;
894 src_y += frame * offset_y;
898 SetClipOrigin(src_bitmap, drawing_gc, dest_x - src_x, dest_y - src_y);
899 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX, TILEY, dest_x, dest_y);
902 void DrawMiniGraphic(int x, int y, int graphic)
904 DrawMiniGraphicExt(drawto, SX + x * MINI_TILEX,SY + y * MINI_TILEY, graphic);
905 MarkTileDirty(x / 2, y / 2);
908 void getMiniGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
910 struct GraphicInfo *g = &graphic_info[graphic];
912 int mini_starty = g->bitmap->height * 2 / 3;
915 *x = mini_startx + g->src_x / 2;
916 *y = mini_starty + g->src_y / 2;
919 void DrawMiniGraphicExt(DrawBuffer *d, int x, int y, int graphic)
924 getMiniGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
925 BlitBitmap(src_bitmap, d, src_x, src_y, MINI_TILEX, MINI_TILEY, x, y);
928 void DrawGraphicShifted(int x,int y, int dx,int dy, int graphic, int frame,
929 int cut_mode, int mask_mode)
934 int width = TILEX, height = TILEY;
940 DrawGraphic(x, y, graphic, frame);
944 if (dx || dy) /* shifted graphic */
946 if (x < BX1) /* object enters playfield from the left */
953 else if (x > BX2) /* object enters playfield from the right */
959 else if (x==BX1 && dx < 0) /* object leaves playfield to the left */
965 else if (x==BX2 && dx > 0) /* object leaves playfield to the right */
967 else if (dx) /* general horizontal movement */
968 MarkTileDirty(x + SIGN(dx), y);
970 if (y < BY1) /* object enters playfield from the top */
972 if (cut_mode==CUT_BELOW) /* object completely above top border */
980 else if (y > BY2) /* object enters playfield from the bottom */
986 else if (y==BY1 && dy < 0) /* object leaves playfield to the top */
992 else if (dy > 0 && cut_mode == CUT_ABOVE)
994 if (y == BY2) /* object completely above bottom border */
1000 MarkTileDirty(x, y + 1);
1001 } /* object leaves playfield to the bottom */
1002 else if (dy > 0 && (y == BY2 || cut_mode == CUT_BELOW))
1004 else if (dy) /* general vertical movement */
1005 MarkTileDirty(x, y + SIGN(dy));
1009 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1011 src_bitmap = graphic_info[graphic].bitmap;
1012 src_x = graphic_info[graphic].src_x;
1013 src_y = graphic_info[graphic].src_y;
1014 offset_x = graphic_info[graphic].offset_x;
1015 offset_y = graphic_info[graphic].offset_y;
1017 src_x += frame * offset_x;
1018 src_y += frame * offset_y;
1021 drawing_gc = src_bitmap->stored_clip_gc;
1026 dest_x = FX + x * TILEX + dx;
1027 dest_y = FY + y * TILEY + dy;
1030 if (!IN_SCR_FIELD(x,y))
1032 printf("DrawGraphicShifted(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
1033 printf("DrawGraphicShifted(): This should never happen!\n");
1038 if (mask_mode == USE_MASKING)
1040 SetClipOrigin(src_bitmap, drawing_gc, dest_x - src_x, dest_y - src_y);
1041 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1045 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1051 void DrawGraphicShiftedThruMask(int x, int y, int dx, int dy, int graphic,
1052 int frame, int cut_mode)
1054 DrawGraphicShifted(x,y, dx,dy, graphic, frame, cut_mode, USE_MASKING);
1057 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
1058 int cut_mode, int mask_mode)
1060 int lx = LEVELX(x), ly = LEVELY(y);
1064 if (IN_LEV_FIELD(lx, ly))
1066 SetRandomAnimationValue(lx, ly);
1068 graphic = el_act_dir2img(element, GfxAction[lx][ly], MovDir[lx][ly]);
1069 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1071 else /* border element */
1073 graphic = el2img(element);
1074 frame = getGraphicAnimationFrame(graphic, -1);
1077 if (element == EL_EXPANDABLE_WALL)
1079 boolean left_stopped = FALSE, right_stopped = FALSE;
1081 if (!IN_LEV_FIELD(lx - 1, ly) || IS_WALL(Feld[lx - 1][ly]))
1082 left_stopped = TRUE;
1083 if (!IN_LEV_FIELD(lx + 1, ly) || IS_WALL(Feld[lx + 1][ly]))
1084 right_stopped = TRUE;
1086 if (left_stopped && right_stopped)
1088 else if (left_stopped)
1090 graphic = IMG_EXPANDABLE_WALL_GROWING_RIGHT;
1091 frame = graphic_info[graphic].anim_frames - 1;
1093 else if (right_stopped)
1095 graphic = IMG_EXPANDABLE_WALL_GROWING_LEFT;
1096 frame = graphic_info[graphic].anim_frames - 1;
1101 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, mask_mode);
1102 else if (mask_mode == USE_MASKING)
1103 DrawGraphicThruMask(x, y, graphic, frame);
1105 DrawGraphic(x, y, graphic, frame);
1108 void DrawLevelElementExt(int x, int y, int dx, int dy, int element,
1109 int cut_mode, int mask_mode)
1111 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1112 DrawScreenElementExt(SCREENX(x), SCREENY(y), dx, dy, element,
1113 cut_mode, mask_mode);
1116 void DrawScreenElementShifted(int x, int y, int dx, int dy, int element,
1119 DrawScreenElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1122 void DrawLevelElementShifted(int x, int y, int dx, int dy, int element,
1125 DrawLevelElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1128 void DrawLevelElementThruMask(int x, int y, int element)
1130 DrawLevelElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1133 void DrawLevelFieldThruMask(int x, int y)
1135 DrawLevelElementExt(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
1138 static void DrawLevelFieldCrumbledSandExt(int x, int y, int graphic, int frame)
1142 int sx = SCREENX(x), sy = SCREENY(y);
1144 int width, height, cx, cy, i;
1145 int snip = TILEX / 8; /* number of border pixels from "crumbled graphic" */
1146 static int xy[4][2] =
1154 if (!IN_LEV_FIELD(x, y))
1157 element = (GfxElement[x][y] != EL_UNDEFINED ? GfxElement[x][y] : Feld[x][y]);
1159 /* crumble field itself */
1160 if (CAN_BE_CRUMBLED(element) && !IS_MOVING(x, y))
1162 if (!IN_SCR_FIELD(sx, sy))
1165 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1169 int xx = x + xy[i][0];
1170 int yy = y + xy[i][1];
1172 element = (IN_LEV_FIELD(xx, yy) ? Feld[xx][yy] : BorderElement);
1174 /* check if neighbour field is of same type */
1175 if (CAN_BE_CRUMBLED(element) && !IS_MOVING(xx, yy))
1178 if (i == 1 || i == 2)
1182 cx = (i == 2 ? TILEX - snip : 0);
1190 cy = (i == 3 ? TILEY - snip : 0);
1193 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1194 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
1197 MarkTileDirty(sx, sy);
1199 else /* crumble neighbour fields */
1201 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1205 int xx = x + xy[i][0];
1206 int yy = y + xy[i][1];
1207 int sxx = sx + xy[i][0];
1208 int syy = sy + xy[i][1];
1210 if (!IN_LEV_FIELD(xx, yy) ||
1211 !IN_SCR_FIELD(sxx, syy) ||
1212 !CAN_BE_CRUMBLED(Feld[xx][yy]) ||
1216 if (i == 1 || i == 2)
1220 cx = (i == 1 ? TILEX - snip : 0);
1228 cy = (i==0 ? TILEY-snip : 0);
1231 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1232 width, height, FX + sxx * TILEX + cx, FY + syy * TILEY + cy);
1234 MarkTileDirty(sxx, syy);
1239 void DrawLevelFieldCrumbledSand(int x, int y)
1241 DrawLevelFieldCrumbledSandExt(x, y, IMG_SAND_CRUMBLED, 0);
1244 void DrawLevelFieldCrumbledSandDigging(int x, int y, int direction,
1247 int graphic1 = el_act_dir2img(EL_SAND, ACTION_DIGGING, direction);
1248 int graphic2 = el_act_dir2img(EL_SAND_CRUMBLED, ACTION_DIGGING, direction);
1249 int frame1 = getGraphicAnimationFrame(graphic1, step_frame);
1250 int frame2 = getGraphicAnimationFrame(graphic2, step_frame);
1251 int sx = SCREENX(x), sy = SCREENY(y);
1253 DrawGraphic(sx, sy, graphic1, frame1);
1254 DrawLevelFieldCrumbledSandExt(x, y, graphic2, frame2);
1257 void DrawLevelFieldCrumbledSandNeighbours(int x, int y)
1259 int sx = SCREENX(x), sy = SCREENY(y);
1260 static int xy[4][2] =
1271 int xx = x + xy[i][0];
1272 int yy = y + xy[i][1];
1273 int sxx = sx + xy[i][0];
1274 int syy = sy + xy[i][1];
1276 if (!IN_LEV_FIELD(xx, yy) ||
1277 !IN_SCR_FIELD(sxx, syy) ||
1278 !CAN_BE_CRUMBLED(Feld[xx][yy]) ||
1282 DrawLevelField(xx, yy);
1286 static int getBorderElement(int x, int y)
1290 { EL_STEELWALL_TOPLEFT, EL_INVISIBLE_STEELWALL_TOPLEFT },
1291 { EL_STEELWALL_TOPRIGHT, EL_INVISIBLE_STEELWALL_TOPRIGHT },
1292 { EL_STEELWALL_BOTTOMLEFT, EL_INVISIBLE_STEELWALL_BOTTOMLEFT },
1293 { EL_STEELWALL_BOTTOMRIGHT, EL_INVISIBLE_STEELWALL_BOTTOMRIGHT },
1294 { EL_STEELWALL_VERTICAL, EL_INVISIBLE_STEELWALL_VERTICAL },
1295 { EL_STEELWALL_HORIZONTAL, EL_INVISIBLE_STEELWALL_HORIZONTAL },
1296 { EL_STEELWALL, EL_INVISIBLE_STEELWALL }
1298 int steel_type = (BorderElement == EL_STEELWALL ? 0 : 1);
1299 int steel_position = (x == -1 && y == -1 ? 0 :
1300 x == lev_fieldx && y == -1 ? 1 :
1301 x == -1 && y == lev_fieldy ? 2 :
1302 x == lev_fieldx && y == lev_fieldy ? 3 :
1303 x == -1 || x == lev_fieldx ? 4 :
1304 y == -1 || y == lev_fieldy ? 5 : 6);
1306 return border[steel_position][steel_type];
1309 void DrawScreenElement(int x, int y, int element)
1311 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
1312 DrawLevelFieldCrumbledSand(LEVELX(x), LEVELY(y));
1315 void DrawLevelElement(int x, int y, int element)
1317 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1318 DrawScreenElement(SCREENX(x), SCREENY(y), element);
1321 void DrawScreenField(int x, int y)
1323 int lx = LEVELX(x), ly = LEVELY(y);
1324 int element, content;
1326 if (!IN_LEV_FIELD(lx, ly))
1328 if (lx < -1 || lx > lev_fieldx || ly < -1 || ly > lev_fieldy)
1331 element = getBorderElement(lx, ly);
1333 DrawScreenElement(x, y, element);
1337 element = Feld[lx][ly];
1338 content = Store[lx][ly];
1340 if (IS_MOVING(lx, ly))
1342 int horiz_move = (MovDir[lx][ly] == MV_LEFT || MovDir[lx][ly] == MV_RIGHT);
1343 boolean cut_mode = NO_CUTTING;
1345 if (element == EL_QUICKSAND_EMPTYING ||
1346 element == EL_MAGIC_WALL_EMPTYING ||
1347 element == EL_BD_MAGIC_WALL_EMPTYING ||
1348 element == EL_AMOEBA_DROPPING)
1349 cut_mode = CUT_ABOVE;
1350 else if (element == EL_QUICKSAND_FILLING ||
1351 element == EL_MAGIC_WALL_FILLING ||
1352 element == EL_BD_MAGIC_WALL_FILLING)
1353 cut_mode = CUT_BELOW;
1355 if (cut_mode == CUT_ABOVE)
1356 DrawScreenElementShifted(x, y, 0, 0, element, NO_CUTTING);
1358 DrawScreenElement(x, y, EL_EMPTY);
1361 DrawScreenElementShifted(x, y, MovPos[lx][ly], 0, element, NO_CUTTING);
1362 else if (cut_mode == NO_CUTTING)
1363 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], element, cut_mode);
1365 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], content, cut_mode);
1367 if (content == EL_ACID)
1368 DrawLevelElementThruMask(lx, ly + 1, EL_ACID);
1370 else if (IS_BLOCKED(lx, ly))
1375 boolean cut_mode = NO_CUTTING;
1376 int element_old, content_old;
1378 Blocked2Moving(lx, ly, &oldx, &oldy);
1381 horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
1382 MovDir[oldx][oldy] == MV_RIGHT);
1384 element_old = Feld[oldx][oldy];
1385 content_old = Store[oldx][oldy];
1387 if (element_old == EL_QUICKSAND_EMPTYING ||
1388 element_old == EL_MAGIC_WALL_EMPTYING ||
1389 element_old == EL_BD_MAGIC_WALL_EMPTYING ||
1390 element_old == EL_AMOEBA_DROPPING)
1391 cut_mode = CUT_ABOVE;
1393 DrawScreenElement(x, y, EL_EMPTY);
1396 DrawScreenElementShifted(sx, sy, MovPos[oldx][oldy], 0, element_old,
1398 else if (cut_mode == NO_CUTTING)
1399 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], element_old,
1402 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], content_old,
1405 else if (IS_DRAWABLE(element))
1406 DrawScreenElement(x, y, element);
1408 DrawScreenElement(x, y, EL_EMPTY);
1411 void DrawLevelField(int x, int y)
1413 if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1414 DrawScreenField(SCREENX(x), SCREENY(y));
1415 else if (IS_MOVING(x, y))
1419 Moving2Blocked(x, y, &newx, &newy);
1420 if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
1421 DrawScreenField(SCREENX(newx), SCREENY(newy));
1423 else if (IS_BLOCKED(x, y))
1427 Blocked2Moving(x, y, &oldx, &oldy);
1428 if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
1429 DrawScreenField(SCREENX(oldx), SCREENY(oldy));
1433 void DrawMiniElement(int x, int y, int element)
1437 graphic = el2edimg(element);
1438 DrawMiniGraphic(x, y, graphic);
1441 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
1443 int x = sx + scroll_x, y = sy + scroll_y;
1445 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
1446 DrawMiniElement(sx, sy, EL_EMPTY);
1447 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
1448 DrawMiniElement(sx, sy, Feld[x][y]);
1450 DrawMiniGraphic(sx, sy, el2edimg(getBorderElement(x, y)));
1453 void getMicroGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
1455 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
1456 int mini_startx = src_bitmap->width * 3 / 4;
1457 int mini_starty = src_bitmap->height * 2 / 3;
1458 int src_x = mini_startx + graphic_info[graphic].src_x / 8;
1459 int src_y = mini_starty + graphic_info[graphic].src_y / 8;
1461 *bitmap = src_bitmap;
1466 void DrawMicroElement(int xpos, int ypos, int element)
1470 int graphic = el2preimg(element);
1472 getMicroGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
1473 BlitBitmap(src_bitmap, drawto, src_x, src_y, MICRO_TILEX, MICRO_TILEY,
1481 SetDrawBackgroundMask(REDRAW_NONE);
1484 for(x=BX1; x<=BX2; x++)
1485 for(y=BY1; y<=BY2; y++)
1486 DrawScreenField(x, y);
1488 redraw_mask |= REDRAW_FIELD;
1491 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
1495 for(x=0; x<size_x; x++)
1496 for(y=0; y<size_y; y++)
1497 DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
1499 redraw_mask |= REDRAW_FIELD;
1502 static void DrawMicroLevelExt(int xpos, int ypos, int from_x, int from_y)
1506 DrawBackground(xpos, ypos, MICROLEV_XSIZE, MICROLEV_YSIZE);
1508 if (lev_fieldx < STD_LEV_FIELDX)
1509 xpos += (STD_LEV_FIELDX - lev_fieldx) / 2 * MICRO_TILEX;
1510 if (lev_fieldy < STD_LEV_FIELDY)
1511 ypos += (STD_LEV_FIELDY - lev_fieldy) / 2 * MICRO_TILEY;
1513 xpos += MICRO_TILEX;
1514 ypos += MICRO_TILEY;
1516 for(x=-1; x<=STD_LEV_FIELDX; x++)
1518 for(y=-1; y<=STD_LEV_FIELDY; y++)
1520 int lx = from_x + x, ly = from_y + y;
1522 if (lx >= 0 && lx < lev_fieldx && ly >= 0 && ly < lev_fieldy)
1523 DrawMicroElement(xpos + x * MICRO_TILEX, ypos + y * MICRO_TILEY,
1524 level.field[lx][ly]);
1525 else if (lx >= -1 && lx < lev_fieldx+1 && ly >= -1 && ly < lev_fieldy+1
1526 && BorderElement != EL_EMPTY)
1527 DrawMicroElement(xpos + x * MICRO_TILEX, ypos + y * MICRO_TILEY,
1528 getBorderElement(lx, ly));
1532 redraw_mask |= REDRAW_MICROLEVEL;
1535 #define MICROLABEL_EMPTY 0
1536 #define MICROLABEL_LEVEL_NAME 1
1537 #define MICROLABEL_CREATED_BY 2
1538 #define MICROLABEL_LEVEL_AUTHOR 3
1539 #define MICROLABEL_IMPORTED_FROM 4
1540 #define MICROLABEL_LEVEL_IMPORT_INFO 5
1542 static void DrawMicroLevelLabelExt(int mode)
1544 char label_text[MAX_OUTPUT_LINESIZE + 1];
1545 int max_len_label_text;
1546 int font_nr = FONT_TEXT_2;
1548 if (mode == MICROLABEL_CREATED_BY || mode == MICROLABEL_IMPORTED_FROM)
1549 font_nr = FONT_TEXT_3;
1551 max_len_label_text = SXSIZE / getFontWidth(font_nr);
1553 DrawBackground(SX, MICROLABEL_YPOS, SXSIZE, getFontHeight(font_nr));
1555 strncpy(label_text, (mode == MICROLABEL_LEVEL_NAME ? level.name :
1556 mode == MICROLABEL_CREATED_BY ? "created by" :
1557 mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
1558 mode == MICROLABEL_IMPORTED_FROM ? "imported from" :
1559 mode == MICROLABEL_LEVEL_IMPORT_INFO ?
1560 leveldir_current->imported_from : ""),
1561 max_len_label_text);
1562 label_text[max_len_label_text] = '\0';
1564 if (strlen(label_text) > 0)
1566 int text_width = strlen(label_text) * getFontWidth(font_nr);
1567 int lxpos = SX + (SXSIZE - text_width) / 2;
1568 int lypos = MICROLABEL_YPOS;
1570 DrawText(lxpos, lypos, label_text, font_nr);
1573 redraw_mask |= REDRAW_MICROLEVEL;
1576 void DrawMicroLevel(int xpos, int ypos, boolean restart)
1578 static unsigned long scroll_delay = 0;
1579 static unsigned long label_delay = 0;
1580 static int from_x, from_y, scroll_direction;
1581 static int label_state, label_counter;
1582 int last_game_status = game_status; /* save current game status */
1584 /* force PREVIEW font on preview level */
1585 game_status = GAME_MODE_PSEUDO_PREVIEW;
1589 from_x = from_y = 0;
1590 scroll_direction = MV_RIGHT;
1594 DrawMicroLevelExt(xpos, ypos, from_x, from_y);
1595 DrawMicroLevelLabelExt(label_state);
1597 /* initialize delay counters */
1598 DelayReached(&scroll_delay, 0);
1599 DelayReached(&label_delay, 0);
1601 if (leveldir_current->name)
1603 int len = strlen(leveldir_current->name);
1604 int lxpos = SX + (SXSIZE - len * getFontWidth(FONT_TEXT_1)) / 2;
1605 int lypos = SY + 352;
1607 DrawText(lxpos, lypos, leveldir_current->name, FONT_TEXT_1);
1610 game_status = last_game_status; /* restore current game status */
1615 /* scroll micro level, if needed */
1616 if ((lev_fieldx > STD_LEV_FIELDX || lev_fieldy > STD_LEV_FIELDY) &&
1617 DelayReached(&scroll_delay, MICROLEVEL_SCROLL_DELAY))
1619 switch (scroll_direction)
1625 scroll_direction = MV_UP;
1629 if (from_x < lev_fieldx - STD_LEV_FIELDX)
1632 scroll_direction = MV_DOWN;
1639 scroll_direction = MV_RIGHT;
1643 if (from_y < lev_fieldy - STD_LEV_FIELDY)
1646 scroll_direction = MV_LEFT;
1653 DrawMicroLevelExt(xpos, ypos, from_x, from_y);
1656 /* redraw micro level label, if needed */
1657 if (strcmp(level.name, NAMELESS_LEVEL_NAME) != 0 &&
1658 strcmp(level.author, ANONYMOUS_NAME) != 0 &&
1659 strcmp(level.author, leveldir_current->name) != 0 &&
1660 DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
1662 int max_label_counter = 23;
1664 if (leveldir_current->imported_from != NULL)
1665 max_label_counter += 14;
1667 label_counter = (label_counter + 1) % max_label_counter;
1668 label_state = (label_counter >= 0 && label_counter <= 7 ?
1669 MICROLABEL_LEVEL_NAME :
1670 label_counter >= 9 && label_counter <= 12 ?
1671 MICROLABEL_CREATED_BY :
1672 label_counter >= 14 && label_counter <= 21 ?
1673 MICROLABEL_LEVEL_AUTHOR :
1674 label_counter >= 23 && label_counter <= 26 ?
1675 MICROLABEL_IMPORTED_FROM :
1676 label_counter >= 28 && label_counter <= 35 ?
1677 MICROLABEL_LEVEL_IMPORT_INFO : MICROLABEL_EMPTY);
1678 DrawMicroLevelLabelExt(label_state);
1681 game_status = last_game_status; /* restore current game status */
1684 int REQ_in_range(int x, int y)
1686 if (y > DY+249 && y < DY+278)
1688 if (x > DX+1 && x < DX+48)
1690 else if (x > DX+51 && x < DX+98)
1696 #define MAX_REQUEST_LINES 13
1697 #define MAX_REQUEST_LINE_LEN 7
1699 boolean Request(char *text, unsigned int req_state)
1701 int mx, my, ty, result = -1;
1702 unsigned int old_door_state;
1703 int last_game_status = game_status; /* save current game status */
1705 #if defined(PLATFORM_UNIX)
1706 /* pause network game while waiting for request to answer */
1707 if (options.network &&
1708 game_status == GAME_MODE_PLAYING &&
1709 req_state & REQUEST_WAIT_FOR)
1710 SendToServer_PausePlaying();
1713 old_door_state = GetDoorState();
1715 /* simulate releasing mouse button over last gadget, if still pressed */
1717 HandleGadgets(-1, -1, 0);
1721 CloseDoor(DOOR_CLOSE_1);
1723 /* save old door content */
1724 BlitBitmap(bitmap_db_door, bitmap_db_door,
1725 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
1726 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
1728 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
1730 /* clear door drawing field */
1731 DrawBackground(DX, DY, DXSIZE, DYSIZE);
1733 /* force DOOR font on preview level */
1734 game_status = GAME_MODE_PSEUDO_DOOR;
1736 /* write text for request */
1737 for(ty=0; ty < MAX_REQUEST_LINES; ty++)
1739 char text_line[MAX_REQUEST_LINE_LEN + 1];
1745 for(tl=0,tx=0; tx < MAX_REQUEST_LINE_LEN; tl++,tx++)
1748 if (!tc || tc == ' ')
1759 strncpy(text_line, text, tl);
1762 DrawText(DX + (DXSIZE - tl * getFontWidth(FONT_TEXT_2)) / 2,
1763 DY + 8 + ty * (getFontHeight(FONT_TEXT_2) + 2),
1764 text_line, FONT_TEXT_2);
1766 text += tl + (tc == ' ' ? 1 : 0);
1769 game_status = last_game_status; /* restore current game status */
1771 if (req_state & REQ_ASK)
1773 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
1774 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
1776 else if (req_state & REQ_CONFIRM)
1778 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
1780 else if (req_state & REQ_PLAYER)
1782 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
1783 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
1784 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
1785 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
1788 /* copy request gadgets to door backbuffer */
1789 BlitBitmap(drawto, bitmap_db_door,
1790 DX, DY, DXSIZE, DYSIZE,
1791 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
1793 OpenDoor(DOOR_OPEN_1);
1799 if (!(req_state & REQUEST_WAIT_FOR))
1801 SetDrawBackgroundMask(REDRAW_FIELD);
1806 if (game_status != GAME_MODE_MAIN)
1809 button_status = MB_RELEASED;
1811 request_gadget_id = -1;
1813 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
1825 case EVENT_BUTTONPRESS:
1826 case EVENT_BUTTONRELEASE:
1827 case EVENT_MOTIONNOTIFY:
1829 if (event.type == EVENT_MOTIONNOTIFY)
1831 if (!PointerInWindow(window))
1832 continue; /* window and pointer are on different screens */
1837 motion_status = TRUE;
1838 mx = ((MotionEvent *) &event)->x;
1839 my = ((MotionEvent *) &event)->y;
1843 motion_status = FALSE;
1844 mx = ((ButtonEvent *) &event)->x;
1845 my = ((ButtonEvent *) &event)->y;
1846 if (event.type == EVENT_BUTTONPRESS)
1847 button_status = ((ButtonEvent *) &event)->button;
1849 button_status = MB_RELEASED;
1852 /* this sets 'request_gadget_id' */
1853 HandleGadgets(mx, my, button_status);
1855 switch(request_gadget_id)
1857 case TOOL_CTRL_ID_YES:
1860 case TOOL_CTRL_ID_NO:
1863 case TOOL_CTRL_ID_CONFIRM:
1864 result = TRUE | FALSE;
1867 case TOOL_CTRL_ID_PLAYER_1:
1870 case TOOL_CTRL_ID_PLAYER_2:
1873 case TOOL_CTRL_ID_PLAYER_3:
1876 case TOOL_CTRL_ID_PLAYER_4:
1887 case EVENT_KEYPRESS:
1888 switch(GetEventKey((KeyEvent *)&event, TRUE))
1901 if (req_state & REQ_PLAYER)
1905 case EVENT_KEYRELEASE:
1906 ClearPlayerAction();
1910 HandleOtherEvents(&event);
1914 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
1916 int joy = AnyJoystick();
1918 if (joy & JOY_BUTTON_1)
1920 else if (joy & JOY_BUTTON_2)
1926 /* don't eat all CPU time */
1930 if (game_status != GAME_MODE_MAIN)
1935 if (!(req_state & REQ_STAY_OPEN))
1937 CloseDoor(DOOR_CLOSE_1);
1939 if (!(req_state & REQ_STAY_CLOSED) && (old_door_state & DOOR_OPEN_1))
1941 BlitBitmap(bitmap_db_door, bitmap_db_door,
1942 DOOR_GFX_PAGEX2,DOOR_GFX_PAGEY1, DXSIZE,DYSIZE,
1943 DOOR_GFX_PAGEX1,DOOR_GFX_PAGEY1);
1944 OpenDoor(DOOR_OPEN_1);
1950 SetDrawBackgroundMask(REDRAW_FIELD);
1952 #if defined(PLATFORM_UNIX)
1953 /* continue network game after request */
1954 if (options.network &&
1955 game_status == GAME_MODE_PLAYING &&
1956 req_state & REQUEST_WAIT_FOR)
1957 SendToServer_ContinuePlaying();
1963 unsigned int OpenDoor(unsigned int door_state)
1965 unsigned int new_door_state;
1967 if (door_state & DOOR_COPY_BACK)
1969 BlitBitmap(bitmap_db_door, bitmap_db_door,
1970 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE + VYSIZE,
1971 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
1972 door_state &= ~DOOR_COPY_BACK;
1975 new_door_state = MoveDoor(door_state);
1977 return(new_door_state);
1980 unsigned int CloseDoor(unsigned int door_state)
1982 unsigned int new_door_state;
1984 BlitBitmap(backbuffer, bitmap_db_door,
1985 DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
1986 BlitBitmap(backbuffer, bitmap_db_door,
1987 VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
1989 new_door_state = MoveDoor(door_state);
1991 return(new_door_state);
1994 unsigned int GetDoorState()
1996 return MoveDoor(DOOR_GET_STATE);
1999 unsigned int SetDoorState(unsigned int door_state)
2001 return MoveDoor(door_state | DOOR_SET_STATE);
2004 unsigned int MoveDoor(unsigned int door_state)
2006 static int door1 = DOOR_OPEN_1;
2007 static int door2 = DOOR_CLOSE_2;
2008 static unsigned long door_delay = 0;
2009 int x, start, stepsize = door.step_offset;
2010 unsigned long door_delay_value = door.step_delay;
2012 if (door_state == DOOR_GET_STATE)
2013 return(door1 | door2);
2015 if (door_state & DOOR_SET_STATE)
2017 if (door_state & DOOR_ACTION_1)
2018 door1 = door_state & DOOR_ACTION_1;
2019 if (door_state & DOOR_ACTION_2)
2020 door2 = door_state & DOOR_ACTION_2;
2022 return(door1 | door2);
2025 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
2026 door_state &= ~DOOR_OPEN_1;
2027 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
2028 door_state &= ~DOOR_CLOSE_1;
2029 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
2030 door_state &= ~DOOR_OPEN_2;
2031 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
2032 door_state &= ~DOOR_CLOSE_2;
2034 if (setup.quick_doors)
2037 door_delay_value = 0;
2039 StopSound(SND_DOOR_OPENING);
2040 StopSound(SND_DOOR_CLOSING);
2043 if (global.autoplay_leveldir)
2045 door_state |= DOOR_NO_DELAY;
2046 door_state &= ~DOOR_CLOSE_ALL;
2049 if (door_state & DOOR_ACTION)
2051 if (!(door_state & DOOR_NO_DELAY))
2053 /* opening door sound has priority over simultaneously closing door */
2054 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
2055 PlaySoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
2056 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
2057 PlaySoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
2060 start = ((door_state & DOOR_NO_DELAY) ? DXSIZE : 0);
2062 for(x=start; x<=DXSIZE; x+=stepsize)
2064 Bitmap *bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
2065 GC gc = bitmap->stored_clip_gc;
2067 if (!(door_state & DOOR_NO_DELAY))
2068 WaitUntilDelayReached(&door_delay, door_delay_value);
2070 if (door_state & DOOR_ACTION_1)
2072 int i = (door_state & DOOR_OPEN_1 ? DXSIZE-x : x);
2073 int j = (DXSIZE - i) / 3;
2075 BlitBitmap(bitmap_db_door, drawto,
2076 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + i/2,
2077 DXSIZE,DYSIZE - i/2, DX, DY);
2079 ClearRectangle(drawto, DX, DY + DYSIZE - i/2, DXSIZE,i/2);
2081 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2082 BlitBitmapMasked(bitmap, drawto,
2083 DXSIZE, DOOR_GFX_PAGEY1, i, 77,
2084 DX + DXSIZE - i, DY + j);
2085 BlitBitmapMasked(bitmap, drawto,
2086 DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63,
2087 DX + DXSIZE - i, DY + 140 + j);
2088 SetClipOrigin(bitmap, gc, DX - DXSIZE + i, DY - (DOOR_GFX_PAGEY1 + j));
2089 BlitBitmapMasked(bitmap, drawto,
2090 DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j,
2092 BlitBitmapMasked(bitmap, drawto,
2093 DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63,
2096 BlitBitmapMasked(bitmap, drawto,
2097 DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
2099 BlitBitmapMasked(bitmap, drawto,
2100 DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
2102 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2103 BlitBitmapMasked(bitmap, drawto,
2104 DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
2105 DX + DXSIZE - i, DY + 77 + j);
2106 BlitBitmapMasked(bitmap, drawto,
2107 DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
2108 DX + DXSIZE - i, DY + 203 + j);
2110 redraw_mask |= REDRAW_DOOR_1;
2113 if (door_state & DOOR_ACTION_2)
2115 int i = (door_state & DOOR_OPEN_2 ? VXSIZE - x : x);
2116 int j = (VXSIZE - i) / 3;
2118 BlitBitmap(bitmap_db_door, drawto,
2119 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + i/2,
2120 VXSIZE, VYSIZE - i/2, VX, VY);
2122 ClearRectangle(drawto, VX, VY + VYSIZE-i/2, VXSIZE, i/2);
2124 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2125 BlitBitmapMasked(bitmap, drawto,
2126 VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2,
2127 VX + VXSIZE-i, VY+j);
2128 SetClipOrigin(bitmap, gc,
2129 VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
2130 BlitBitmapMasked(bitmap, drawto,
2131 VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j,
2134 BlitBitmapMasked(bitmap, drawto,
2135 VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2,
2136 i, VYSIZE / 2, VX, VY + VYSIZE / 2 - j);
2137 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2138 BlitBitmapMasked(bitmap, drawto,
2139 VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2,
2141 VX + VXSIZE - i, VY + VYSIZE / 2 + j);
2143 redraw_mask |= REDRAW_DOOR_2;
2148 if (game_status == GAME_MODE_MAIN)
2153 if (setup.quick_doors)
2155 StopSound(SND_DOOR_OPENING);
2156 StopSound(SND_DOOR_CLOSING);
2159 if (door_state & DOOR_ACTION_1)
2160 door1 = door_state & DOOR_ACTION_1;
2161 if (door_state & DOOR_ACTION_2)
2162 door2 = door_state & DOOR_ACTION_2;
2164 return (door1 | door2);
2167 void DrawSpecialEditorDoor()
2169 /* draw bigger toolbox window */
2170 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
2171 DOOR_GFX_PAGEX7, 0, EXSIZE + 8, 8,
2173 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
2174 EX - 4, VY - 4, EXSIZE + 8, EYSIZE - VYSIZE + 4,
2177 redraw_mask |= REDRAW_ALL;
2180 void UndrawSpecialEditorDoor()
2182 /* draw normal tape recorder window */
2183 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
2184 EX - 4, EY - 12, EXSIZE + 8, EYSIZE - VYSIZE + 12,
2187 redraw_mask |= REDRAW_ALL;
2191 /* ---------- new tool button stuff ---------------------------------------- */
2193 /* graphic position values for tool buttons */
2194 #define TOOL_BUTTON_YES_XPOS 2
2195 #define TOOL_BUTTON_YES_YPOS 250
2196 #define TOOL_BUTTON_YES_GFX_YPOS 0
2197 #define TOOL_BUTTON_YES_XSIZE 46
2198 #define TOOL_BUTTON_YES_YSIZE 28
2199 #define TOOL_BUTTON_NO_XPOS 52
2200 #define TOOL_BUTTON_NO_YPOS TOOL_BUTTON_YES_YPOS
2201 #define TOOL_BUTTON_NO_GFX_YPOS TOOL_BUTTON_YES_GFX_YPOS
2202 #define TOOL_BUTTON_NO_XSIZE TOOL_BUTTON_YES_XSIZE
2203 #define TOOL_BUTTON_NO_YSIZE TOOL_BUTTON_YES_YSIZE
2204 #define TOOL_BUTTON_CONFIRM_XPOS TOOL_BUTTON_YES_XPOS
2205 #define TOOL_BUTTON_CONFIRM_YPOS TOOL_BUTTON_YES_YPOS
2206 #define TOOL_BUTTON_CONFIRM_GFX_YPOS 30
2207 #define TOOL_BUTTON_CONFIRM_XSIZE 96
2208 #define TOOL_BUTTON_CONFIRM_YSIZE TOOL_BUTTON_YES_YSIZE
2209 #define TOOL_BUTTON_PLAYER_XSIZE 30
2210 #define TOOL_BUTTON_PLAYER_YSIZE 30
2211 #define TOOL_BUTTON_PLAYER_GFX_XPOS 5
2212 #define TOOL_BUTTON_PLAYER_GFX_YPOS 185
2213 #define TOOL_BUTTON_PLAYER_XPOS (5 + TOOL_BUTTON_PLAYER_XSIZE / 2)
2214 #define TOOL_BUTTON_PLAYER_YPOS (215 - TOOL_BUTTON_PLAYER_YSIZE / 2)
2215 #define TOOL_BUTTON_PLAYER1_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2216 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2217 #define TOOL_BUTTON_PLAYER2_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2218 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2219 #define TOOL_BUTTON_PLAYER3_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2220 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2221 #define TOOL_BUTTON_PLAYER4_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2222 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2223 #define TOOL_BUTTON_PLAYER1_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2224 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2225 #define TOOL_BUTTON_PLAYER2_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2226 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2227 #define TOOL_BUTTON_PLAYER3_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2228 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2229 #define TOOL_BUTTON_PLAYER4_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2230 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2239 } toolbutton_info[NUM_TOOL_BUTTONS] =
2242 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_GFX_YPOS,
2243 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_YPOS,
2244 TOOL_BUTTON_YES_XSIZE, TOOL_BUTTON_YES_YSIZE,
2249 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_GFX_YPOS,
2250 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_YPOS,
2251 TOOL_BUTTON_NO_XSIZE, TOOL_BUTTON_NO_YSIZE,
2256 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_GFX_YPOS,
2257 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_YPOS,
2258 TOOL_BUTTON_CONFIRM_XSIZE, TOOL_BUTTON_CONFIRM_YSIZE,
2259 TOOL_CTRL_ID_CONFIRM,
2263 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2264 TOOL_BUTTON_PLAYER1_XPOS, TOOL_BUTTON_PLAYER1_YPOS,
2265 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2266 TOOL_CTRL_ID_PLAYER_1,
2270 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2271 TOOL_BUTTON_PLAYER2_XPOS, TOOL_BUTTON_PLAYER2_YPOS,
2272 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2273 TOOL_CTRL_ID_PLAYER_2,
2277 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2278 TOOL_BUTTON_PLAYER3_XPOS, TOOL_BUTTON_PLAYER3_YPOS,
2279 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2280 TOOL_CTRL_ID_PLAYER_3,
2284 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2285 TOOL_BUTTON_PLAYER4_XPOS, TOOL_BUTTON_PLAYER4_YPOS,
2286 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2287 TOOL_CTRL_ID_PLAYER_4,
2292 void CreateToolButtons()
2296 for (i=0; i<NUM_TOOL_BUTTONS; i++)
2298 Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
2299 Bitmap *deco_bitmap = None;
2300 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
2301 struct GadgetInfo *gi;
2302 unsigned long event_mask;
2303 int gd_xoffset, gd_yoffset;
2304 int gd_x1, gd_x2, gd_y;
2307 event_mask = GD_EVENT_RELEASED;
2309 gd_xoffset = toolbutton_info[i].xpos;
2310 gd_yoffset = toolbutton_info[i].ypos;
2311 gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
2312 gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
2313 gd_y = DOOR_GFX_PAGEY1 + gd_yoffset;
2315 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
2317 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
2319 getMiniGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr),
2320 &deco_bitmap, &deco_x, &deco_y);
2321 deco_xpos = (toolbutton_info[i].width - MINI_TILEX) / 2;
2322 deco_ypos = (toolbutton_info[i].height - MINI_TILEY) / 2;
2325 gi = CreateGadget(GDI_CUSTOM_ID, id,
2326 GDI_INFO_TEXT, toolbutton_info[i].infotext,
2327 GDI_X, DX + toolbutton_info[i].x,
2328 GDI_Y, DY + toolbutton_info[i].y,
2329 GDI_WIDTH, toolbutton_info[i].width,
2330 GDI_HEIGHT, toolbutton_info[i].height,
2331 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
2332 GDI_STATE, GD_BUTTON_UNPRESSED,
2333 GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
2334 GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
2335 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
2336 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
2337 GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
2338 GDI_DECORATION_SHIFTING, 1, 1,
2339 GDI_EVENT_MASK, event_mask,
2340 GDI_CALLBACK_ACTION, HandleToolButtons,
2344 Error(ERR_EXIT, "cannot create gadget");
2346 tool_gadget[id] = gi;
2350 void FreeToolButtons()
2354 for (i=0; i<NUM_TOOL_BUTTONS; i++)
2355 FreeGadget(tool_gadget[i]);
2358 static void UnmapToolButtons()
2362 for (i=0; i<NUM_TOOL_BUTTONS; i++)
2363 UnmapGadget(tool_gadget[i]);
2366 static void HandleToolButtons(struct GadgetInfo *gi)
2368 request_gadget_id = gi->custom_id;
2371 int get_next_element(int element)
2375 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
2376 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
2377 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
2378 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
2379 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
2380 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
2381 case EL_AMOEBA_DROPPING: return EL_AMOEBA_WET;
2383 default: return element;
2387 int el_act_dir2img(int element, int action, int direction)
2389 element = GFX_ELEMENT(element);
2390 direction = MV_DIR_BIT(direction);
2392 return element_info[element].direction_graphic[action][direction];
2395 int el_act2img(int element, int action)
2397 element = GFX_ELEMENT(element);
2399 return element_info[element].graphic[action];
2402 int el_dir2img(int element, int direction)
2404 element = GFX_ELEMENT(element);
2406 return el_act_dir2img(element, ACTION_DEFAULT, direction);
2409 int el2img(int element)
2411 element = GFX_ELEMENT(element);
2413 return element_info[element].graphic[ACTION_DEFAULT];
2416 int el2edimg(int element)
2418 element = GFX_ELEMENT(element);
2420 return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
2423 int el2preimg(int element)
2425 element = GFX_ELEMENT(element);
2427 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];