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)))
605 if (Feld[next_jx][next_jy] == EL_SOKOBAN_FIELD_FULL)
606 DrawLevelElement(next_jx, next_jy, EL_SOKOBAN_FIELD_EMPTY);
608 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
611 DrawLevelField(next_jx, next_jy);
615 if (!IN_SCR_FIELD(sx, sy))
618 if (setup.direct_draw)
619 SetDrawtoField(DRAW_BUFFERED);
621 /* ----------------------------------------------------------------------- */
622 /* draw things behind the player, if needed */
623 /* ----------------------------------------------------------------------- */
626 DrawLevelElement(jx, jy, Back[jx][jy]);
627 else if (IS_ACTIVE_BOMB(element))
628 DrawLevelElement(jx, jy, EL_EMPTY);
631 if (player_is_moving && GfxElement[jx][jy] != EL_UNDEFINED)
633 if (GfxElement[jx][jy] == EL_SAND)
634 DrawLevelFieldCrumbledSandDigging(jx, jy, move_dir, player->StepFrame);
637 int old_element = GfxElement[jx][jy];
638 int old_graphic = el_act_dir2img(old_element, action, move_dir);
639 int frame = getGraphicAnimationFrame(old_graphic, player->StepFrame);
641 DrawGraphic(sx, sy, old_graphic, frame);
646 GfxElement[jx][jy] = EL_UNDEFINED;
648 DrawLevelField(jx, jy);
652 /* ----------------------------------------------------------------------- */
653 /* draw player himself */
654 /* ----------------------------------------------------------------------- */
656 if (player->use_murphy_graphic)
658 static int last_horizontal_dir = MV_LEFT;
661 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
662 last_horizontal_dir = move_dir;
664 direction = (player->snapped ? move_dir : last_horizontal_dir);
666 graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, direction);
669 graphic = el_act_dir2img(player->element_nr, player->GfxAction, move_dir);
671 frame = getGraphicAnimationFrame(graphic, player->Frame);
675 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
676 sxx = player->GfxPos;
678 syy = player->GfxPos;
681 if (!setup.soft_scrolling && ScreenMovPos)
684 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
686 if (SHIELD_ON(player))
688 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
689 IMG_SHIELD_NORMAL_ACTIVE);
690 int frame = getGraphicAnimationFrame(graphic, -1);
692 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
695 /* ----------------------------------------------------------------------- */
696 /* draw things the player is pushing, if needed */
697 /* ----------------------------------------------------------------------- */
699 if (player->Pushing && player_is_moving)
701 int px = SCREENX(next_jx), py = SCREENY(next_jy);
704 (element == EL_SOKOBAN_FIELD_EMPTY ||
705 Feld[next_jx][next_jy] == EL_SOKOBAN_FIELD_FULL))
706 DrawGraphicShiftedThruMask(px, py, sxx, syy, IMG_SOKOBAN_OBJECT, 0,
710 int element = Feld[next_jx][next_jy];
711 int graphic = el2img(element);
714 if ((sxx || syy) && IS_PUSHABLE(element))
716 graphic = el_act_dir2img(element, ACTION_MOVING, move_dir);
717 frame = getGraphicAnimationFrame(graphic, player->Frame);
720 DrawGraphicShifted(px, py, sxx, syy, graphic, frame,
721 NO_CUTTING, NO_MASKING);
725 /* ----------------------------------------------------------------------- */
726 /* draw things in front of player (active dynamite or dynabombs) */
727 /* ----------------------------------------------------------------------- */
729 if (IS_ACTIVE_BOMB(element))
731 graphic = el2img(element);
732 frame = getGraphicAnimationFrame(graphic, GfxFrame[jx][jy]);
734 if (game.emulation == EMU_SUPAPLEX)
735 DrawGraphic(sx, sy, IMG_SP_DISK_RED, frame);
737 DrawGraphicThruMask(sx, sy, graphic, frame);
740 if (player_is_moving && last_element == EL_EXPLOSION)
742 int stored = Store[last_jx][last_jy];
743 int graphic = (game.emulation != EMU_SUPAPLEX ? IMG_EXPLOSION :
744 stored == EL_SP_INFOTRON ? IMG_SP_EXPLOSION_INFOTRON :
746 int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
747 int phase = ExplodePhase[last_jx][last_jy] - 1;
748 int frame = getGraphicAnimationFrame(graphic, phase - delay);
751 DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy), graphic, frame);
754 /* ----------------------------------------------------------------------- */
755 /* draw elements the player is just walking/passing through/under */
756 /* ----------------------------------------------------------------------- */
758 /* handle the field the player is leaving ... */
759 if (player_is_moving && IS_ACCESSIBLE_INSIDE(last_element))
760 DrawLevelField(last_jx, last_jy);
761 else if (player_is_moving && IS_ACCESSIBLE_UNDER(last_element))
762 DrawLevelFieldThruMask(last_jx, last_jy);
764 /* ... and the field the player is entering */
765 if (IS_ACCESSIBLE_INSIDE(element))
766 DrawLevelField(jx, jy);
767 else if (IS_ACCESSIBLE_UNDER(element))
768 DrawLevelFieldThruMask(jx, jy);
770 if (setup.direct_draw)
772 int dest_x = SX + SCREENX(MIN(jx, last_jx)) * TILEX;
773 int dest_y = SY + SCREENY(MIN(jy, last_jy)) * TILEY;
774 int x_size = TILEX * (1 + ABS(jx - last_jx));
775 int y_size = TILEY * (1 + ABS(jy - last_jy));
777 BlitBitmap(drawto_field, window,
778 dest_x, dest_y, x_size, y_size, dest_x, dest_y);
779 SetDrawtoField(DRAW_DIRECT);
782 MarkTileDirty(sx,sy);
785 void getGraphicSource(int graphic, int frame, Bitmap **bitmap, int *x, int *y)
787 struct GraphicInfo *g = &graphic_info[graphic];
791 if (g->offset_y == 0) /* frames are ordered horizontally */
793 int max_width = g->anim_frames_per_line * g->width;
795 *x = (g->src_x + frame * g->offset_x) % max_width;
796 *y = g->src_y + (g->src_x + frame * g->offset_x) / max_width * g->height;
798 else if (g->offset_x == 0) /* frames are ordered vertically */
800 int max_height = g->anim_frames_per_line * g->height;
802 *x = g->src_x + (g->src_y + frame * g->offset_y) / max_height * g->width;
803 *y = (g->src_y + frame * g->offset_y) % max_height;
805 else /* frames are ordered diagonally */
807 *x = g->src_x + frame * g->offset_x;
808 *y = g->src_y + frame * g->offset_y;
812 void DrawGraphic(int x, int y, int graphic, int frame)
815 if (!IN_SCR_FIELD(x, y))
817 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
818 printf("DrawGraphic(): This should never happen!\n");
823 DrawGraphicExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic, frame);
828 void DrawOldGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic)
833 getOldGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
834 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
838 void DrawGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
845 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
847 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
848 int src_x = graphic_info[graphic].src_x;
849 int src_y = graphic_info[graphic].src_y;
850 int offset_x = graphic_info[graphic].offset_x;
851 int offset_y = graphic_info[graphic].offset_y;
853 src_x += frame * offset_x;
854 src_y += frame * offset_y;
857 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
860 void DrawGraphicThruMask(int x, int y, int graphic, int frame)
863 if (!IN_SCR_FIELD(x, y))
865 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
866 printf("DrawGraphicThruMask(): This should never happen!\n");
871 DrawGraphicThruMaskExt(drawto_field, FX + x * TILEX, FY + y *TILEY, graphic,
876 void DrawGraphicThruMaskExt(DrawBuffer *d, int dest_x, int dest_y, int graphic,
884 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
885 drawing_gc = src_bitmap->stored_clip_gc;
887 GC drawing_gc = src_bitmap->stored_clip_gc;
888 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
889 int src_x = graphic_info[graphic].src_x;
890 int src_y = graphic_info[graphic].src_y;
891 int offset_x = graphic_info[graphic].offset_x;
892 int offset_y = graphic_info[graphic].offset_y;
894 src_x += frame * offset_x;
895 src_y += frame * offset_y;
899 SetClipOrigin(src_bitmap, drawing_gc, dest_x - src_x, dest_y - src_y);
900 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX, TILEY, dest_x, dest_y);
903 void DrawMiniGraphic(int x, int y, int graphic)
905 DrawMiniGraphicExt(drawto, SX + x * MINI_TILEX,SY + y * MINI_TILEY, graphic);
906 MarkTileDirty(x / 2, y / 2);
909 void getMiniGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
911 struct GraphicInfo *g = &graphic_info[graphic];
913 int mini_starty = g->bitmap->height * 2 / 3;
916 *x = mini_startx + g->src_x / 2;
917 *y = mini_starty + g->src_y / 2;
920 void DrawMiniGraphicExt(DrawBuffer *d, int x, int y, int graphic)
925 getMiniGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
926 BlitBitmap(src_bitmap, d, src_x, src_y, MINI_TILEX, MINI_TILEY, x, y);
929 void DrawGraphicShifted(int x,int y, int dx,int dy, int graphic, int frame,
930 int cut_mode, int mask_mode)
935 int width = TILEX, height = TILEY;
941 DrawGraphic(x, y, graphic, frame);
945 if (dx || dy) /* shifted graphic */
947 if (x < BX1) /* object enters playfield from the left */
954 else if (x > BX2) /* object enters playfield from the right */
960 else if (x==BX1 && dx < 0) /* object leaves playfield to the left */
966 else if (x==BX2 && dx > 0) /* object leaves playfield to the right */
968 else if (dx) /* general horizontal movement */
969 MarkTileDirty(x + SIGN(dx), y);
971 if (y < BY1) /* object enters playfield from the top */
973 if (cut_mode==CUT_BELOW) /* object completely above top border */
981 else if (y > BY2) /* object enters playfield from the bottom */
987 else if (y==BY1 && dy < 0) /* object leaves playfield to the top */
993 else if (dy > 0 && cut_mode == CUT_ABOVE)
995 if (y == BY2) /* object completely above bottom border */
1001 MarkTileDirty(x, y + 1);
1002 } /* object leaves playfield to the bottom */
1003 else if (dy > 0 && (y == BY2 || cut_mode == CUT_BELOW))
1005 else if (dy) /* general vertical movement */
1006 MarkTileDirty(x, y + SIGN(dy));
1010 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1012 src_bitmap = graphic_info[graphic].bitmap;
1013 src_x = graphic_info[graphic].src_x;
1014 src_y = graphic_info[graphic].src_y;
1015 offset_x = graphic_info[graphic].offset_x;
1016 offset_y = graphic_info[graphic].offset_y;
1018 src_x += frame * offset_x;
1019 src_y += frame * offset_y;
1022 drawing_gc = src_bitmap->stored_clip_gc;
1027 dest_x = FX + x * TILEX + dx;
1028 dest_y = FY + y * TILEY + dy;
1031 if (!IN_SCR_FIELD(x,y))
1033 printf("DrawGraphicShifted(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
1034 printf("DrawGraphicShifted(): This should never happen!\n");
1039 if (mask_mode == USE_MASKING)
1041 SetClipOrigin(src_bitmap, drawing_gc, dest_x - src_x, dest_y - src_y);
1042 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1046 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1052 void DrawGraphicShiftedThruMask(int x, int y, int dx, int dy, int graphic,
1053 int frame, int cut_mode)
1055 DrawGraphicShifted(x,y, dx,dy, graphic, frame, cut_mode, USE_MASKING);
1058 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
1059 int cut_mode, int mask_mode)
1061 int lx = LEVELX(x), ly = LEVELY(y);
1065 if (IN_LEV_FIELD(lx, ly))
1067 SetRandomAnimationValue(lx, ly);
1069 graphic = el_act_dir2img(element, GfxAction[lx][ly], MovDir[lx][ly]);
1070 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1072 else /* border element */
1074 graphic = el2img(element);
1075 frame = getGraphicAnimationFrame(graphic, -1);
1078 if (element == EL_EXPANDABLE_WALL)
1080 boolean left_stopped = FALSE, right_stopped = FALSE;
1082 if (!IN_LEV_FIELD(lx - 1, ly) || IS_WALL(Feld[lx - 1][ly]))
1083 left_stopped = TRUE;
1084 if (!IN_LEV_FIELD(lx + 1, ly) || IS_WALL(Feld[lx + 1][ly]))
1085 right_stopped = TRUE;
1087 if (left_stopped && right_stopped)
1089 else if (left_stopped)
1091 graphic = IMG_EXPANDABLE_WALL_GROWING_RIGHT;
1092 frame = graphic_info[graphic].anim_frames - 1;
1094 else if (right_stopped)
1096 graphic = IMG_EXPANDABLE_WALL_GROWING_LEFT;
1097 frame = graphic_info[graphic].anim_frames - 1;
1101 else if (IS_AMOEBOID(element) || element == EL_AMOEBA_DROPPING)
1103 graphic = (element == EL_BD_AMOEBA ? IMG_BD_AMOEBA_PART1 :
1104 element == EL_AMOEBA_WET ? IMG_AMOEBA_WET_PART1 :
1105 element == EL_AMOEBA_DRY ? IMG_AMOEBA_DRY_PART1 :
1106 element == EL_AMOEBA_FULL ? IMG_AMOEBA_FULL_PART1 :
1107 IMG_AMOEBA_DEAD_PART1);
1109 graphic += (x + 2 * y + 4) % 4;
1114 if (IS_AMOEBOID(element) || element == EL_AMOEBA_DROPPING)
1116 if (Feld[lx][ly] == EL_AMOEBA_DROPPING)
1117 printf("---> %d -> %d / %d [%d]\n",
1118 element, graphic, frame, GfxRandom[lx][ly]);
1123 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, mask_mode);
1124 else if (mask_mode == USE_MASKING)
1125 DrawGraphicThruMask(x, y, graphic, frame);
1127 DrawGraphic(x, y, graphic, frame);
1130 void DrawLevelElementExt(int x, int y, int dx, int dy, int element,
1131 int cut_mode, int mask_mode)
1133 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1134 DrawScreenElementExt(SCREENX(x), SCREENY(y), dx, dy, element,
1135 cut_mode, mask_mode);
1138 void DrawScreenElementShifted(int x, int y, int dx, int dy, int element,
1141 DrawScreenElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1144 void DrawLevelElementShifted(int x, int y, int dx, int dy, int element,
1147 DrawLevelElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1151 void DrawOldScreenElementThruMask(int x, int y, int element)
1153 DrawOldScreenElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1156 void DrawScreenElementThruMask(int x, int y, int element)
1158 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1162 void DrawLevelElementThruMask(int x, int y, int element)
1164 DrawLevelElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1167 void DrawLevelFieldThruMask(int x, int y)
1169 DrawLevelElementExt(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
1172 static void DrawLevelFieldCrumbledSandExt(int x, int y, int graphic, int frame)
1176 int sx = SCREENX(x), sy = SCREENY(y);
1178 int width, height, cx, cy, i;
1179 int snip = TILEX / 8; /* number of border pixels from "crumbled graphic" */
1180 static int xy[4][2] =
1188 if (!IN_LEV_FIELD(x, y))
1191 element = (GfxElement[x][y] != EL_UNDEFINED ? GfxElement[x][y] : Feld[x][y]);
1193 /* crumble field itself */
1194 if (CAN_BE_CRUMBLED(element) && !IS_MOVING(x, y))
1196 if (!IN_SCR_FIELD(sx, sy))
1199 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1203 int xx = x + xy[i][0];
1204 int yy = y + xy[i][1];
1206 element = (IN_LEV_FIELD(xx, yy) ? Feld[xx][yy] : EL_STEELWALL);
1208 /* check if neighbour field is of same type */
1209 if (CAN_BE_CRUMBLED(element) && !IS_MOVING(xx, yy))
1212 if (i == 1 || i == 2)
1216 cx = (i == 2 ? TILEX - snip : 0);
1224 cy = (i == 3 ? TILEY - snip : 0);
1227 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1228 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
1231 MarkTileDirty(sx, sy);
1233 else /* crumble neighbour fields */
1235 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1239 int xx = x + xy[i][0];
1240 int yy = y + xy[i][1];
1241 int sxx = sx + xy[i][0];
1242 int syy = sy + xy[i][1];
1244 if (!IN_LEV_FIELD(xx, yy) ||
1245 !IN_SCR_FIELD(sxx, syy) ||
1246 !CAN_BE_CRUMBLED(Feld[xx][yy]) ||
1250 if (i == 1 || i == 2)
1254 cx = (i == 1 ? TILEX - snip : 0);
1262 cy = (i==0 ? TILEY-snip : 0);
1265 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1266 width, height, FX + sxx * TILEX + cx, FY + syy * TILEY + cy);
1268 MarkTileDirty(sxx, syy);
1273 void DrawLevelFieldCrumbledSand(int x, int y)
1275 DrawLevelFieldCrumbledSandExt(x, y, IMG_SAND_CRUMBLED, 0);
1278 void DrawLevelFieldCrumbledSandDigging(int x, int y, int direction,
1281 int graphic1 = el_act_dir2img(EL_SAND, ACTION_DIGGING, direction);
1282 int graphic2 = el_act_dir2img(EL_SAND_CRUMBLED, ACTION_DIGGING, direction);
1283 int frame1 = getGraphicAnimationFrame(graphic1, step_frame);
1284 int frame2 = getGraphicAnimationFrame(graphic2, step_frame);
1285 int sx = SCREENX(x), sy = SCREENY(y);
1287 DrawGraphic(sx, sy, graphic1, frame1);
1288 DrawLevelFieldCrumbledSandExt(x, y, graphic2, frame2);
1291 static int getBorderElement(int x, int y)
1295 { EL_STEELWALL_TOPLEFT, EL_INVISIBLE_STEELWALL_TOPLEFT },
1296 { EL_STEELWALL_TOPRIGHT, EL_INVISIBLE_STEELWALL_TOPRIGHT },
1297 { EL_STEELWALL_BOTTOMLEFT, EL_INVISIBLE_STEELWALL_BOTTOMLEFT },
1298 { EL_STEELWALL_BOTTOMRIGHT, EL_INVISIBLE_STEELWALL_BOTTOMRIGHT },
1299 { EL_STEELWALL_VERTICAL, EL_INVISIBLE_STEELWALL_VERTICAL },
1300 { EL_STEELWALL_HORIZONTAL, EL_INVISIBLE_STEELWALL_HORIZONTAL },
1301 { EL_STEELWALL, EL_INVISIBLE_STEELWALL }
1303 int steel_type = (BorderElement == EL_STEELWALL ? 0 : 1);
1304 int steel_position = (x == -1 && y == -1 ? 0 :
1305 x == lev_fieldx && y == -1 ? 1 :
1306 x == -1 && y == lev_fieldy ? 2 :
1307 x == lev_fieldx && y == lev_fieldy ? 3 :
1308 x == -1 || x == lev_fieldx ? 4 :
1309 y == -1 || y == lev_fieldy ? 5 : 6);
1311 return border[steel_position][steel_type];
1314 void DrawScreenElement(int x, int y, int element)
1316 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
1317 DrawLevelFieldCrumbledSand(LEVELX(x), LEVELY(y));
1320 void DrawLevelElement(int x, int y, int element)
1322 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1323 DrawScreenElement(SCREENX(x), SCREENY(y), element);
1326 void DrawScreenField(int x, int y)
1328 int lx = LEVELX(x), ly = LEVELY(y);
1329 int element, content;
1331 if (!IN_LEV_FIELD(lx, ly))
1333 if (lx < -1 || lx > lev_fieldx || ly < -1 || ly > lev_fieldy)
1336 element = getBorderElement(lx, ly);
1338 DrawScreenElement(x, y, element);
1342 element = Feld[lx][ly];
1343 content = Store[lx][ly];
1345 if (IS_MOVING(lx, ly))
1347 int horiz_move = (MovDir[lx][ly] == MV_LEFT || MovDir[lx][ly] == MV_RIGHT);
1348 boolean cut_mode = NO_CUTTING;
1350 if (element == EL_QUICKSAND_EMPTYING ||
1351 element == EL_MAGIC_WALL_EMPTYING ||
1352 element == EL_BD_MAGIC_WALL_EMPTYING ||
1353 element == EL_AMOEBA_DROPPING)
1354 cut_mode = CUT_ABOVE;
1355 else if (element == EL_QUICKSAND_FILLING ||
1356 element == EL_MAGIC_WALL_FILLING ||
1357 element == EL_BD_MAGIC_WALL_FILLING)
1358 cut_mode = CUT_BELOW;
1360 if (cut_mode == CUT_ABOVE)
1361 DrawScreenElementShifted(x, y, 0, 0, element, NO_CUTTING);
1363 DrawScreenElement(x, y, EL_EMPTY);
1366 DrawScreenElementShifted(x, y, MovPos[lx][ly], 0, element, NO_CUTTING);
1367 else if (cut_mode == NO_CUTTING)
1368 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], element, cut_mode);
1370 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], content, cut_mode);
1372 if (content == EL_ACID)
1373 DrawLevelElementThruMask(lx, ly + 1, EL_ACID);
1375 else if (IS_BLOCKED(lx, ly))
1380 boolean cut_mode = NO_CUTTING;
1381 int element_old, content_old;
1383 Blocked2Moving(lx, ly, &oldx, &oldy);
1386 horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
1387 MovDir[oldx][oldy] == MV_RIGHT);
1389 element_old = Feld[oldx][oldy];
1390 content_old = Store[oldx][oldy];
1392 if (element_old == EL_QUICKSAND_EMPTYING ||
1393 element_old == EL_MAGIC_WALL_EMPTYING ||
1394 element_old == EL_BD_MAGIC_WALL_EMPTYING ||
1395 element_old == EL_AMOEBA_DROPPING)
1396 cut_mode = CUT_ABOVE;
1398 DrawScreenElement(x, y, EL_EMPTY);
1401 DrawScreenElementShifted(sx, sy, MovPos[oldx][oldy], 0, element_old,
1403 else if (cut_mode == NO_CUTTING)
1404 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], element_old,
1407 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], content_old,
1410 else if (IS_DRAWABLE(element))
1411 DrawScreenElement(x, y, element);
1413 DrawScreenElement(x, y, EL_EMPTY);
1416 void DrawLevelField(int x, int y)
1418 if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1419 DrawScreenField(SCREENX(x), SCREENY(y));
1420 else if (IS_MOVING(x, y))
1424 Moving2Blocked(x, y, &newx, &newy);
1425 if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
1426 DrawScreenField(SCREENX(newx), SCREENY(newy));
1428 else if (IS_BLOCKED(x, y))
1432 Blocked2Moving(x, y, &oldx, &oldy);
1433 if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
1434 DrawScreenField(SCREENX(oldx), SCREENY(oldy));
1438 void DrawMiniElement(int x, int y, int element)
1442 graphic = el2edimg(element);
1443 DrawMiniGraphic(x, y, graphic);
1446 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
1448 int x = sx + scroll_x, y = sy + scroll_y;
1450 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
1451 DrawMiniElement(sx, sy, EL_EMPTY);
1452 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
1453 DrawMiniElement(sx, sy, Feld[x][y]);
1455 DrawMiniGraphic(sx, sy, el2edimg(getBorderElement(x, y)));
1458 void getMicroGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
1460 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
1461 int mini_startx = src_bitmap->width * 3 / 4;
1462 int mini_starty = src_bitmap->height * 2 / 3;
1463 int src_x = mini_startx + graphic_info[graphic].src_x / 8;
1464 int src_y = mini_starty + graphic_info[graphic].src_y / 8;
1467 if (src_x + MICRO_TILEX > src_bitmap->width ||
1468 src_y + MICRO_TILEY > src_bitmap->height)
1470 /* graphic of desired size seems not to be contained in this image;
1471 dirty workaround: get it from the middle of the normal sized image */
1473 getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
1474 src_x += (TILEX / 2 - MICRO_TILEX / 2);
1475 src_y += (TILEY / 2 - MICRO_TILEY / 2);
1479 *bitmap = src_bitmap;
1484 void DrawMicroElement(int xpos, int ypos, int element)
1488 int graphic = el2preimg(element);
1490 getMicroGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
1491 BlitBitmap(src_bitmap, drawto, src_x, src_y, MICRO_TILEX, MICRO_TILEY,
1499 SetDrawBackgroundMask(REDRAW_NONE);
1502 for(x=BX1; x<=BX2; x++)
1503 for(y=BY1; y<=BY2; y++)
1504 DrawScreenField(x, y);
1506 redraw_mask |= REDRAW_FIELD;
1509 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
1513 for(x=0; x<size_x; x++)
1514 for(y=0; y<size_y; y++)
1515 DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
1517 redraw_mask |= REDRAW_FIELD;
1520 static void DrawMicroLevelExt(int xpos, int ypos, int from_x, int from_y)
1524 DrawBackground(xpos, ypos, MICROLEV_XSIZE, MICROLEV_YSIZE);
1526 if (lev_fieldx < STD_LEV_FIELDX)
1527 xpos += (STD_LEV_FIELDX - lev_fieldx) / 2 * MICRO_TILEX;
1528 if (lev_fieldy < STD_LEV_FIELDY)
1529 ypos += (STD_LEV_FIELDY - lev_fieldy) / 2 * MICRO_TILEY;
1531 xpos += MICRO_TILEX;
1532 ypos += MICRO_TILEY;
1534 for(x=-1; x<=STD_LEV_FIELDX; x++)
1536 for(y=-1; y<=STD_LEV_FIELDY; y++)
1538 int lx = from_x + x, ly = from_y + y;
1540 if (lx >= 0 && lx < lev_fieldx && ly >= 0 && ly < lev_fieldy)
1541 DrawMicroElement(xpos + x * MICRO_TILEX, ypos + y * MICRO_TILEY,
1543 else if (lx >= -1 && lx < lev_fieldx+1 && ly >= -1 && ly < lev_fieldy+1
1544 && BorderElement != EL_EMPTY)
1545 DrawMicroElement(xpos + x * MICRO_TILEX, ypos + y * MICRO_TILEY,
1546 getBorderElement(lx, ly));
1550 redraw_mask |= REDRAW_MICROLEVEL;
1553 #define MICROLABEL_EMPTY 0
1554 #define MICROLABEL_LEVEL_NAME 1
1555 #define MICROLABEL_CREATED_BY 2
1556 #define MICROLABEL_LEVEL_AUTHOR 3
1557 #define MICROLABEL_IMPORTED_FROM 4
1558 #define MICROLABEL_LEVEL_IMPORT_INFO 5
1560 static void DrawMicroLevelLabelExt(int mode)
1562 char label_text[MAX_OUTPUT_LINESIZE + 1];
1563 int max_len_label_text;
1564 int font_nr = FONT_TEXT_2;
1566 if (mode == MICROLABEL_CREATED_BY || mode == MICROLABEL_IMPORTED_FROM)
1567 font_nr = FONT_TEXT_3;
1569 max_len_label_text = SXSIZE / getFontWidth(font_nr);
1571 DrawBackground(SX, MICROLABEL_YPOS, SXSIZE, getFontHeight(font_nr));
1573 strncpy(label_text, (mode == MICROLABEL_LEVEL_NAME ? level.name :
1574 mode == MICROLABEL_CREATED_BY ? "created by" :
1575 mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
1576 mode == MICROLABEL_IMPORTED_FROM ? "imported from" :
1577 mode == MICROLABEL_LEVEL_IMPORT_INFO ?
1578 leveldir_current->imported_from : ""),
1579 max_len_label_text);
1580 label_text[max_len_label_text] = '\0';
1582 if (strlen(label_text) > 0)
1584 int text_width = strlen(label_text) * getFontWidth(font_nr);
1585 int lxpos = SX + (SXSIZE - text_width) / 2;
1586 int lypos = MICROLABEL_YPOS;
1588 DrawText(lxpos, lypos, label_text, font_nr);
1591 redraw_mask |= REDRAW_MICROLEVEL;
1594 void DrawMicroLevel(int xpos, int ypos, boolean restart)
1596 static unsigned long scroll_delay = 0;
1597 static unsigned long label_delay = 0;
1598 static int from_x, from_y, scroll_direction;
1599 static int label_state, label_counter;
1600 int last_game_status = game_status; /* save current game status */
1602 /* force PREVIEW font on preview level */
1603 game_status = GAME_MODE_PSEUDO_PREVIEW;
1607 from_x = from_y = 0;
1608 scroll_direction = MV_RIGHT;
1612 DrawMicroLevelExt(xpos, ypos, from_x, from_y);
1613 DrawMicroLevelLabelExt(label_state);
1615 /* initialize delay counters */
1616 DelayReached(&scroll_delay, 0);
1617 DelayReached(&label_delay, 0);
1619 if (leveldir_current->name)
1621 int len = strlen(leveldir_current->name);
1622 int lxpos = SX + (SXSIZE - len * getFontWidth(FONT_TEXT_1)) / 2;
1623 int lypos = SY + 352;
1625 DrawText(lxpos, lypos, leveldir_current->name, FONT_TEXT_1);
1628 game_status = last_game_status; /* restore current game status */
1633 /* scroll micro level, if needed */
1634 if ((lev_fieldx > STD_LEV_FIELDX || lev_fieldy > STD_LEV_FIELDY) &&
1635 DelayReached(&scroll_delay, MICROLEVEL_SCROLL_DELAY))
1637 switch (scroll_direction)
1643 scroll_direction = MV_UP;
1647 if (from_x < lev_fieldx - STD_LEV_FIELDX)
1650 scroll_direction = MV_DOWN;
1657 scroll_direction = MV_RIGHT;
1661 if (from_y < lev_fieldy - STD_LEV_FIELDY)
1664 scroll_direction = MV_LEFT;
1671 DrawMicroLevelExt(xpos, ypos, from_x, from_y);
1674 /* redraw micro level label, if needed */
1675 if (strcmp(level.name, NAMELESS_LEVEL_NAME) != 0 &&
1676 strcmp(level.author, ANONYMOUS_NAME) != 0 &&
1677 strcmp(level.author, leveldir_current->name) != 0 &&
1678 DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
1680 int max_label_counter = 23;
1682 if (leveldir_current->imported_from != NULL)
1683 max_label_counter += 14;
1685 label_counter = (label_counter + 1) % max_label_counter;
1686 label_state = (label_counter >= 0 && label_counter <= 7 ?
1687 MICROLABEL_LEVEL_NAME :
1688 label_counter >= 9 && label_counter <= 12 ?
1689 MICROLABEL_CREATED_BY :
1690 label_counter >= 14 && label_counter <= 21 ?
1691 MICROLABEL_LEVEL_AUTHOR :
1692 label_counter >= 23 && label_counter <= 26 ?
1693 MICROLABEL_IMPORTED_FROM :
1694 label_counter >= 28 && label_counter <= 35 ?
1695 MICROLABEL_LEVEL_IMPORT_INFO : MICROLABEL_EMPTY);
1696 DrawMicroLevelLabelExt(label_state);
1699 game_status = last_game_status; /* restore current game status */
1702 int REQ_in_range(int x, int y)
1704 if (y > DY+249 && y < DY+278)
1706 if (x > DX+1 && x < DX+48)
1708 else if (x > DX+51 && x < DX+98)
1714 #define MAX_REQUEST_LINES 13
1715 #define MAX_REQUEST_LINE_LEN 7
1717 boolean Request(char *text, unsigned int req_state)
1719 int mx, my, ty, result = -1;
1720 unsigned int old_door_state;
1721 int last_game_status = game_status; /* save current game status */
1723 #if defined(PLATFORM_UNIX)
1724 /* pause network game while waiting for request to answer */
1725 if (options.network &&
1726 game_status == GAME_MODE_PLAYING &&
1727 req_state & REQUEST_WAIT_FOR)
1728 SendToServer_PausePlaying();
1731 old_door_state = GetDoorState();
1735 CloseDoor(DOOR_CLOSE_1);
1737 /* save old door content */
1738 BlitBitmap(bitmap_db_door, bitmap_db_door,
1739 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
1740 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
1742 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
1744 /* clear door drawing field */
1745 DrawBackground(DX, DY, DXSIZE, DYSIZE);
1747 /* force DOOR font on preview level */
1748 game_status = GAME_MODE_PSEUDO_DOOR;
1750 /* write text for request */
1751 for(ty=0; ty < MAX_REQUEST_LINES; ty++)
1753 char text_line[MAX_REQUEST_LINE_LEN + 1];
1759 for(tl=0,tx=0; tx < MAX_REQUEST_LINE_LEN; tl++,tx++)
1762 if (!tc || tc == ' ')
1773 strncpy(text_line, text, tl);
1776 DrawText(DX + (DXSIZE - tl * getFontWidth(FONT_TEXT_2)) / 2,
1777 DY + 8 + ty * (getFontHeight(FONT_TEXT_2) + 2),
1778 text_line, FONT_TEXT_2);
1780 text += tl + (tc == ' ' ? 1 : 0);
1783 game_status = last_game_status; /* restore current game status */
1785 if (req_state & REQ_ASK)
1787 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
1788 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
1790 else if (req_state & REQ_CONFIRM)
1792 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
1794 else if (req_state & REQ_PLAYER)
1796 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
1797 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
1798 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
1799 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
1802 /* copy request gadgets to door backbuffer */
1803 BlitBitmap(drawto, bitmap_db_door,
1804 DX, DY, DXSIZE, DYSIZE,
1805 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
1807 OpenDoor(DOOR_OPEN_1);
1813 if (!(req_state & REQUEST_WAIT_FOR))
1815 SetDrawBackgroundMask(REDRAW_FIELD);
1820 if (game_status != GAME_MODE_MAIN)
1823 button_status = MB_RELEASED;
1825 request_gadget_id = -1;
1827 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
1839 case EVENT_BUTTONPRESS:
1840 case EVENT_BUTTONRELEASE:
1841 case EVENT_MOTIONNOTIFY:
1843 if (event.type == EVENT_MOTIONNOTIFY)
1845 if (!PointerInWindow(window))
1846 continue; /* window and pointer are on different screens */
1851 motion_status = TRUE;
1852 mx = ((MotionEvent *) &event)->x;
1853 my = ((MotionEvent *) &event)->y;
1857 motion_status = FALSE;
1858 mx = ((ButtonEvent *) &event)->x;
1859 my = ((ButtonEvent *) &event)->y;
1860 if (event.type == EVENT_BUTTONPRESS)
1861 button_status = ((ButtonEvent *) &event)->button;
1863 button_status = MB_RELEASED;
1866 /* this sets 'request_gadget_id' */
1867 HandleGadgets(mx, my, button_status);
1869 switch(request_gadget_id)
1871 case TOOL_CTRL_ID_YES:
1874 case TOOL_CTRL_ID_NO:
1877 case TOOL_CTRL_ID_CONFIRM:
1878 result = TRUE | FALSE;
1881 case TOOL_CTRL_ID_PLAYER_1:
1884 case TOOL_CTRL_ID_PLAYER_2:
1887 case TOOL_CTRL_ID_PLAYER_3:
1890 case TOOL_CTRL_ID_PLAYER_4:
1901 case EVENT_KEYPRESS:
1902 switch(GetEventKey((KeyEvent *)&event, TRUE))
1915 if (req_state & REQ_PLAYER)
1919 case EVENT_KEYRELEASE:
1920 ClearPlayerAction();
1924 HandleOtherEvents(&event);
1928 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
1930 int joy = AnyJoystick();
1932 if (joy & JOY_BUTTON_1)
1934 else if (joy & JOY_BUTTON_2)
1940 /* don't eat all CPU time */
1944 if (game_status != GAME_MODE_MAIN)
1949 if (!(req_state & REQ_STAY_OPEN))
1951 CloseDoor(DOOR_CLOSE_1);
1953 if (!(req_state & REQ_STAY_CLOSED) && (old_door_state & DOOR_OPEN_1))
1955 BlitBitmap(bitmap_db_door, bitmap_db_door,
1956 DOOR_GFX_PAGEX2,DOOR_GFX_PAGEY1, DXSIZE,DYSIZE,
1957 DOOR_GFX_PAGEX1,DOOR_GFX_PAGEY1);
1958 OpenDoor(DOOR_OPEN_1);
1964 SetDrawBackgroundMask(REDRAW_FIELD);
1966 #if defined(PLATFORM_UNIX)
1967 /* continue network game after request */
1968 if (options.network &&
1969 game_status == GAME_MODE_PLAYING &&
1970 req_state & REQUEST_WAIT_FOR)
1971 SendToServer_ContinuePlaying();
1977 unsigned int OpenDoor(unsigned int door_state)
1979 unsigned int new_door_state;
1981 if (door_state & DOOR_COPY_BACK)
1983 BlitBitmap(bitmap_db_door, bitmap_db_door,
1984 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE + VYSIZE,
1985 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
1986 door_state &= ~DOOR_COPY_BACK;
1989 new_door_state = MoveDoor(door_state);
1991 return(new_door_state);
1994 unsigned int CloseDoor(unsigned int door_state)
1996 unsigned int new_door_state;
1998 BlitBitmap(backbuffer, bitmap_db_door,
1999 DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2000 BlitBitmap(backbuffer, bitmap_db_door,
2001 VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
2003 new_door_state = MoveDoor(door_state);
2005 return(new_door_state);
2008 unsigned int GetDoorState()
2010 return MoveDoor(DOOR_GET_STATE);
2013 unsigned int SetDoorState(unsigned int door_state)
2015 return MoveDoor(door_state | DOOR_SET_STATE);
2018 unsigned int MoveDoor(unsigned int door_state)
2020 static int door1 = DOOR_OPEN_1;
2021 static int door2 = DOOR_CLOSE_2;
2022 static unsigned long door_delay = 0;
2023 int x, start, stepsize = door.step_offset;
2024 unsigned long door_delay_value = door.step_delay;
2026 if (door_state == DOOR_GET_STATE)
2027 return(door1 | door2);
2029 if (door_state & DOOR_SET_STATE)
2031 if (door_state & DOOR_ACTION_1)
2032 door1 = door_state & DOOR_ACTION_1;
2033 if (door_state & DOOR_ACTION_2)
2034 door2 = door_state & DOOR_ACTION_2;
2036 return(door1 | door2);
2039 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
2040 door_state &= ~DOOR_OPEN_1;
2041 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
2042 door_state &= ~DOOR_CLOSE_1;
2043 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
2044 door_state &= ~DOOR_OPEN_2;
2045 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
2046 door_state &= ~DOOR_CLOSE_2;
2048 if (setup.quick_doors)
2051 door_delay_value = 0;
2053 StopSound(SND_DOOR_OPENING);
2054 StopSound(SND_DOOR_CLOSING);
2057 if (global.autoplay_leveldir)
2059 door_state |= DOOR_NO_DELAY;
2060 door_state &= ~DOOR_CLOSE_ALL;
2063 if (door_state & DOOR_ACTION)
2065 if (!(door_state & DOOR_NO_DELAY))
2067 /* opening door sound has priority over simultaneously closing door */
2068 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
2069 PlaySoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
2070 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
2071 PlaySoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
2074 start = ((door_state & DOOR_NO_DELAY) ? DXSIZE : 0);
2076 for(x=start; x<=DXSIZE; x+=stepsize)
2078 Bitmap *bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
2079 GC gc = bitmap->stored_clip_gc;
2081 if (!(door_state & DOOR_NO_DELAY))
2082 WaitUntilDelayReached(&door_delay, door_delay_value);
2084 if (door_state & DOOR_ACTION_1)
2086 int i = (door_state & DOOR_OPEN_1 ? DXSIZE-x : x);
2087 int j = (DXSIZE - i) / 3;
2089 BlitBitmap(bitmap_db_door, drawto,
2090 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + i/2,
2091 DXSIZE,DYSIZE - i/2, DX, DY);
2093 ClearRectangle(drawto, DX, DY + DYSIZE - i/2, DXSIZE,i/2);
2095 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2096 BlitBitmapMasked(bitmap, drawto,
2097 DXSIZE, DOOR_GFX_PAGEY1, i, 77,
2098 DX + DXSIZE - i, DY + j);
2099 BlitBitmapMasked(bitmap, drawto,
2100 DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63,
2101 DX + DXSIZE - i, DY + 140 + j);
2102 SetClipOrigin(bitmap, gc, DX - DXSIZE + i, DY - (DOOR_GFX_PAGEY1 + j));
2103 BlitBitmapMasked(bitmap, drawto,
2104 DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j,
2106 BlitBitmapMasked(bitmap, drawto,
2107 DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63,
2110 BlitBitmapMasked(bitmap, drawto,
2111 DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
2113 BlitBitmapMasked(bitmap, drawto,
2114 DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
2116 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2117 BlitBitmapMasked(bitmap, drawto,
2118 DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
2119 DX + DXSIZE - i, DY + 77 + j);
2120 BlitBitmapMasked(bitmap, drawto,
2121 DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
2122 DX + DXSIZE - i, DY + 203 + j);
2124 redraw_mask |= REDRAW_DOOR_1;
2127 if (door_state & DOOR_ACTION_2)
2129 int i = (door_state & DOOR_OPEN_2 ? VXSIZE - x : x);
2130 int j = (VXSIZE - i) / 3;
2132 BlitBitmap(bitmap_db_door, drawto,
2133 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + i/2,
2134 VXSIZE, VYSIZE - i/2, VX, VY);
2136 ClearRectangle(drawto, VX, VY + VYSIZE-i/2, VXSIZE, i/2);
2138 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2139 BlitBitmapMasked(bitmap, drawto,
2140 VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2,
2141 VX + VXSIZE-i, VY+j);
2142 SetClipOrigin(bitmap, gc,
2143 VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
2144 BlitBitmapMasked(bitmap, drawto,
2145 VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j,
2148 BlitBitmapMasked(bitmap, drawto,
2149 VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2,
2150 i, VYSIZE / 2, VX, VY + VYSIZE / 2 - j);
2151 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2152 BlitBitmapMasked(bitmap, drawto,
2153 VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2,
2155 VX + VXSIZE - i, VY + VYSIZE / 2 + j);
2157 redraw_mask |= REDRAW_DOOR_2;
2162 if (game_status == GAME_MODE_MAIN)
2167 if (setup.quick_doors)
2169 StopSound(SND_DOOR_OPENING);
2170 StopSound(SND_DOOR_CLOSING);
2173 if (door_state & DOOR_ACTION_1)
2174 door1 = door_state & DOOR_ACTION_1;
2175 if (door_state & DOOR_ACTION_2)
2176 door2 = door_state & DOOR_ACTION_2;
2178 return (door1 | door2);
2181 void DrawSpecialEditorDoor()
2183 /* draw bigger toolbox window */
2184 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
2185 DOOR_GFX_PAGEX7, 0, EXSIZE + 8, 8,
2187 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
2188 EX - 4, VY - 4, EXSIZE + 8, EYSIZE - VYSIZE + 4,
2191 redraw_mask |= REDRAW_ALL;
2194 void UndrawSpecialEditorDoor()
2196 /* draw normal tape recorder window */
2197 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
2198 EX - 4, EY - 12, EXSIZE + 8, EYSIZE - VYSIZE + 12,
2201 redraw_mask |= REDRAW_ALL;
2205 /* ---------- new tool button stuff ---------------------------------------- */
2207 /* graphic position values for tool buttons */
2208 #define TOOL_BUTTON_YES_XPOS 2
2209 #define TOOL_BUTTON_YES_YPOS 250
2210 #define TOOL_BUTTON_YES_GFX_YPOS 0
2211 #define TOOL_BUTTON_YES_XSIZE 46
2212 #define TOOL_BUTTON_YES_YSIZE 28
2213 #define TOOL_BUTTON_NO_XPOS 52
2214 #define TOOL_BUTTON_NO_YPOS TOOL_BUTTON_YES_YPOS
2215 #define TOOL_BUTTON_NO_GFX_YPOS TOOL_BUTTON_YES_GFX_YPOS
2216 #define TOOL_BUTTON_NO_XSIZE TOOL_BUTTON_YES_XSIZE
2217 #define TOOL_BUTTON_NO_YSIZE TOOL_BUTTON_YES_YSIZE
2218 #define TOOL_BUTTON_CONFIRM_XPOS TOOL_BUTTON_YES_XPOS
2219 #define TOOL_BUTTON_CONFIRM_YPOS TOOL_BUTTON_YES_YPOS
2220 #define TOOL_BUTTON_CONFIRM_GFX_YPOS 30
2221 #define TOOL_BUTTON_CONFIRM_XSIZE 96
2222 #define TOOL_BUTTON_CONFIRM_YSIZE TOOL_BUTTON_YES_YSIZE
2223 #define TOOL_BUTTON_PLAYER_XSIZE 30
2224 #define TOOL_BUTTON_PLAYER_YSIZE 30
2225 #define TOOL_BUTTON_PLAYER_GFX_XPOS 5
2226 #define TOOL_BUTTON_PLAYER_GFX_YPOS 185
2227 #define TOOL_BUTTON_PLAYER_XPOS (5 + TOOL_BUTTON_PLAYER_XSIZE / 2)
2228 #define TOOL_BUTTON_PLAYER_YPOS (215 - TOOL_BUTTON_PLAYER_YSIZE / 2)
2229 #define TOOL_BUTTON_PLAYER1_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2230 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2231 #define TOOL_BUTTON_PLAYER2_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2232 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2233 #define TOOL_BUTTON_PLAYER3_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2234 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2235 #define TOOL_BUTTON_PLAYER4_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2236 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2237 #define TOOL_BUTTON_PLAYER1_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2238 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2239 #define TOOL_BUTTON_PLAYER2_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2240 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2241 #define TOOL_BUTTON_PLAYER3_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2242 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2243 #define TOOL_BUTTON_PLAYER4_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2244 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2253 } toolbutton_info[NUM_TOOL_BUTTONS] =
2256 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_GFX_YPOS,
2257 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_YPOS,
2258 TOOL_BUTTON_YES_XSIZE, TOOL_BUTTON_YES_YSIZE,
2263 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_GFX_YPOS,
2264 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_YPOS,
2265 TOOL_BUTTON_NO_XSIZE, TOOL_BUTTON_NO_YSIZE,
2270 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_GFX_YPOS,
2271 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_YPOS,
2272 TOOL_BUTTON_CONFIRM_XSIZE, TOOL_BUTTON_CONFIRM_YSIZE,
2273 TOOL_CTRL_ID_CONFIRM,
2277 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2278 TOOL_BUTTON_PLAYER1_XPOS, TOOL_BUTTON_PLAYER1_YPOS,
2279 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2280 TOOL_CTRL_ID_PLAYER_1,
2284 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2285 TOOL_BUTTON_PLAYER2_XPOS, TOOL_BUTTON_PLAYER2_YPOS,
2286 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2287 TOOL_CTRL_ID_PLAYER_2,
2291 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2292 TOOL_BUTTON_PLAYER3_XPOS, TOOL_BUTTON_PLAYER3_YPOS,
2293 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2294 TOOL_CTRL_ID_PLAYER_3,
2298 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2299 TOOL_BUTTON_PLAYER4_XPOS, TOOL_BUTTON_PLAYER4_YPOS,
2300 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2301 TOOL_CTRL_ID_PLAYER_4,
2306 void CreateToolButtons()
2310 for (i=0; i<NUM_TOOL_BUTTONS; i++)
2312 Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
2313 Bitmap *deco_bitmap = None;
2314 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
2315 struct GadgetInfo *gi;
2316 unsigned long event_mask;
2317 int gd_xoffset, gd_yoffset;
2318 int gd_x1, gd_x2, gd_y;
2321 event_mask = GD_EVENT_RELEASED;
2323 gd_xoffset = toolbutton_info[i].xpos;
2324 gd_yoffset = toolbutton_info[i].ypos;
2325 gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
2326 gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
2327 gd_y = DOOR_GFX_PAGEY1 + gd_yoffset;
2329 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
2331 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
2333 getMiniGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr),
2334 &deco_bitmap, &deco_x, &deco_y);
2335 deco_xpos = (toolbutton_info[i].width - MINI_TILEX) / 2;
2336 deco_ypos = (toolbutton_info[i].height - MINI_TILEY) / 2;
2339 gi = CreateGadget(GDI_CUSTOM_ID, id,
2340 GDI_INFO_TEXT, toolbutton_info[i].infotext,
2341 GDI_X, DX + toolbutton_info[i].x,
2342 GDI_Y, DY + toolbutton_info[i].y,
2343 GDI_WIDTH, toolbutton_info[i].width,
2344 GDI_HEIGHT, toolbutton_info[i].height,
2345 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
2346 GDI_STATE, GD_BUTTON_UNPRESSED,
2347 GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
2348 GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
2349 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
2350 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
2351 GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
2352 GDI_DECORATION_SHIFTING, 1, 1,
2353 GDI_EVENT_MASK, event_mask,
2354 GDI_CALLBACK_ACTION, HandleToolButtons,
2358 Error(ERR_EXIT, "cannot create gadget");
2360 tool_gadget[id] = gi;
2364 void FreeToolButtons()
2368 for (i=0; i<NUM_TOOL_BUTTONS; i++)
2369 FreeGadget(tool_gadget[i]);
2372 static void UnmapToolButtons()
2376 for (i=0; i<NUM_TOOL_BUTTONS; i++)
2377 UnmapGadget(tool_gadget[i]);
2380 static void HandleToolButtons(struct GadgetInfo *gi)
2382 request_gadget_id = gi->custom_id;
2385 int get_next_element(int element)
2389 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
2390 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
2391 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
2392 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
2393 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
2394 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
2395 case EL_AMOEBA_DROPPING: return EL_AMOEBA_WET;
2397 default: return element;
2401 int el_act_dir2img(int element, int action, int direction)
2403 element = GFX_ELEMENT(element);
2404 direction = MV_DIR_BIT(direction);
2406 return element_info[element].direction_graphic[action][direction];
2409 int el_act2img(int element, int action)
2411 element = GFX_ELEMENT(element);
2413 return element_info[element].graphic[action];
2416 int el_dir2img(int element, int direction)
2418 element = GFX_ELEMENT(element);
2420 return el_act_dir2img(element, ACTION_DEFAULT, direction);
2423 int el2img(int element)
2425 element = GFX_ELEMENT(element);
2427 return element_info[element].graphic[ACTION_DEFAULT];
2430 int el2edimg(int element)
2432 element = GFX_ELEMENT(element);
2434 return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
2437 int el2preimg(int element)
2439 element = GFX_ELEMENT(element);
2441 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];