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);
246 if (redraw_mask & REDRAW_DOOR_3)
247 BlitBitmap(backbuffer, window, EX, EY, EXSIZE, EYSIZE, EX, EY);
248 redraw_mask &= ~REDRAW_DOORS;
251 if (redraw_mask & REDRAW_MICROLEVEL)
253 BlitBitmap(backbuffer, window,
254 MICROLEV_XPOS, MICROLEV_YPOS, MICROLEV_XSIZE, MICROLEV_YSIZE,
255 MICROLEV_XPOS, MICROLEV_YPOS);
256 BlitBitmap(backbuffer, window,
257 SX, MICROLABEL_YPOS, SXSIZE, getFontHeight(FONT_SPECIAL_GAME),
258 SX, MICROLABEL_YPOS);
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_DEFAULT_SMALL, FONT_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 == PLAYING)
394 ClearRectangle(fieldbuffer, 0, 0, FXSIZE, FYSIZE);
395 SetDrawtoField(DRAW_BUFFERED);
398 SetDrawtoField(DRAW_BACKBUFFER);
400 if (setup.direct_draw && game_status == 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)
486 DrawGraphicAnimation(SCREENX(x), SCREENY(y), el2img(element));
489 inline void DrawLevelGraphicAnimationIfNeeded(int x, int y, int graphic)
491 int sx = SCREENX(x), sy = SCREENY(y);
493 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
496 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
499 DrawGraphicAnimation(sx, sy, graphic);
502 void DrawLevelElementAnimationIfNeeded(int x, int y, int element)
504 int sx = SCREENX(x), sy = SCREENY(y);
507 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
510 graphic = el_act_dir2img(element, GfxAction[x][y], MovDir[x][y]);
512 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
515 DrawGraphicAnimation(sx, sy, graphic);
518 void DrawAllPlayers()
522 for(i=0; i<MAX_PLAYERS; i++)
523 if (stored_player[i].active)
524 DrawPlayer(&stored_player[i]);
527 void DrawPlayerField(int x, int y)
529 if (!IS_PLAYER(x, y))
532 DrawPlayer(PLAYERINFO(x, y));
535 void DrawPlayer(struct PlayerInfo *player)
537 int jx = player->jx, jy = player->jy;
538 int last_jx = player->last_jx, last_jy = player->last_jy;
539 int next_jx = jx + (jx - last_jx), next_jy = jy + (jy - last_jy);
540 int sx = SCREENX(jx), sy = SCREENY(jy);
541 int sxx = 0, syy = 0;
542 int element = Feld[jx][jy], last_element = Feld[last_jx][last_jy];
545 boolean player_is_moving = (last_jx != jx || last_jy != jy ? TRUE : FALSE);
547 if (!player->active || !IN_SCR_FIELD(SCREENX(last_jx), SCREENY(last_jy)))
551 if (!IN_LEV_FIELD(jx,jy))
553 printf("DrawPlayerField(): x = %d, y = %d\n",jx,jy);
554 printf("DrawPlayerField(): sx = %d, sy = %d\n",sx,sy);
555 printf("DrawPlayerField(): This should never happen!\n");
560 if (element == EL_EXPLOSION)
563 /* ----------------------------------------------------------------------- */
564 /* draw things in the field the player is leaving, if needed */
565 /* ----------------------------------------------------------------------- */
567 if (player_is_moving)
569 if (Store[last_jx][last_jy] && IS_DRAWABLE(last_element))
571 DrawLevelElement(last_jx, last_jy, Store[last_jx][last_jy]);
573 if (last_element == EL_DYNAMITE_ACTIVE)
574 DrawDynamite(last_jx, last_jy);
576 DrawLevelFieldThruMask(last_jx, last_jy);
578 else if (last_element == EL_DYNAMITE_ACTIVE)
579 DrawDynamite(last_jx, last_jy);
581 DrawLevelField(last_jx, last_jy);
583 if (player->Pushing && IN_SCR_FIELD(SCREENX(next_jx), SCREENY(next_jy)))
587 if (Feld[next_jx][next_jy] == EL_SOKOBAN_FIELD_FULL)
588 DrawLevelElement(next_jx, next_jy, EL_SOKOBAN_FIELD_EMPTY);
590 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
593 DrawLevelField(next_jx, next_jy);
597 if (!IN_SCR_FIELD(sx, sy))
600 if (setup.direct_draw)
601 SetDrawtoField(DRAW_BUFFERED);
603 /* ----------------------------------------------------------------------- */
604 /* draw things behind the player, if needed */
605 /* ----------------------------------------------------------------------- */
608 DrawLevelElement(jx, jy, Store[jx][jy]);
609 else if (!IS_ACTIVE_BOMB(element))
610 DrawLevelField(jx, jy);
612 DrawLevelElement(jx, jy, EL_EMPTY);
614 /* ----------------------------------------------------------------------- */
615 /* draw player himself */
616 /* ----------------------------------------------------------------------- */
618 player->GfxAction = (player->Pushing ? ACTION_PUSHING :
619 player->is_digging ? ACTION_DIGGING :
620 player->is_moving ? ACTION_MOVING :
621 player->snapped ? ACTION_SNAPPING : ACTION_DEFAULT);
623 if (player->use_murphy_graphic)
625 static int last_horizontal_dir = MV_LEFT;
628 if (player->MovDir == MV_LEFT || player->MovDir == MV_RIGHT)
629 last_horizontal_dir = player->MovDir;
631 direction = (player->snapped ? player->MovDir : last_horizontal_dir);
633 graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, direction);
636 graphic = el_act_dir2img(player->element_nr, player->GfxAction,
639 frame = getGraphicAnimationFrame(graphic, player->Frame);
643 if (player->MovDir == MV_LEFT || player->MovDir == MV_RIGHT)
644 sxx = player->GfxPos;
646 syy = player->GfxPos;
649 if (!setup.soft_scrolling && ScreenMovPos)
652 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
654 if (SHIELD_ON(player))
656 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
657 IMG_SHIELD_NORMAL_ACTIVE);
658 int frame = getGraphicAnimationFrame(graphic, -1);
660 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
663 /* ----------------------------------------------------------------------- */
664 /* draw things the player is pushing, if needed */
665 /* ----------------------------------------------------------------------- */
667 if (player->Pushing && player_is_moving)
669 int px = SCREENX(next_jx), py = SCREENY(next_jy);
672 (element == EL_SOKOBAN_FIELD_EMPTY ||
673 Feld[next_jx][next_jy] == EL_SOKOBAN_FIELD_FULL))
674 DrawGraphicShiftedThruMask(px, py, sxx, syy, IMG_SOKOBAN_OBJECT, 0,
678 int element = Feld[next_jx][next_jy];
679 int graphic = el2img(element);
682 if ((sxx || syy) && IS_PUSHABLE(element))
684 graphic = el_act_dir2img(element, ACTION_MOVING, player->MovDir);
685 frame = getGraphicAnimationFrame(graphic, player->Frame);
688 DrawGraphicShifted(px, py, sxx, syy, graphic, frame,
689 NO_CUTTING, NO_MASKING);
693 /* ----------------------------------------------------------------------- */
694 /* draw things in front of player (active dynamite or dynabombs) */
695 /* ----------------------------------------------------------------------- */
697 if (IS_ACTIVE_BOMB(element))
699 graphic = el2img(element);
700 frame = getGraphicAnimationFrame(graphic, GfxFrame[jx][jy]);
702 if (game.emulation == EMU_SUPAPLEX)
703 DrawGraphic(sx, sy, IMG_SP_DISK_RED, frame);
705 DrawGraphicThruMask(sx, sy, graphic, frame);
708 if (player_is_moving && last_element == EL_EXPLOSION)
710 int stored = Store[last_jx][last_jy];
711 int graphic = (game.emulation != EMU_SUPAPLEX ? IMG_EXPLOSION :
712 stored == EL_SP_INFOTRON ? IMG_SP_EXPLOSION_INFOTRON :
714 int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
715 int phase = ExplodePhase[last_jx][last_jy] - 1;
716 int frame = getGraphicAnimationFrame(graphic, phase - delay);
719 DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy), graphic, frame);
722 /* ----------------------------------------------------------------------- */
723 /* draw elements that stay over the player */
724 /* ----------------------------------------------------------------------- */
726 /* handle the field the player is leaving ... */
727 if (player_is_moving && IS_OVER_PLAYER(last_element))
728 DrawLevelField(last_jx, last_jy);
730 /* ... and the field the player is entering */
731 if (IS_OVER_PLAYER(element))
732 DrawLevelField(jx, jy);
734 if (setup.direct_draw)
736 int dest_x = SX + SCREENX(MIN(jx, last_jx)) * TILEX;
737 int dest_y = SY + SCREENY(MIN(jy, last_jy)) * TILEY;
738 int x_size = TILEX * (1 + ABS(jx - last_jx));
739 int y_size = TILEY * (1 + ABS(jy - last_jy));
741 BlitBitmap(drawto_field, window,
742 dest_x, dest_y, x_size, y_size, dest_x, dest_y);
743 SetDrawtoField(DRAW_DIRECT);
746 MarkTileDirty(sx,sy);
749 void getGraphicSource(int graphic, int frame, Bitmap **bitmap, int *x, int *y)
751 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
752 int offset_x = graphic_info[graphic].offset_x;
753 int offset_y = graphic_info[graphic].offset_y;
754 int src_x = graphic_info[graphic].src_x + frame * offset_x;
755 int src_y = graphic_info[graphic].src_y + frame * offset_y;
757 *bitmap = src_bitmap;
762 void DrawGraphic(int x, int y, int graphic, int frame)
765 if (!IN_SCR_FIELD(x, y))
767 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
768 printf("DrawGraphic(): This should never happen!\n");
773 DrawGraphicExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic, frame);
778 void DrawOldGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic)
783 getOldGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
784 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
788 void DrawGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
795 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
797 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
798 int src_x = graphic_info[graphic].src_x;
799 int src_y = graphic_info[graphic].src_y;
800 int offset_x = graphic_info[graphic].offset_x;
801 int offset_y = graphic_info[graphic].offset_y;
803 src_x += frame * offset_x;
804 src_y += frame * offset_y;
807 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
810 void DrawGraphicThruMask(int x, int y, int graphic, int frame)
813 if (!IN_SCR_FIELD(x, y))
815 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
816 printf("DrawGraphicThruMask(): This should never happen!\n");
821 DrawGraphicThruMaskExt(drawto_field, FX + x * TILEX, FY + y *TILEY, graphic,
826 void DrawGraphicThruMaskExt(DrawBuffer *d, int dest_x, int dest_y, int graphic,
834 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
835 drawing_gc = src_bitmap->stored_clip_gc;
837 GC drawing_gc = src_bitmap->stored_clip_gc;
838 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
839 int src_x = graphic_info[graphic].src_x;
840 int src_y = graphic_info[graphic].src_y;
841 int offset_x = graphic_info[graphic].offset_x;
842 int offset_y = graphic_info[graphic].offset_y;
844 src_x += frame * offset_x;
845 src_y += frame * offset_y;
849 SetClipOrigin(src_bitmap, drawing_gc, dest_x - src_x, dest_y - src_y);
850 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX, TILEY, dest_x, dest_y);
853 void DrawMiniGraphic(int x, int y, int graphic)
855 DrawMiniGraphicExt(drawto, SX + x * MINI_TILEX,SY + y * MINI_TILEY, graphic);
856 MarkTileDirty(x / 2, y / 2);
859 void getMiniGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
861 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
863 int mini_starty = src_bitmap->height * 2 / 3;
864 int src_x = mini_startx + graphic_info[graphic].src_x / 2;
865 int src_y = mini_starty + graphic_info[graphic].src_y / 2;
868 /* !!! not needed anymore, because of automatically created mini graphics */
869 if (src_x + MINI_TILEX > src_bitmap->width ||
870 src_y + MINI_TILEY > src_bitmap->height)
872 /* graphic of desired size seems not to be contained in this image;
873 dirty workaround: get it from the middle of the normal sized image */
875 printf("::: using dirty workaround for %d (%d, %d)\n",
876 graphic, src_bitmap->width, src_bitmap->height);
878 getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
879 src_x += (TILEX / 2 - MINI_TILEX / 2);
880 src_y += (TILEY / 2 - MINI_TILEY / 2);
884 *bitmap = src_bitmap;
889 void DrawMiniGraphicExt(DrawBuffer *d, int x, int y, int graphic)
894 getMiniGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
895 BlitBitmap(src_bitmap, d, src_x, src_y, MINI_TILEX, MINI_TILEY, x, y);
898 void DrawGraphicShifted(int x,int y, int dx,int dy, int graphic, int frame,
899 int cut_mode, int mask_mode)
908 int width = TILEX, height = TILEY;
914 DrawGraphic(x, y, graphic, frame);
918 if (dx || dy) /* shifted graphic */
920 if (x < BX1) /* object enters playfield from the left */
927 else if (x > BX2) /* object enters playfield from the right */
933 else if (x==BX1 && dx < 0) /* object leaves playfield to the left */
939 else if (x==BX2 && dx > 0) /* object leaves playfield to the right */
941 else if (dx) /* general horizontal movement */
942 MarkTileDirty(x + SIGN(dx), y);
944 if (y < BY1) /* object enters playfield from the top */
946 if (cut_mode==CUT_BELOW) /* object completely above top border */
954 else if (y > BY2) /* object enters playfield from the bottom */
960 else if (y==BY1 && dy < 0) /* object leaves playfield to the top */
966 else if (dy > 0 && cut_mode == CUT_ABOVE)
968 if (y == BY2) /* object completely above bottom border */
974 MarkTileDirty(x, y + 1);
975 } /* object leaves playfield to the bottom */
976 else if (dy > 0 && (y == BY2 || cut_mode == CUT_BELOW))
978 else if (dy) /* general vertical movement */
979 MarkTileDirty(x, y + SIGN(dy));
982 src_bitmap = graphic_info[graphic].bitmap;
983 src_x = graphic_info[graphic].src_x;
984 src_y = graphic_info[graphic].src_y;
985 offset_x = graphic_info[graphic].offset_x;
986 offset_y = graphic_info[graphic].offset_y;
988 drawing_gc = src_bitmap->stored_clip_gc;
990 src_x += frame * offset_x;
991 src_y += frame * offset_y;
996 dest_x = FX + x * TILEX + dx;
997 dest_y = FY + y * TILEY + dy;
1000 if (!IN_SCR_FIELD(x,y))
1002 printf("DrawGraphicShifted(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
1003 printf("DrawGraphicShifted(): This should never happen!\n");
1008 if (mask_mode == USE_MASKING)
1010 SetClipOrigin(src_bitmap, drawing_gc, dest_x - src_x, dest_y - src_y);
1011 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1015 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1021 void DrawGraphicShiftedThruMask(int x, int y, int dx, int dy, int graphic,
1022 int frame, int cut_mode)
1024 DrawGraphicShifted(x,y, dx,dy, graphic, frame, cut_mode, USE_MASKING);
1027 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
1028 int cut_mode, int mask_mode)
1030 int lx = LEVELX(x), ly = LEVELY(y);
1034 if (IN_LEV_FIELD(lx, ly))
1036 SetRandomAnimationValue(lx, ly);
1038 graphic = el_act_dir2img(element, GfxAction[lx][ly], MovDir[lx][ly]);
1039 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1041 else /* border element */
1043 graphic = el2img(element);
1044 frame = getGraphicAnimationFrame(graphic, -1);
1047 if (element == EL_WALL_GROWING)
1049 boolean left_stopped = FALSE, right_stopped = FALSE;
1051 if (!IN_LEV_FIELD(lx - 1, ly) || IS_MAUER(Feld[lx - 1][ly]))
1052 left_stopped = TRUE;
1053 if (!IN_LEV_FIELD(lx + 1, ly) || IS_MAUER(Feld[lx + 1][ly]))
1054 right_stopped = TRUE;
1056 if (left_stopped && right_stopped)
1058 else if (left_stopped)
1060 graphic = IMG_WALL_GROWING_ACTIVE_RIGHT;
1061 frame = graphic_info[graphic].anim_frames - 1;
1063 else if (right_stopped)
1065 graphic = IMG_WALL_GROWING_ACTIVE_LEFT;
1066 frame = graphic_info[graphic].anim_frames - 1;
1070 else if (IS_AMOEBOID(element) || element == EL_AMOEBA_DRIPPING)
1072 graphic = (element == EL_BD_AMOEBA ? IMG_BD_AMOEBA_PART1 :
1073 element == EL_AMOEBA_WET ? IMG_AMOEBA_WET_PART1 :
1074 element == EL_AMOEBA_DRY ? IMG_AMOEBA_DRY_PART1 :
1075 element == EL_AMOEBA_FULL ? IMG_AMOEBA_FULL_PART1 :
1076 IMG_AMOEBA_DEAD_PART1);
1078 graphic += (x + 2 * y + 4) % 4;
1083 if (IS_AMOEBOID(element) || element == EL_AMOEBA_DRIPPING)
1085 if (Feld[lx][ly] == EL_AMOEBA_DRIPPING)
1086 printf("---> %d -> %d / %d [%d]\n",
1087 element, graphic, frame, GfxRandom[lx][ly]);
1092 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, mask_mode);
1093 else if (mask_mode == USE_MASKING)
1094 DrawGraphicThruMask(x, y, graphic, frame);
1096 DrawGraphic(x, y, graphic, frame);
1099 void DrawLevelElementExt(int x, int y, int dx, int dy, int element,
1100 int cut_mode, int mask_mode)
1102 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1103 DrawScreenElementExt(SCREENX(x), SCREENY(y), dx, dy, element,
1104 cut_mode, mask_mode);
1107 void DrawScreenElementShifted(int x, int y, int dx, int dy, int element,
1110 DrawScreenElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1113 void DrawLevelElementShifted(int x, int y, int dx, int dy, int element,
1116 DrawLevelElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1120 void DrawOldScreenElementThruMask(int x, int y, int element)
1122 DrawOldScreenElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1125 void DrawScreenElementThruMask(int x, int y, int element)
1127 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1131 void DrawLevelElementThruMask(int x, int y, int element)
1133 DrawLevelElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1136 void DrawLevelFieldThruMask(int x, int y)
1138 DrawLevelElementExt(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
1141 void DrawCrumbledSand(int x, int y)
1145 int i, width, height, cx,cy;
1146 int lx = LEVELX(x), ly = LEVELY(y);
1147 int element, graphic;
1149 static int xy[4][2] =
1157 if (!IN_LEV_FIELD(lx, ly))
1160 element = Feld[lx][ly];
1162 if (element == EL_SAND ||
1163 element == EL_LANDMINE ||
1164 element == EL_TRAP ||
1165 element == EL_TRAP_ACTIVE)
1167 if (!IN_SCR_FIELD(x, y))
1170 graphic = IMG_SAND_CRUMBLED;
1172 src_bitmap = graphic_info[graphic].bitmap;
1173 src_x = graphic_info[graphic].src_x;
1174 src_y = graphic_info[graphic].src_y;
1180 lxx = lx + xy[i][0];
1181 lyy = ly + xy[i][1];
1182 if (!IN_LEV_FIELD(lxx, lyy))
1183 element = EL_STEELWALL;
1185 element = Feld[lxx][lyy];
1187 if (element == EL_SAND ||
1188 element == EL_LANDMINE ||
1189 element == EL_TRAP ||
1190 element == EL_TRAP_ACTIVE)
1193 if (i == 1 || i == 2)
1197 cx = (i == 2 ? TILEX - snip : 0);
1205 cy = (i == 3 ? TILEY - snip : 0);
1208 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1209 width, height, FX + x * TILEX + cx, FY + y * TILEY + cy);
1212 MarkTileDirty(x, y);
1216 graphic = IMG_SAND_CRUMBLED;
1218 src_bitmap = graphic_info[graphic].bitmap;
1219 src_x = graphic_info[graphic].src_x;
1220 src_y = graphic_info[graphic].src_y;
1224 int xx, yy, lxx, lyy;
1228 lxx = lx + xy[i][0];
1229 lyy = ly + xy[i][1];
1231 if (!IN_LEV_FIELD(lxx, lyy) ||
1232 (Feld[lxx][lyy] != EL_SAND &&
1233 Feld[lxx][lyy] != EL_LANDMINE &&
1234 Feld[lxx][lyy] != EL_TRAP &&
1235 Feld[lxx][lyy] != EL_TRAP_ACTIVE) ||
1236 !IN_SCR_FIELD(xx, yy))
1239 if (i == 1 || i == 2)
1243 cx = (i == 1 ? TILEX - snip : 0);
1251 cy = (i==0 ? TILEY-snip : 0);
1254 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1255 width, height, FX + xx * TILEX + cx, FY + yy * TILEY + cy);
1257 MarkTileDirty(xx, yy);
1262 static int getBorderElement(int x, int y)
1266 { EL_STEELWALL_TOPLEFT, EL_INVISIBLE_STEELWALL_TOPLEFT },
1267 { EL_STEELWALL_TOPRIGHT, EL_INVISIBLE_STEELWALL_TOPRIGHT },
1268 { EL_STEELWALL_BOTTOMLEFT, EL_INVISIBLE_STEELWALL_BOTTOMLEFT },
1269 { EL_STEELWALL_BOTTOMRIGHT, EL_INVISIBLE_STEELWALL_BOTTOMRIGHT },
1270 { EL_STEELWALL_VERTICAL, EL_INVISIBLE_STEELWALL_VERTICAL },
1271 { EL_STEELWALL_HORIZONTAL, EL_INVISIBLE_STEELWALL_HORIZONTAL },
1272 { EL_STEELWALL, EL_INVISIBLE_STEELWALL }
1274 int steel_type = (BorderElement == EL_STEELWALL ? 0 : 1);
1275 int steel_position = (x == -1 && y == -1 ? 0 :
1276 x == lev_fieldx && y == -1 ? 1 :
1277 x == -1 && y == lev_fieldy ? 2 :
1278 x == lev_fieldx && y == lev_fieldy ? 3 :
1279 x == -1 || x == lev_fieldx ? 4 :
1280 y == -1 || y == lev_fieldy ? 5 : 6);
1282 return border[steel_position][steel_type];
1285 void DrawScreenElement(int x, int y, int element)
1287 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
1288 DrawCrumbledSand(x, y);
1291 void DrawLevelElement(int x, int y, int element)
1293 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1294 DrawScreenElement(SCREENX(x), SCREENY(y), element);
1297 void DrawScreenField(int x, int y)
1299 int lx = LEVELX(x), ly = LEVELY(y);
1300 int element, content;
1302 if (!IN_LEV_FIELD(lx, ly))
1304 if (lx < -1 || lx > lev_fieldx || ly < -1 || ly > lev_fieldy)
1307 element = getBorderElement(lx, ly);
1309 DrawScreenElement(x, y, element);
1313 element = Feld[lx][ly];
1314 content = Store[lx][ly];
1316 if (IS_MOVING(lx, ly))
1318 int horiz_move = (MovDir[lx][ly] == MV_LEFT || MovDir[lx][ly] == MV_RIGHT);
1319 boolean cut_mode = NO_CUTTING;
1321 if (element == EL_QUICKSAND_EMPTYING ||
1322 element == EL_MAGIC_WALL_EMPTYING ||
1323 element == EL_BD_MAGIC_WALL_EMPTYING ||
1324 element == EL_AMOEBA_DRIPPING)
1325 cut_mode = CUT_ABOVE;
1326 else if (element == EL_QUICKSAND_FILLING ||
1327 element == EL_MAGIC_WALL_FILLING ||
1328 element == EL_BD_MAGIC_WALL_FILLING)
1329 cut_mode = CUT_BELOW;
1331 if (cut_mode == CUT_ABOVE)
1332 DrawScreenElementShifted(x, y, 0, 0, element, NO_CUTTING);
1334 DrawScreenElement(x, y, EL_EMPTY);
1337 DrawScreenElementShifted(x, y, MovPos[lx][ly], 0, element, NO_CUTTING);
1338 else if (cut_mode == NO_CUTTING)
1339 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], element, cut_mode);
1341 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], content, cut_mode);
1343 if (content == EL_ACID)
1344 DrawLevelElementThruMask(lx, ly + 1, EL_ACID);
1346 else if (IS_BLOCKED(lx, ly))
1351 boolean cut_mode = NO_CUTTING;
1352 int element_old, content_old;
1354 Blocked2Moving(lx, ly, &oldx, &oldy);
1357 horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
1358 MovDir[oldx][oldy] == MV_RIGHT);
1360 element_old = Feld[oldx][oldy];
1361 content_old = Store[oldx][oldy];
1363 if (element_old == EL_QUICKSAND_EMPTYING ||
1364 element_old == EL_MAGIC_WALL_EMPTYING ||
1365 element_old == EL_BD_MAGIC_WALL_EMPTYING ||
1366 element_old == EL_AMOEBA_DRIPPING)
1367 cut_mode = CUT_ABOVE;
1369 DrawScreenElement(x, y, EL_EMPTY);
1372 DrawScreenElementShifted(sx, sy, MovPos[oldx][oldy], 0, element_old,
1374 else if (cut_mode == NO_CUTTING)
1375 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], element_old,
1378 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], content_old,
1381 else if (IS_DRAWABLE(element))
1382 DrawScreenElement(x, y, element);
1384 DrawScreenElement(x, y, EL_EMPTY);
1387 void DrawLevelField(int x, int y)
1389 if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1390 DrawScreenField(SCREENX(x), SCREENY(y));
1391 else if (IS_MOVING(x, y))
1395 Moving2Blocked(x, y, &newx, &newy);
1396 if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
1397 DrawScreenField(SCREENX(newx), SCREENY(newy));
1399 else if (IS_BLOCKED(x, y))
1403 Blocked2Moving(x, y, &oldx, &oldy);
1404 if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
1405 DrawScreenField(SCREENX(oldx), SCREENY(oldy));
1409 void DrawMiniElement(int x, int y, int element)
1413 graphic = el2edimg(element);
1414 DrawMiniGraphic(x, y, graphic);
1417 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
1419 int x = sx + scroll_x, y = sy + scroll_y;
1421 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
1422 DrawMiniElement(sx, sy, EL_EMPTY);
1423 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
1424 DrawMiniElement(sx, sy, Feld[x][y]);
1426 DrawMiniGraphic(sx, sy, el2edimg(getBorderElement(x, y)));
1429 void getMicroGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
1431 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
1432 int mini_startx = src_bitmap->width * 3 / 4;
1433 int mini_starty = src_bitmap->height * 2 / 3;
1434 int src_x = mini_startx + graphic_info[graphic].src_x / 8;
1435 int src_y = mini_starty + graphic_info[graphic].src_y / 8;
1437 if (src_x + MICRO_TILEX > src_bitmap->width ||
1438 src_y + MICRO_TILEY > src_bitmap->height)
1440 /* graphic of desired size seems not to be contained in this image;
1441 dirty workaround: get it from the middle of the normal sized image */
1443 getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
1444 src_x += (TILEX / 2 - MICRO_TILEX / 2);
1445 src_y += (TILEY / 2 - MICRO_TILEY / 2);
1448 *bitmap = src_bitmap;
1453 void DrawMicroElement(int xpos, int ypos, int element)
1457 int graphic = el2preimg(element);
1459 getMicroGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
1460 BlitBitmap(src_bitmap, drawto, src_x, src_y, MICRO_TILEX, MICRO_TILEY,
1468 SetDrawBackgroundMask(REDRAW_NONE);
1471 for(x=BX1; x<=BX2; x++)
1472 for(y=BY1; y<=BY2; y++)
1473 DrawScreenField(x, y);
1475 redraw_mask |= REDRAW_FIELD;
1478 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
1482 for(x=0; x<size_x; x++)
1483 for(y=0; y<size_y; y++)
1484 DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
1486 redraw_mask |= REDRAW_FIELD;
1489 static void DrawMicroLevelExt(int xpos, int ypos, int from_x, int from_y)
1493 DrawBackground(xpos, ypos, MICROLEV_XSIZE, MICROLEV_YSIZE);
1495 if (lev_fieldx < STD_LEV_FIELDX)
1496 xpos += (STD_LEV_FIELDX - lev_fieldx) / 2 * MICRO_TILEX;
1497 if (lev_fieldy < STD_LEV_FIELDY)
1498 ypos += (STD_LEV_FIELDY - lev_fieldy) / 2 * MICRO_TILEY;
1500 xpos += MICRO_TILEX;
1501 ypos += MICRO_TILEY;
1503 for(x=-1; x<=STD_LEV_FIELDX; x++)
1505 for(y=-1; y<=STD_LEV_FIELDY; y++)
1507 int lx = from_x + x, ly = from_y + y;
1509 if (lx >= 0 && lx < lev_fieldx && ly >= 0 && ly < lev_fieldy)
1510 DrawMicroElement(xpos + x * MICRO_TILEX, ypos + y * MICRO_TILEY,
1512 else if (lx >= -1 && lx < lev_fieldx+1 && ly >= -1 && ly < lev_fieldy+1
1513 && BorderElement != EL_EMPTY)
1514 DrawMicroElement(xpos + x * MICRO_TILEX, ypos + y * MICRO_TILEY,
1515 getBorderElement(lx, ly));
1519 redraw_mask |= REDRAW_MICROLEVEL;
1522 #define MICROLABEL_EMPTY 0
1523 #define MICROLABEL_LEVEL_NAME 1
1524 #define MICROLABEL_CREATED_BY 2
1525 #define MICROLABEL_LEVEL_AUTHOR 3
1526 #define MICROLABEL_IMPORTED_FROM 4
1527 #define MICROLABEL_LEVEL_IMPORT_INFO 5
1529 static void DrawMicroLevelLabelExt(int mode)
1531 char label_text[MAX_OUTPUT_LINESIZE + 1];
1532 int max_len_label_text = SXSIZE / getFontWidth(FONT_SPECIAL_GAME);
1534 DrawBackground(SX, MICROLABEL_YPOS, SXSIZE,getFontHeight(FONT_SPECIAL_GAME));
1536 strncpy(label_text, (mode == MICROLABEL_LEVEL_NAME ? level.name :
1537 mode == MICROLABEL_CREATED_BY ? "created by" :
1538 mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
1539 mode == MICROLABEL_IMPORTED_FROM ? "imported from" :
1540 mode == MICROLABEL_LEVEL_IMPORT_INFO ?
1541 leveldir_current->imported_from : ""),
1542 max_len_label_text);
1543 label_text[max_len_label_text] = '\0';
1545 if (strlen(label_text) > 0)
1547 int text_width = strlen(label_text) * getFontWidth(FONT_SPECIAL_GAME);
1548 int lxpos = SX + (SXSIZE - text_width) / 2;
1549 int lypos = MICROLABEL_YPOS;
1551 DrawText(lxpos, lypos, label_text, FONT_SPECIAL_GAME);
1554 redraw_mask |= REDRAW_MICROLEVEL;
1557 void DrawMicroLevel(int xpos, int ypos, boolean restart)
1559 static unsigned long scroll_delay = 0;
1560 static unsigned long label_delay = 0;
1561 static int from_x, from_y, scroll_direction;
1562 static int label_state, label_counter;
1566 from_x = from_y = 0;
1567 scroll_direction = MV_RIGHT;
1571 DrawMicroLevelExt(xpos, ypos, from_x, from_y);
1572 DrawMicroLevelLabelExt(label_state);
1574 /* initialize delay counters */
1575 DelayReached(&scroll_delay, 0);
1576 DelayReached(&label_delay, 0);
1581 /* scroll micro level, if needed */
1582 if ((lev_fieldx > STD_LEV_FIELDX || lev_fieldy > STD_LEV_FIELDY) &&
1583 DelayReached(&scroll_delay, MICROLEVEL_SCROLL_DELAY))
1585 switch (scroll_direction)
1591 scroll_direction = MV_UP;
1595 if (from_x < lev_fieldx - STD_LEV_FIELDX)
1598 scroll_direction = MV_DOWN;
1605 scroll_direction = MV_RIGHT;
1609 if (from_y < lev_fieldy - STD_LEV_FIELDY)
1612 scroll_direction = MV_LEFT;
1619 DrawMicroLevelExt(xpos, ypos, from_x, from_y);
1622 /* redraw micro level label, if needed */
1623 if (strcmp(level.name, NAMELESS_LEVEL_NAME) != 0 &&
1624 strcmp(level.author, ANONYMOUS_NAME) != 0 &&
1625 strcmp(level.author, leveldir_current->name) != 0 &&
1626 DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
1628 int max_label_counter = 23;
1630 if (leveldir_current->imported_from != NULL)
1631 max_label_counter += 14;
1633 label_counter = (label_counter + 1) % max_label_counter;
1634 label_state = (label_counter >= 0 && label_counter <= 7 ?
1635 MICROLABEL_LEVEL_NAME :
1636 label_counter >= 9 && label_counter <= 12 ?
1637 MICROLABEL_CREATED_BY :
1638 label_counter >= 14 && label_counter <= 21 ?
1639 MICROLABEL_LEVEL_AUTHOR :
1640 label_counter >= 23 && label_counter <= 26 ?
1641 MICROLABEL_IMPORTED_FROM :
1642 label_counter >= 28 && label_counter <= 35 ?
1643 MICROLABEL_LEVEL_IMPORT_INFO : MICROLABEL_EMPTY);
1644 DrawMicroLevelLabelExt(label_state);
1648 int REQ_in_range(int x, int y)
1650 if (y > DY+249 && y < DY+278)
1652 if (x > DX+1 && x < DX+48)
1654 else if (x > DX+51 && x < DX+98)
1660 #define MAX_REQUEST_LINES 13
1661 #define MAX_REQUEST_LINE_LEN 7
1663 boolean Request(char *text, unsigned int req_state)
1665 int mx, my, ty, result = -1;
1666 unsigned int old_door_state;
1668 #if defined(PLATFORM_UNIX)
1669 /* pause network game while waiting for request to answer */
1670 if (options.network &&
1671 game_status == PLAYING &&
1672 req_state & REQUEST_WAIT_FOR)
1673 SendToServer_PausePlaying();
1676 old_door_state = GetDoorState();
1680 CloseDoor(DOOR_CLOSE_1);
1682 /* save old door content */
1683 BlitBitmap(bitmap_db_door, bitmap_db_door,
1684 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
1685 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
1687 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
1689 /* clear door drawing field */
1690 DrawBackground(DX, DY, DXSIZE, DYSIZE);
1692 /* write text for request */
1693 for(ty=0; ty < MAX_REQUEST_LINES; ty++)
1695 char text_line[MAX_REQUEST_LINE_LEN + 1];
1701 for(tl=0,tx=0; tx < MAX_REQUEST_LINE_LEN; tl++,tx++)
1704 if (!tc || tc == ' ')
1715 strncpy(text_line, text, tl);
1718 DrawText(DX + 50 - (tl * 14)/2, DY + 8 + ty * 16,
1719 text_line, FONT_DEFAULT_SMALL);
1721 text += tl + (tc == ' ' ? 1 : 0);
1724 if (req_state & REQ_ASK)
1726 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
1727 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
1729 else if (req_state & REQ_CONFIRM)
1731 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
1733 else if (req_state & REQ_PLAYER)
1735 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
1736 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
1737 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
1738 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
1741 /* copy request gadgets to door backbuffer */
1742 BlitBitmap(drawto, bitmap_db_door,
1743 DX, DY, DXSIZE, DYSIZE,
1744 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
1746 OpenDoor(DOOR_OPEN_1);
1752 if (!(req_state & REQUEST_WAIT_FOR))
1754 SetDrawBackgroundMask(REDRAW_FIELD);
1759 if (game_status != MAINMENU)
1762 button_status = MB_RELEASED;
1764 request_gadget_id = -1;
1766 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
1778 case EVENT_BUTTONPRESS:
1779 case EVENT_BUTTONRELEASE:
1780 case EVENT_MOTIONNOTIFY:
1782 if (event.type == EVENT_MOTIONNOTIFY)
1784 if (!PointerInWindow(window))
1785 continue; /* window and pointer are on different screens */
1790 motion_status = TRUE;
1791 mx = ((MotionEvent *) &event)->x;
1792 my = ((MotionEvent *) &event)->y;
1796 motion_status = FALSE;
1797 mx = ((ButtonEvent *) &event)->x;
1798 my = ((ButtonEvent *) &event)->y;
1799 if (event.type == EVENT_BUTTONPRESS)
1800 button_status = ((ButtonEvent *) &event)->button;
1802 button_status = MB_RELEASED;
1805 /* this sets 'request_gadget_id' */
1806 HandleGadgets(mx, my, button_status);
1808 switch(request_gadget_id)
1810 case TOOL_CTRL_ID_YES:
1813 case TOOL_CTRL_ID_NO:
1816 case TOOL_CTRL_ID_CONFIRM:
1817 result = TRUE | FALSE;
1820 case TOOL_CTRL_ID_PLAYER_1:
1823 case TOOL_CTRL_ID_PLAYER_2:
1826 case TOOL_CTRL_ID_PLAYER_3:
1829 case TOOL_CTRL_ID_PLAYER_4:
1840 case EVENT_KEYPRESS:
1841 switch(GetEventKey((KeyEvent *)&event, TRUE))
1854 if (req_state & REQ_PLAYER)
1858 case EVENT_KEYRELEASE:
1859 ClearPlayerAction();
1863 HandleOtherEvents(&event);
1867 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
1869 int joy = AnyJoystick();
1871 if (joy & JOY_BUTTON_1)
1873 else if (joy & JOY_BUTTON_2)
1879 /* don't eat all CPU time */
1883 if (game_status != MAINMENU)
1888 if (!(req_state & REQ_STAY_OPEN))
1890 CloseDoor(DOOR_CLOSE_1);
1892 if (!(req_state & REQ_STAY_CLOSED) && (old_door_state & DOOR_OPEN_1))
1894 BlitBitmap(bitmap_db_door, bitmap_db_door,
1895 DOOR_GFX_PAGEX2,DOOR_GFX_PAGEY1, DXSIZE,DYSIZE,
1896 DOOR_GFX_PAGEX1,DOOR_GFX_PAGEY1);
1897 OpenDoor(DOOR_OPEN_1);
1903 SetDrawBackgroundMask(REDRAW_FIELD);
1905 #if defined(PLATFORM_UNIX)
1906 /* continue network game after request */
1907 if (options.network &&
1908 game_status == PLAYING &&
1909 req_state & REQUEST_WAIT_FOR)
1910 SendToServer_ContinuePlaying();
1916 unsigned int OpenDoor(unsigned int door_state)
1918 unsigned int new_door_state;
1920 if (door_state & DOOR_COPY_BACK)
1922 BlitBitmap(bitmap_db_door, bitmap_db_door,
1923 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE + VYSIZE,
1924 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
1925 door_state &= ~DOOR_COPY_BACK;
1928 new_door_state = MoveDoor(door_state);
1930 return(new_door_state);
1933 unsigned int CloseDoor(unsigned int door_state)
1935 unsigned int new_door_state;
1937 BlitBitmap(backbuffer, bitmap_db_door,
1938 DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
1939 BlitBitmap(backbuffer, bitmap_db_door,
1940 VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
1942 new_door_state = MoveDoor(door_state);
1944 return(new_door_state);
1947 unsigned int GetDoorState()
1949 return MoveDoor(DOOR_GET_STATE);
1952 unsigned int SetDoorState(unsigned int door_state)
1954 return MoveDoor(door_state | DOOR_SET_STATE);
1957 unsigned int MoveDoor(unsigned int door_state)
1959 static int door1 = DOOR_OPEN_1;
1960 static int door2 = DOOR_CLOSE_2;
1961 static unsigned long door_delay = 0;
1962 int x, start, stepsize = 2;
1963 unsigned long door_delay_value = stepsize * 5;
1965 if (door_state == DOOR_GET_STATE)
1966 return(door1 | door2);
1968 if (door_state & DOOR_SET_STATE)
1970 if (door_state & DOOR_ACTION_1)
1971 door1 = door_state & DOOR_ACTION_1;
1972 if (door_state & DOOR_ACTION_2)
1973 door2 = door_state & DOOR_ACTION_2;
1975 return(door1 | door2);
1978 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
1979 door_state &= ~DOOR_OPEN_1;
1980 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
1981 door_state &= ~DOOR_CLOSE_1;
1982 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
1983 door_state &= ~DOOR_OPEN_2;
1984 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
1985 door_state &= ~DOOR_CLOSE_2;
1987 if (setup.quick_doors)
1990 door_delay_value = 0;
1992 StopSound(SND_MENU_DOOR_OPENING);
1993 StopSound(SND_MENU_DOOR_CLOSING);
1996 if (global.autoplay_leveldir)
1998 door_state |= DOOR_NO_DELAY;
1999 door_state &= ~DOOR_CLOSE_ALL;
2002 if (door_state & DOOR_ACTION)
2004 if (!(door_state & DOOR_NO_DELAY))
2006 /* opening door sound has priority over simultaneously closing door */
2007 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
2008 PlaySoundStereo(SND_MENU_DOOR_OPENING, SOUND_MAX_RIGHT);
2009 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
2010 PlaySoundStereo(SND_MENU_DOOR_CLOSING, SOUND_MAX_RIGHT);
2013 start = ((door_state & DOOR_NO_DELAY) ? DXSIZE : 0);
2015 for(x=start; x<=DXSIZE; x+=stepsize)
2017 Bitmap *bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
2018 GC gc = bitmap->stored_clip_gc;
2020 if (!(door_state & DOOR_NO_DELAY))
2021 WaitUntilDelayReached(&door_delay, door_delay_value);
2023 if (door_state & DOOR_ACTION_1)
2025 int i = (door_state & DOOR_OPEN_1 ? DXSIZE-x : x);
2026 int j = (DXSIZE - i) / 3;
2028 BlitBitmap(bitmap_db_door, drawto,
2029 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + i/2,
2030 DXSIZE,DYSIZE - i/2, DX, DY);
2032 ClearRectangle(drawto, DX, DY + DYSIZE - i/2, DXSIZE,i/2);
2034 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2035 BlitBitmapMasked(bitmap, drawto,
2036 DXSIZE, DOOR_GFX_PAGEY1, i, 77,
2037 DX + DXSIZE - i, DY + j);
2038 BlitBitmapMasked(bitmap, drawto,
2039 DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63,
2040 DX + DXSIZE - i, DY + 140 + j);
2041 SetClipOrigin(bitmap, gc, DX - DXSIZE + i, DY - (DOOR_GFX_PAGEY1 + j));
2042 BlitBitmapMasked(bitmap, drawto,
2043 DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j,
2045 BlitBitmapMasked(bitmap, drawto,
2046 DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63,
2049 BlitBitmapMasked(bitmap, drawto,
2050 DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
2052 BlitBitmapMasked(bitmap, drawto,
2053 DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
2055 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2056 BlitBitmapMasked(bitmap, drawto,
2057 DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
2058 DX + DXSIZE - i, DY + 77 + j);
2059 BlitBitmapMasked(bitmap, drawto,
2060 DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
2061 DX + DXSIZE - i, DY + 203 + j);
2063 redraw_mask |= REDRAW_DOOR_1;
2066 if (door_state & DOOR_ACTION_2)
2068 int i = (door_state & DOOR_OPEN_2 ? VXSIZE - x : x);
2069 int j = (VXSIZE - i) / 3;
2071 BlitBitmap(bitmap_db_door, drawto,
2072 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + i/2,
2073 VXSIZE, VYSIZE - i/2, VX, VY);
2075 ClearRectangle(drawto, VX, VY + VYSIZE-i/2, VXSIZE, i/2);
2077 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2078 BlitBitmapMasked(bitmap, drawto,
2079 VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2,
2080 VX + VXSIZE-i, VY+j);
2081 SetClipOrigin(bitmap, gc,
2082 VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
2083 BlitBitmapMasked(bitmap, drawto,
2084 VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j,
2087 BlitBitmapMasked(bitmap, drawto,
2088 VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2,
2089 i, VYSIZE / 2, VX, VY + VYSIZE / 2 - j);
2090 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2091 BlitBitmapMasked(bitmap, drawto,
2092 VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2,
2094 VX + VXSIZE - i, VY + VYSIZE / 2 + j);
2096 redraw_mask |= REDRAW_DOOR_2;
2101 if (game_status == MAINMENU)
2106 if (setup.quick_doors)
2108 StopSound(SND_MENU_DOOR_OPENING);
2109 StopSound(SND_MENU_DOOR_CLOSING);
2112 if (door_state & DOOR_ACTION_1)
2113 door1 = door_state & DOOR_ACTION_1;
2114 if (door_state & DOOR_ACTION_2)
2115 door2 = door_state & DOOR_ACTION_2;
2117 return (door1 | door2);
2120 void DrawSpecialEditorDoor()
2122 /* draw bigger toolbox window */
2123 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
2124 DOOR_GFX_PAGEX7, 0, EXSIZE + 8, 8,
2126 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
2127 EX - 4, VY - 4, EXSIZE + 8, EYSIZE - VYSIZE + 4,
2130 redraw_mask |= REDRAW_ALL;
2133 void UndrawSpecialEditorDoor()
2135 /* draw normal tape recorder window */
2136 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
2137 EX - 4, EY - 12, EXSIZE + 8, EYSIZE - VYSIZE + 12,
2140 redraw_mask |= REDRAW_ALL;
2144 int ReadPixel(DrawBuffer *bitmap, int x, int y)
2146 XImage *pixel_image;
2147 unsigned long pixel_value;
2149 pixel_image = XGetImage(display, bitmap->drawable,
2150 x, y, 1, 1, AllPlanes, ZPixmap);
2151 pixel_value = XGetPixel(pixel_image, 0, 0);
2153 XDestroyImage(pixel_image);
2159 /* ---------- new tool button stuff ---------------------------------------- */
2161 /* graphic position values for tool buttons */
2162 #define TOOL_BUTTON_YES_XPOS 2
2163 #define TOOL_BUTTON_YES_YPOS 250
2164 #define TOOL_BUTTON_YES_GFX_YPOS 0
2165 #define TOOL_BUTTON_YES_XSIZE 46
2166 #define TOOL_BUTTON_YES_YSIZE 28
2167 #define TOOL_BUTTON_NO_XPOS 52
2168 #define TOOL_BUTTON_NO_YPOS TOOL_BUTTON_YES_YPOS
2169 #define TOOL_BUTTON_NO_GFX_YPOS TOOL_BUTTON_YES_GFX_YPOS
2170 #define TOOL_BUTTON_NO_XSIZE TOOL_BUTTON_YES_XSIZE
2171 #define TOOL_BUTTON_NO_YSIZE TOOL_BUTTON_YES_YSIZE
2172 #define TOOL_BUTTON_CONFIRM_XPOS TOOL_BUTTON_YES_XPOS
2173 #define TOOL_BUTTON_CONFIRM_YPOS TOOL_BUTTON_YES_YPOS
2174 #define TOOL_BUTTON_CONFIRM_GFX_YPOS 30
2175 #define TOOL_BUTTON_CONFIRM_XSIZE 96
2176 #define TOOL_BUTTON_CONFIRM_YSIZE TOOL_BUTTON_YES_YSIZE
2177 #define TOOL_BUTTON_PLAYER_XSIZE 30
2178 #define TOOL_BUTTON_PLAYER_YSIZE 30
2179 #define TOOL_BUTTON_PLAYER_GFX_XPOS 5
2180 #define TOOL_BUTTON_PLAYER_GFX_YPOS 185
2181 #define TOOL_BUTTON_PLAYER_XPOS (5 + TOOL_BUTTON_PLAYER_XSIZE / 2)
2182 #define TOOL_BUTTON_PLAYER_YPOS (215 - TOOL_BUTTON_PLAYER_YSIZE / 2)
2183 #define TOOL_BUTTON_PLAYER1_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2184 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2185 #define TOOL_BUTTON_PLAYER2_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2186 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2187 #define TOOL_BUTTON_PLAYER3_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2188 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2189 #define TOOL_BUTTON_PLAYER4_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2190 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2191 #define TOOL_BUTTON_PLAYER1_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2192 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2193 #define TOOL_BUTTON_PLAYER2_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2194 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2195 #define TOOL_BUTTON_PLAYER3_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2196 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2197 #define TOOL_BUTTON_PLAYER4_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2198 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2207 } toolbutton_info[NUM_TOOL_BUTTONS] =
2210 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_GFX_YPOS,
2211 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_YPOS,
2212 TOOL_BUTTON_YES_XSIZE, TOOL_BUTTON_YES_YSIZE,
2217 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_GFX_YPOS,
2218 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_YPOS,
2219 TOOL_BUTTON_NO_XSIZE, TOOL_BUTTON_NO_YSIZE,
2224 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_GFX_YPOS,
2225 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_YPOS,
2226 TOOL_BUTTON_CONFIRM_XSIZE, TOOL_BUTTON_CONFIRM_YSIZE,
2227 TOOL_CTRL_ID_CONFIRM,
2231 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2232 TOOL_BUTTON_PLAYER1_XPOS, TOOL_BUTTON_PLAYER1_YPOS,
2233 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2234 TOOL_CTRL_ID_PLAYER_1,
2238 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2239 TOOL_BUTTON_PLAYER2_XPOS, TOOL_BUTTON_PLAYER2_YPOS,
2240 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2241 TOOL_CTRL_ID_PLAYER_2,
2245 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2246 TOOL_BUTTON_PLAYER3_XPOS, TOOL_BUTTON_PLAYER3_YPOS,
2247 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2248 TOOL_CTRL_ID_PLAYER_3,
2252 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2253 TOOL_BUTTON_PLAYER4_XPOS, TOOL_BUTTON_PLAYER4_YPOS,
2254 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2255 TOOL_CTRL_ID_PLAYER_4,
2260 void CreateToolButtons()
2264 for (i=0; i<NUM_TOOL_BUTTONS; i++)
2266 Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
2267 Bitmap *deco_bitmap = None;
2268 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
2269 struct GadgetInfo *gi;
2270 unsigned long event_mask;
2271 int gd_xoffset, gd_yoffset;
2272 int gd_x1, gd_x2, gd_y;
2275 event_mask = GD_EVENT_RELEASED;
2277 gd_xoffset = toolbutton_info[i].xpos;
2278 gd_yoffset = toolbutton_info[i].ypos;
2279 gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
2280 gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
2281 gd_y = DOOR_GFX_PAGEY1 + gd_yoffset;
2283 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
2285 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
2287 getMiniGraphicSource(PLAYER_NR_GFX(IMG_PLAYER1, player_nr),
2288 &deco_bitmap, &deco_x, &deco_y);
2289 deco_xpos = (toolbutton_info[i].width - MINI_TILEX) / 2;
2290 deco_ypos = (toolbutton_info[i].height - MINI_TILEY) / 2;
2293 gi = CreateGadget(GDI_CUSTOM_ID, id,
2294 GDI_INFO_TEXT, toolbutton_info[i].infotext,
2295 GDI_X, DX + toolbutton_info[i].x,
2296 GDI_Y, DY + toolbutton_info[i].y,
2297 GDI_WIDTH, toolbutton_info[i].width,
2298 GDI_HEIGHT, toolbutton_info[i].height,
2299 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
2300 GDI_STATE, GD_BUTTON_UNPRESSED,
2301 GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
2302 GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
2303 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
2304 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
2305 GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
2306 GDI_DECORATION_SHIFTING, 1, 1,
2307 GDI_EVENT_MASK, event_mask,
2308 GDI_CALLBACK_ACTION, HandleToolButtons,
2312 Error(ERR_EXIT, "cannot create gadget");
2314 tool_gadget[id] = gi;
2318 void FreeToolButtons()
2322 for (i=0; i<NUM_TOOL_BUTTONS; i++)
2323 FreeGadget(tool_gadget[i]);
2326 static void UnmapToolButtons()
2330 for (i=0; i<NUM_TOOL_BUTTONS; i++)
2331 UnmapGadget(tool_gadget[i]);
2334 static void HandleToolButtons(struct GadgetInfo *gi)
2336 request_gadget_id = gi->custom_id;
2339 int get_next_element(int element)
2343 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
2344 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
2345 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
2346 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
2347 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
2348 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
2349 case EL_AMOEBA_DRIPPING: return EL_AMOEBA_WET;
2351 default: return element;
2355 int el_act_dir2img(int element, int action, int direction)
2357 direction = MV_DIR_BIT(direction);
2359 return element_info[element].direction_graphic[action][direction];
2362 int el_act2img(int element, int action)
2364 return element_info[element].graphic[action];
2367 int el_dir2img(int element, int direction)
2369 return el_act_dir2img(element, ACTION_DEFAULT, direction);
2372 int el2img(int element)
2374 return element_info[element].graphic[ACTION_DEFAULT];
2377 int el2edimg(int element)
2379 return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
2382 int el2preimg(int element)
2384 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];