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,
711 int element = Feld[jx][jy];
713 int element = Feld[next_jx][next_jy];
716 int graphic = el2img(element);
719 if ((sxx || syy) && IS_PUSHABLE(element))
721 graphic = el_act_dir2img(element, ACTION_MOVING, move_dir);
722 frame = getGraphicAnimationFrame(graphic, player->Frame);
725 DrawGraphicShifted(px, py, sxx, syy, graphic, frame,
726 NO_CUTTING, NO_MASKING);
730 /* ----------------------------------------------------------------------- */
731 /* draw things in front of player (active dynamite or dynabombs) */
732 /* ----------------------------------------------------------------------- */
734 if (IS_ACTIVE_BOMB(element))
736 graphic = el2img(element);
737 frame = getGraphicAnimationFrame(graphic, GfxFrame[jx][jy]);
739 if (game.emulation == EMU_SUPAPLEX)
740 DrawGraphic(sx, sy, IMG_SP_DISK_RED, frame);
742 DrawGraphicThruMask(sx, sy, graphic, frame);
745 if (player_is_moving && last_element == EL_EXPLOSION)
748 int graphic = el_act2img(GfxElement[last_jx][last_jy], ACTION_EXPLODING);
750 int stored = Store[last_jx][last_jy];
751 int graphic = (game.emulation != EMU_SUPAPLEX ? IMG_EXPLOSION :
752 stored == EL_SP_INFOTRON ? IMG_SP_EXPLOSION_INFOTRON :
755 int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
756 int phase = ExplodePhase[last_jx][last_jy] - 1;
757 int frame = getGraphicAnimationFrame(graphic, phase - delay);
760 DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy), graphic, frame);
763 /* ----------------------------------------------------------------------- */
764 /* draw elements the player is just walking/passing through/under */
765 /* ----------------------------------------------------------------------- */
767 /* handle the field the player is leaving ... */
768 if (player_is_moving && IS_ACCESSIBLE_INSIDE(last_element))
769 DrawLevelField(last_jx, last_jy);
770 else if (player_is_moving && IS_ACCESSIBLE_UNDER(last_element))
771 DrawLevelFieldThruMask(last_jx, last_jy);
773 /* ... and the field the player is entering */
774 if (IS_ACCESSIBLE_INSIDE(element))
775 DrawLevelField(jx, jy);
776 else if (IS_ACCESSIBLE_UNDER(element))
777 DrawLevelFieldThruMask(jx, jy);
779 if (setup.direct_draw)
781 int dest_x = SX + SCREENX(MIN(jx, last_jx)) * TILEX;
782 int dest_y = SY + SCREENY(MIN(jy, last_jy)) * TILEY;
783 int x_size = TILEX * (1 + ABS(jx - last_jx));
784 int y_size = TILEY * (1 + ABS(jy - last_jy));
786 BlitBitmap(drawto_field, window,
787 dest_x, dest_y, x_size, y_size, dest_x, dest_y);
788 SetDrawtoField(DRAW_DIRECT);
791 MarkTileDirty(sx,sy);
794 void getGraphicSource(int graphic, int frame, Bitmap **bitmap, int *x, int *y)
796 struct GraphicInfo *g = &graphic_info[graphic];
800 if (g->offset_y == 0) /* frames are ordered horizontally */
802 int max_width = g->anim_frames_per_line * g->width;
804 *x = (g->src_x + frame * g->offset_x) % max_width;
805 *y = g->src_y + (g->src_x + frame * g->offset_x) / max_width * g->height;
807 else if (g->offset_x == 0) /* frames are ordered vertically */
809 int max_height = g->anim_frames_per_line * g->height;
811 *x = g->src_x + (g->src_y + frame * g->offset_y) / max_height * g->width;
812 *y = (g->src_y + frame * g->offset_y) % max_height;
814 else /* frames are ordered diagonally */
816 *x = g->src_x + frame * g->offset_x;
817 *y = g->src_y + frame * g->offset_y;
821 void DrawGraphic(int x, int y, int graphic, int frame)
824 if (!IN_SCR_FIELD(x, y))
826 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
827 printf("DrawGraphic(): This should never happen!\n");
832 DrawGraphicExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic, frame);
837 void DrawOldGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic)
842 getOldGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
843 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
847 void DrawGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
854 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
856 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
857 int src_x = graphic_info[graphic].src_x;
858 int src_y = graphic_info[graphic].src_y;
859 int offset_x = graphic_info[graphic].offset_x;
860 int offset_y = graphic_info[graphic].offset_y;
862 src_x += frame * offset_x;
863 src_y += frame * offset_y;
866 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
869 void DrawGraphicThruMask(int x, int y, int graphic, int frame)
872 if (!IN_SCR_FIELD(x, y))
874 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
875 printf("DrawGraphicThruMask(): This should never happen!\n");
880 DrawGraphicThruMaskExt(drawto_field, FX + x * TILEX, FY + y *TILEY, graphic,
885 void DrawGraphicThruMaskExt(DrawBuffer *d, int dest_x, int dest_y, int graphic,
893 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
894 drawing_gc = src_bitmap->stored_clip_gc;
896 GC drawing_gc = src_bitmap->stored_clip_gc;
897 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
898 int src_x = graphic_info[graphic].src_x;
899 int src_y = graphic_info[graphic].src_y;
900 int offset_x = graphic_info[graphic].offset_x;
901 int offset_y = graphic_info[graphic].offset_y;
903 src_x += frame * offset_x;
904 src_y += frame * offset_y;
908 SetClipOrigin(src_bitmap, drawing_gc, dest_x - src_x, dest_y - src_y);
909 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX, TILEY, dest_x, dest_y);
912 void DrawMiniGraphic(int x, int y, int graphic)
914 DrawMiniGraphicExt(drawto, SX + x * MINI_TILEX,SY + y * MINI_TILEY, graphic);
915 MarkTileDirty(x / 2, y / 2);
918 void getMiniGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
920 struct GraphicInfo *g = &graphic_info[graphic];
922 int mini_starty = g->bitmap->height * 2 / 3;
925 *x = mini_startx + g->src_x / 2;
926 *y = mini_starty + g->src_y / 2;
929 void DrawMiniGraphicExt(DrawBuffer *d, int x, int y, int graphic)
934 getMiniGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
935 BlitBitmap(src_bitmap, d, src_x, src_y, MINI_TILEX, MINI_TILEY, x, y);
938 void DrawGraphicShifted(int x,int y, int dx,int dy, int graphic, int frame,
939 int cut_mode, int mask_mode)
944 int width = TILEX, height = TILEY;
950 DrawGraphic(x, y, graphic, frame);
954 if (dx || dy) /* shifted graphic */
956 if (x < BX1) /* object enters playfield from the left */
963 else if (x > BX2) /* object enters playfield from the right */
969 else if (x==BX1 && dx < 0) /* object leaves playfield to the left */
975 else if (x==BX2 && dx > 0) /* object leaves playfield to the right */
977 else if (dx) /* general horizontal movement */
978 MarkTileDirty(x + SIGN(dx), y);
980 if (y < BY1) /* object enters playfield from the top */
982 if (cut_mode==CUT_BELOW) /* object completely above top border */
990 else if (y > BY2) /* object enters playfield from the bottom */
996 else if (y==BY1 && dy < 0) /* object leaves playfield to the top */
1002 else if (dy > 0 && cut_mode == CUT_ABOVE)
1004 if (y == BY2) /* object completely above bottom border */
1010 MarkTileDirty(x, y + 1);
1011 } /* object leaves playfield to the bottom */
1012 else if (dy > 0 && (y == BY2 || cut_mode == CUT_BELOW))
1014 else if (dy) /* general vertical movement */
1015 MarkTileDirty(x, y + SIGN(dy));
1019 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1021 src_bitmap = graphic_info[graphic].bitmap;
1022 src_x = graphic_info[graphic].src_x;
1023 src_y = graphic_info[graphic].src_y;
1024 offset_x = graphic_info[graphic].offset_x;
1025 offset_y = graphic_info[graphic].offset_y;
1027 src_x += frame * offset_x;
1028 src_y += frame * offset_y;
1031 drawing_gc = src_bitmap->stored_clip_gc;
1036 dest_x = FX + x * TILEX + dx;
1037 dest_y = FY + y * TILEY + dy;
1040 if (!IN_SCR_FIELD(x,y))
1042 printf("DrawGraphicShifted(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
1043 printf("DrawGraphicShifted(): This should never happen!\n");
1048 if (mask_mode == USE_MASKING)
1050 SetClipOrigin(src_bitmap, drawing_gc, dest_x - src_x, dest_y - src_y);
1051 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1055 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1061 void DrawGraphicShiftedThruMask(int x, int y, int dx, int dy, int graphic,
1062 int frame, int cut_mode)
1064 DrawGraphicShifted(x,y, dx,dy, graphic, frame, cut_mode, USE_MASKING);
1067 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
1068 int cut_mode, int mask_mode)
1070 int lx = LEVELX(x), ly = LEVELY(y);
1074 if (IN_LEV_FIELD(lx, ly))
1076 SetRandomAnimationValue(lx, ly);
1078 graphic = el_act_dir2img(element, GfxAction[lx][ly], MovDir[lx][ly]);
1079 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1081 else /* border element */
1083 graphic = el2img(element);
1084 frame = getGraphicAnimationFrame(graphic, -1);
1087 if (element == EL_EXPANDABLE_WALL)
1089 boolean left_stopped = FALSE, right_stopped = FALSE;
1091 if (!IN_LEV_FIELD(lx - 1, ly) || IS_WALL(Feld[lx - 1][ly]))
1092 left_stopped = TRUE;
1093 if (!IN_LEV_FIELD(lx + 1, ly) || IS_WALL(Feld[lx + 1][ly]))
1094 right_stopped = TRUE;
1096 if (left_stopped && right_stopped)
1098 else if (left_stopped)
1100 graphic = IMG_EXPANDABLE_WALL_GROWING_RIGHT;
1101 frame = graphic_info[graphic].anim_frames - 1;
1103 else if (right_stopped)
1105 graphic = IMG_EXPANDABLE_WALL_GROWING_LEFT;
1106 frame = graphic_info[graphic].anim_frames - 1;
1110 else if (IS_AMOEBOID(element) || element == EL_AMOEBA_DROPPING)
1112 graphic = (element == EL_BD_AMOEBA ? IMG_BD_AMOEBA_PART1 :
1113 element == EL_AMOEBA_WET ? IMG_AMOEBA_WET_PART1 :
1114 element == EL_AMOEBA_DRY ? IMG_AMOEBA_DRY_PART1 :
1115 element == EL_AMOEBA_FULL ? IMG_AMOEBA_FULL_PART1 :
1116 IMG_AMOEBA_DEAD_PART1);
1118 graphic += (x + 2 * y + 4) % 4;
1123 if (IS_AMOEBOID(element) || element == EL_AMOEBA_DROPPING)
1125 if (Feld[lx][ly] == EL_AMOEBA_DROPPING)
1126 printf("---> %d -> %d / %d [%d]\n",
1127 element, graphic, frame, GfxRandom[lx][ly]);
1132 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, mask_mode);
1133 else if (mask_mode == USE_MASKING)
1134 DrawGraphicThruMask(x, y, graphic, frame);
1136 DrawGraphic(x, y, graphic, frame);
1139 void DrawLevelElementExt(int x, int y, int dx, int dy, int element,
1140 int cut_mode, int mask_mode)
1142 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1143 DrawScreenElementExt(SCREENX(x), SCREENY(y), dx, dy, element,
1144 cut_mode, mask_mode);
1147 void DrawScreenElementShifted(int x, int y, int dx, int dy, int element,
1150 DrawScreenElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1153 void DrawLevelElementShifted(int x, int y, int dx, int dy, int element,
1156 DrawLevelElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1160 void DrawOldScreenElementThruMask(int x, int y, int element)
1162 DrawOldScreenElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1165 void DrawScreenElementThruMask(int x, int y, int element)
1167 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1171 void DrawLevelElementThruMask(int x, int y, int element)
1173 DrawLevelElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1176 void DrawLevelFieldThruMask(int x, int y)
1178 DrawLevelElementExt(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
1181 static void DrawLevelFieldCrumbledSandExt(int x, int y, int graphic, int frame)
1185 int sx = SCREENX(x), sy = SCREENY(y);
1187 int width, height, cx, cy, i;
1188 int snip = TILEX / 8; /* number of border pixels from "crumbled graphic" */
1189 static int xy[4][2] =
1197 if (!IN_LEV_FIELD(x, y))
1200 element = (GfxElement[x][y] != EL_UNDEFINED ? GfxElement[x][y] : Feld[x][y]);
1202 /* crumble field itself */
1203 if (CAN_BE_CRUMBLED(element) && !IS_MOVING(x, y))
1205 if (!IN_SCR_FIELD(sx, sy))
1208 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1212 int xx = x + xy[i][0];
1213 int yy = y + xy[i][1];
1215 element = (IN_LEV_FIELD(xx, yy) ? Feld[xx][yy] : EL_STEELWALL);
1217 /* check if neighbour field is of same type */
1218 if (CAN_BE_CRUMBLED(element) && !IS_MOVING(xx, yy))
1221 if (i == 1 || i == 2)
1225 cx = (i == 2 ? TILEX - snip : 0);
1233 cy = (i == 3 ? TILEY - snip : 0);
1236 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1237 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
1240 MarkTileDirty(sx, sy);
1242 else /* crumble neighbour fields */
1244 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1248 int xx = x + xy[i][0];
1249 int yy = y + xy[i][1];
1250 int sxx = sx + xy[i][0];
1251 int syy = sy + xy[i][1];
1253 if (!IN_LEV_FIELD(xx, yy) ||
1254 !IN_SCR_FIELD(sxx, syy) ||
1255 !CAN_BE_CRUMBLED(Feld[xx][yy]) ||
1259 if (i == 1 || i == 2)
1263 cx = (i == 1 ? TILEX - snip : 0);
1271 cy = (i==0 ? TILEY-snip : 0);
1274 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1275 width, height, FX + sxx * TILEX + cx, FY + syy * TILEY + cy);
1277 MarkTileDirty(sxx, syy);
1282 void DrawLevelFieldCrumbledSand(int x, int y)
1284 DrawLevelFieldCrumbledSandExt(x, y, IMG_SAND_CRUMBLED, 0);
1287 void DrawLevelFieldCrumbledSandDigging(int x, int y, int direction,
1290 int graphic1 = el_act_dir2img(EL_SAND, ACTION_DIGGING, direction);
1291 int graphic2 = el_act_dir2img(EL_SAND_CRUMBLED, ACTION_DIGGING, direction);
1292 int frame1 = getGraphicAnimationFrame(graphic1, step_frame);
1293 int frame2 = getGraphicAnimationFrame(graphic2, step_frame);
1294 int sx = SCREENX(x), sy = SCREENY(y);
1296 DrawGraphic(sx, sy, graphic1, frame1);
1297 DrawLevelFieldCrumbledSandExt(x, y, graphic2, frame2);
1300 static int getBorderElement(int x, int y)
1304 { EL_STEELWALL_TOPLEFT, EL_INVISIBLE_STEELWALL_TOPLEFT },
1305 { EL_STEELWALL_TOPRIGHT, EL_INVISIBLE_STEELWALL_TOPRIGHT },
1306 { EL_STEELWALL_BOTTOMLEFT, EL_INVISIBLE_STEELWALL_BOTTOMLEFT },
1307 { EL_STEELWALL_BOTTOMRIGHT, EL_INVISIBLE_STEELWALL_BOTTOMRIGHT },
1308 { EL_STEELWALL_VERTICAL, EL_INVISIBLE_STEELWALL_VERTICAL },
1309 { EL_STEELWALL_HORIZONTAL, EL_INVISIBLE_STEELWALL_HORIZONTAL },
1310 { EL_STEELWALL, EL_INVISIBLE_STEELWALL }
1312 int steel_type = (BorderElement == EL_STEELWALL ? 0 : 1);
1313 int steel_position = (x == -1 && y == -1 ? 0 :
1314 x == lev_fieldx && y == -1 ? 1 :
1315 x == -1 && y == lev_fieldy ? 2 :
1316 x == lev_fieldx && y == lev_fieldy ? 3 :
1317 x == -1 || x == lev_fieldx ? 4 :
1318 y == -1 || y == lev_fieldy ? 5 : 6);
1320 return border[steel_position][steel_type];
1323 void DrawScreenElement(int x, int y, int element)
1325 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
1326 DrawLevelFieldCrumbledSand(LEVELX(x), LEVELY(y));
1329 void DrawLevelElement(int x, int y, int element)
1331 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1332 DrawScreenElement(SCREENX(x), SCREENY(y), element);
1335 void DrawScreenField(int x, int y)
1337 int lx = LEVELX(x), ly = LEVELY(y);
1338 int element, content;
1340 if (!IN_LEV_FIELD(lx, ly))
1342 if (lx < -1 || lx > lev_fieldx || ly < -1 || ly > lev_fieldy)
1345 element = getBorderElement(lx, ly);
1347 DrawScreenElement(x, y, element);
1351 element = Feld[lx][ly];
1352 content = Store[lx][ly];
1354 if (IS_MOVING(lx, ly))
1356 int horiz_move = (MovDir[lx][ly] == MV_LEFT || MovDir[lx][ly] == MV_RIGHT);
1357 boolean cut_mode = NO_CUTTING;
1359 if (element == EL_QUICKSAND_EMPTYING ||
1360 element == EL_MAGIC_WALL_EMPTYING ||
1361 element == EL_BD_MAGIC_WALL_EMPTYING ||
1362 element == EL_AMOEBA_DROPPING)
1363 cut_mode = CUT_ABOVE;
1364 else if (element == EL_QUICKSAND_FILLING ||
1365 element == EL_MAGIC_WALL_FILLING ||
1366 element == EL_BD_MAGIC_WALL_FILLING)
1367 cut_mode = CUT_BELOW;
1369 if (cut_mode == CUT_ABOVE)
1370 DrawScreenElementShifted(x, y, 0, 0, element, NO_CUTTING);
1372 DrawScreenElement(x, y, EL_EMPTY);
1375 DrawScreenElementShifted(x, y, MovPos[lx][ly], 0, element, NO_CUTTING);
1376 else if (cut_mode == NO_CUTTING)
1377 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], element, cut_mode);
1379 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], content, cut_mode);
1381 if (content == EL_ACID)
1382 DrawLevelElementThruMask(lx, ly + 1, EL_ACID);
1384 else if (IS_BLOCKED(lx, ly))
1389 boolean cut_mode = NO_CUTTING;
1390 int element_old, content_old;
1392 Blocked2Moving(lx, ly, &oldx, &oldy);
1395 horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
1396 MovDir[oldx][oldy] == MV_RIGHT);
1398 element_old = Feld[oldx][oldy];
1399 content_old = Store[oldx][oldy];
1401 if (element_old == EL_QUICKSAND_EMPTYING ||
1402 element_old == EL_MAGIC_WALL_EMPTYING ||
1403 element_old == EL_BD_MAGIC_WALL_EMPTYING ||
1404 element_old == EL_AMOEBA_DROPPING)
1405 cut_mode = CUT_ABOVE;
1407 DrawScreenElement(x, y, EL_EMPTY);
1410 DrawScreenElementShifted(sx, sy, MovPos[oldx][oldy], 0, element_old,
1412 else if (cut_mode == NO_CUTTING)
1413 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], element_old,
1416 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], content_old,
1419 else if (IS_DRAWABLE(element))
1420 DrawScreenElement(x, y, element);
1422 DrawScreenElement(x, y, EL_EMPTY);
1425 void DrawLevelField(int x, int y)
1427 if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1428 DrawScreenField(SCREENX(x), SCREENY(y));
1429 else if (IS_MOVING(x, y))
1433 Moving2Blocked(x, y, &newx, &newy);
1434 if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
1435 DrawScreenField(SCREENX(newx), SCREENY(newy));
1437 else if (IS_BLOCKED(x, y))
1441 Blocked2Moving(x, y, &oldx, &oldy);
1442 if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
1443 DrawScreenField(SCREENX(oldx), SCREENY(oldy));
1447 void DrawMiniElement(int x, int y, int element)
1451 graphic = el2edimg(element);
1452 DrawMiniGraphic(x, y, graphic);
1455 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
1457 int x = sx + scroll_x, y = sy + scroll_y;
1459 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
1460 DrawMiniElement(sx, sy, EL_EMPTY);
1461 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
1462 DrawMiniElement(sx, sy, Feld[x][y]);
1464 DrawMiniGraphic(sx, sy, el2edimg(getBorderElement(x, y)));
1467 void getMicroGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
1469 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
1470 int mini_startx = src_bitmap->width * 3 / 4;
1471 int mini_starty = src_bitmap->height * 2 / 3;
1472 int src_x = mini_startx + graphic_info[graphic].src_x / 8;
1473 int src_y = mini_starty + graphic_info[graphic].src_y / 8;
1476 if (src_x + MICRO_TILEX > src_bitmap->width ||
1477 src_y + MICRO_TILEY > src_bitmap->height)
1479 /* graphic of desired size seems not to be contained in this image;
1480 dirty workaround: get it from the middle of the normal sized image */
1482 getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
1483 src_x += (TILEX / 2 - MICRO_TILEX / 2);
1484 src_y += (TILEY / 2 - MICRO_TILEY / 2);
1488 *bitmap = src_bitmap;
1493 void DrawMicroElement(int xpos, int ypos, int element)
1497 int graphic = el2preimg(element);
1499 getMicroGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
1500 BlitBitmap(src_bitmap, drawto, src_x, src_y, MICRO_TILEX, MICRO_TILEY,
1508 SetDrawBackgroundMask(REDRAW_NONE);
1511 for(x=BX1; x<=BX2; x++)
1512 for(y=BY1; y<=BY2; y++)
1513 DrawScreenField(x, y);
1515 redraw_mask |= REDRAW_FIELD;
1518 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
1522 for(x=0; x<size_x; x++)
1523 for(y=0; y<size_y; y++)
1524 DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
1526 redraw_mask |= REDRAW_FIELD;
1529 static void DrawMicroLevelExt(int xpos, int ypos, int from_x, int from_y)
1533 DrawBackground(xpos, ypos, MICROLEV_XSIZE, MICROLEV_YSIZE);
1535 if (lev_fieldx < STD_LEV_FIELDX)
1536 xpos += (STD_LEV_FIELDX - lev_fieldx) / 2 * MICRO_TILEX;
1537 if (lev_fieldy < STD_LEV_FIELDY)
1538 ypos += (STD_LEV_FIELDY - lev_fieldy) / 2 * MICRO_TILEY;
1540 xpos += MICRO_TILEX;
1541 ypos += MICRO_TILEY;
1543 for(x=-1; x<=STD_LEV_FIELDX; x++)
1545 for(y=-1; y<=STD_LEV_FIELDY; y++)
1547 int lx = from_x + x, ly = from_y + y;
1549 if (lx >= 0 && lx < lev_fieldx && ly >= 0 && ly < lev_fieldy)
1550 DrawMicroElement(xpos + x * MICRO_TILEX, ypos + y * MICRO_TILEY,
1552 else if (lx >= -1 && lx < lev_fieldx+1 && ly >= -1 && ly < lev_fieldy+1
1553 && BorderElement != EL_EMPTY)
1554 DrawMicroElement(xpos + x * MICRO_TILEX, ypos + y * MICRO_TILEY,
1555 getBorderElement(lx, ly));
1559 redraw_mask |= REDRAW_MICROLEVEL;
1562 #define MICROLABEL_EMPTY 0
1563 #define MICROLABEL_LEVEL_NAME 1
1564 #define MICROLABEL_CREATED_BY 2
1565 #define MICROLABEL_LEVEL_AUTHOR 3
1566 #define MICROLABEL_IMPORTED_FROM 4
1567 #define MICROLABEL_LEVEL_IMPORT_INFO 5
1569 static void DrawMicroLevelLabelExt(int mode)
1571 char label_text[MAX_OUTPUT_LINESIZE + 1];
1572 int max_len_label_text;
1573 int font_nr = FONT_TEXT_2;
1575 if (mode == MICROLABEL_CREATED_BY || mode == MICROLABEL_IMPORTED_FROM)
1576 font_nr = FONT_TEXT_3;
1578 max_len_label_text = SXSIZE / getFontWidth(font_nr);
1580 DrawBackground(SX, MICROLABEL_YPOS, SXSIZE, getFontHeight(font_nr));
1582 strncpy(label_text, (mode == MICROLABEL_LEVEL_NAME ? level.name :
1583 mode == MICROLABEL_CREATED_BY ? "created by" :
1584 mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
1585 mode == MICROLABEL_IMPORTED_FROM ? "imported from" :
1586 mode == MICROLABEL_LEVEL_IMPORT_INFO ?
1587 leveldir_current->imported_from : ""),
1588 max_len_label_text);
1589 label_text[max_len_label_text] = '\0';
1591 if (strlen(label_text) > 0)
1593 int text_width = strlen(label_text) * getFontWidth(font_nr);
1594 int lxpos = SX + (SXSIZE - text_width) / 2;
1595 int lypos = MICROLABEL_YPOS;
1597 DrawText(lxpos, lypos, label_text, font_nr);
1600 redraw_mask |= REDRAW_MICROLEVEL;
1603 void DrawMicroLevel(int xpos, int ypos, boolean restart)
1605 static unsigned long scroll_delay = 0;
1606 static unsigned long label_delay = 0;
1607 static int from_x, from_y, scroll_direction;
1608 static int label_state, label_counter;
1609 int last_game_status = game_status; /* save current game status */
1611 /* force PREVIEW font on preview level */
1612 game_status = GAME_MODE_PSEUDO_PREVIEW;
1616 from_x = from_y = 0;
1617 scroll_direction = MV_RIGHT;
1621 DrawMicroLevelExt(xpos, ypos, from_x, from_y);
1622 DrawMicroLevelLabelExt(label_state);
1624 /* initialize delay counters */
1625 DelayReached(&scroll_delay, 0);
1626 DelayReached(&label_delay, 0);
1628 if (leveldir_current->name)
1630 int len = strlen(leveldir_current->name);
1631 int lxpos = SX + (SXSIZE - len * getFontWidth(FONT_TEXT_1)) / 2;
1632 int lypos = SY + 352;
1634 DrawText(lxpos, lypos, leveldir_current->name, FONT_TEXT_1);
1637 game_status = last_game_status; /* restore current game status */
1642 /* scroll micro level, if needed */
1643 if ((lev_fieldx > STD_LEV_FIELDX || lev_fieldy > STD_LEV_FIELDY) &&
1644 DelayReached(&scroll_delay, MICROLEVEL_SCROLL_DELAY))
1646 switch (scroll_direction)
1652 scroll_direction = MV_UP;
1656 if (from_x < lev_fieldx - STD_LEV_FIELDX)
1659 scroll_direction = MV_DOWN;
1666 scroll_direction = MV_RIGHT;
1670 if (from_y < lev_fieldy - STD_LEV_FIELDY)
1673 scroll_direction = MV_LEFT;
1680 DrawMicroLevelExt(xpos, ypos, from_x, from_y);
1683 /* redraw micro level label, if needed */
1684 if (strcmp(level.name, NAMELESS_LEVEL_NAME) != 0 &&
1685 strcmp(level.author, ANONYMOUS_NAME) != 0 &&
1686 strcmp(level.author, leveldir_current->name) != 0 &&
1687 DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
1689 int max_label_counter = 23;
1691 if (leveldir_current->imported_from != NULL)
1692 max_label_counter += 14;
1694 label_counter = (label_counter + 1) % max_label_counter;
1695 label_state = (label_counter >= 0 && label_counter <= 7 ?
1696 MICROLABEL_LEVEL_NAME :
1697 label_counter >= 9 && label_counter <= 12 ?
1698 MICROLABEL_CREATED_BY :
1699 label_counter >= 14 && label_counter <= 21 ?
1700 MICROLABEL_LEVEL_AUTHOR :
1701 label_counter >= 23 && label_counter <= 26 ?
1702 MICROLABEL_IMPORTED_FROM :
1703 label_counter >= 28 && label_counter <= 35 ?
1704 MICROLABEL_LEVEL_IMPORT_INFO : MICROLABEL_EMPTY);
1705 DrawMicroLevelLabelExt(label_state);
1708 game_status = last_game_status; /* restore current game status */
1711 int REQ_in_range(int x, int y)
1713 if (y > DY+249 && y < DY+278)
1715 if (x > DX+1 && x < DX+48)
1717 else if (x > DX+51 && x < DX+98)
1723 #define MAX_REQUEST_LINES 13
1724 #define MAX_REQUEST_LINE_LEN 7
1726 boolean Request(char *text, unsigned int req_state)
1728 int mx, my, ty, result = -1;
1729 unsigned int old_door_state;
1730 int last_game_status = game_status; /* save current game status */
1732 #if defined(PLATFORM_UNIX)
1733 /* pause network game while waiting for request to answer */
1734 if (options.network &&
1735 game_status == GAME_MODE_PLAYING &&
1736 req_state & REQUEST_WAIT_FOR)
1737 SendToServer_PausePlaying();
1740 old_door_state = GetDoorState();
1744 CloseDoor(DOOR_CLOSE_1);
1746 /* save old door content */
1747 BlitBitmap(bitmap_db_door, bitmap_db_door,
1748 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
1749 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
1751 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
1753 /* clear door drawing field */
1754 DrawBackground(DX, DY, DXSIZE, DYSIZE);
1756 /* force DOOR font on preview level */
1757 game_status = GAME_MODE_PSEUDO_DOOR;
1759 /* write text for request */
1760 for(ty=0; ty < MAX_REQUEST_LINES; ty++)
1762 char text_line[MAX_REQUEST_LINE_LEN + 1];
1768 for(tl=0,tx=0; tx < MAX_REQUEST_LINE_LEN; tl++,tx++)
1771 if (!tc || tc == ' ')
1782 strncpy(text_line, text, tl);
1785 DrawText(DX + (DXSIZE - tl * getFontWidth(FONT_TEXT_2)) / 2,
1786 DY + 8 + ty * (getFontHeight(FONT_TEXT_2) + 2),
1787 text_line, FONT_TEXT_2);
1789 text += tl + (tc == ' ' ? 1 : 0);
1792 game_status = last_game_status; /* restore current game status */
1794 if (req_state & REQ_ASK)
1796 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
1797 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
1799 else if (req_state & REQ_CONFIRM)
1801 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
1803 else if (req_state & REQ_PLAYER)
1805 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
1806 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
1807 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
1808 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
1811 /* copy request gadgets to door backbuffer */
1812 BlitBitmap(drawto, bitmap_db_door,
1813 DX, DY, DXSIZE, DYSIZE,
1814 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
1816 OpenDoor(DOOR_OPEN_1);
1822 if (!(req_state & REQUEST_WAIT_FOR))
1824 SetDrawBackgroundMask(REDRAW_FIELD);
1829 if (game_status != GAME_MODE_MAIN)
1832 button_status = MB_RELEASED;
1834 request_gadget_id = -1;
1836 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
1848 case EVENT_BUTTONPRESS:
1849 case EVENT_BUTTONRELEASE:
1850 case EVENT_MOTIONNOTIFY:
1852 if (event.type == EVENT_MOTIONNOTIFY)
1854 if (!PointerInWindow(window))
1855 continue; /* window and pointer are on different screens */
1860 motion_status = TRUE;
1861 mx = ((MotionEvent *) &event)->x;
1862 my = ((MotionEvent *) &event)->y;
1866 motion_status = FALSE;
1867 mx = ((ButtonEvent *) &event)->x;
1868 my = ((ButtonEvent *) &event)->y;
1869 if (event.type == EVENT_BUTTONPRESS)
1870 button_status = ((ButtonEvent *) &event)->button;
1872 button_status = MB_RELEASED;
1875 /* this sets 'request_gadget_id' */
1876 HandleGadgets(mx, my, button_status);
1878 switch(request_gadget_id)
1880 case TOOL_CTRL_ID_YES:
1883 case TOOL_CTRL_ID_NO:
1886 case TOOL_CTRL_ID_CONFIRM:
1887 result = TRUE | FALSE;
1890 case TOOL_CTRL_ID_PLAYER_1:
1893 case TOOL_CTRL_ID_PLAYER_2:
1896 case TOOL_CTRL_ID_PLAYER_3:
1899 case TOOL_CTRL_ID_PLAYER_4:
1910 case EVENT_KEYPRESS:
1911 switch(GetEventKey((KeyEvent *)&event, TRUE))
1924 if (req_state & REQ_PLAYER)
1928 case EVENT_KEYRELEASE:
1929 ClearPlayerAction();
1933 HandleOtherEvents(&event);
1937 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
1939 int joy = AnyJoystick();
1941 if (joy & JOY_BUTTON_1)
1943 else if (joy & JOY_BUTTON_2)
1949 /* don't eat all CPU time */
1953 if (game_status != GAME_MODE_MAIN)
1958 if (!(req_state & REQ_STAY_OPEN))
1960 CloseDoor(DOOR_CLOSE_1);
1962 if (!(req_state & REQ_STAY_CLOSED) && (old_door_state & DOOR_OPEN_1))
1964 BlitBitmap(bitmap_db_door, bitmap_db_door,
1965 DOOR_GFX_PAGEX2,DOOR_GFX_PAGEY1, DXSIZE,DYSIZE,
1966 DOOR_GFX_PAGEX1,DOOR_GFX_PAGEY1);
1967 OpenDoor(DOOR_OPEN_1);
1973 SetDrawBackgroundMask(REDRAW_FIELD);
1975 #if defined(PLATFORM_UNIX)
1976 /* continue network game after request */
1977 if (options.network &&
1978 game_status == GAME_MODE_PLAYING &&
1979 req_state & REQUEST_WAIT_FOR)
1980 SendToServer_ContinuePlaying();
1986 unsigned int OpenDoor(unsigned int door_state)
1988 unsigned int new_door_state;
1990 if (door_state & DOOR_COPY_BACK)
1992 BlitBitmap(bitmap_db_door, bitmap_db_door,
1993 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE + VYSIZE,
1994 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
1995 door_state &= ~DOOR_COPY_BACK;
1998 new_door_state = MoveDoor(door_state);
2000 return(new_door_state);
2003 unsigned int CloseDoor(unsigned int door_state)
2005 unsigned int new_door_state;
2007 BlitBitmap(backbuffer, bitmap_db_door,
2008 DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2009 BlitBitmap(backbuffer, bitmap_db_door,
2010 VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
2012 new_door_state = MoveDoor(door_state);
2014 return(new_door_state);
2017 unsigned int GetDoorState()
2019 return MoveDoor(DOOR_GET_STATE);
2022 unsigned int SetDoorState(unsigned int door_state)
2024 return MoveDoor(door_state | DOOR_SET_STATE);
2027 unsigned int MoveDoor(unsigned int door_state)
2029 static int door1 = DOOR_OPEN_1;
2030 static int door2 = DOOR_CLOSE_2;
2031 static unsigned long door_delay = 0;
2032 int x, start, stepsize = door.step_offset;
2033 unsigned long door_delay_value = door.step_delay;
2035 if (door_state == DOOR_GET_STATE)
2036 return(door1 | door2);
2038 if (door_state & DOOR_SET_STATE)
2040 if (door_state & DOOR_ACTION_1)
2041 door1 = door_state & DOOR_ACTION_1;
2042 if (door_state & DOOR_ACTION_2)
2043 door2 = door_state & DOOR_ACTION_2;
2045 return(door1 | door2);
2048 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
2049 door_state &= ~DOOR_OPEN_1;
2050 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
2051 door_state &= ~DOOR_CLOSE_1;
2052 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
2053 door_state &= ~DOOR_OPEN_2;
2054 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
2055 door_state &= ~DOOR_CLOSE_2;
2057 if (setup.quick_doors)
2060 door_delay_value = 0;
2062 StopSound(SND_DOOR_OPENING);
2063 StopSound(SND_DOOR_CLOSING);
2066 if (global.autoplay_leveldir)
2068 door_state |= DOOR_NO_DELAY;
2069 door_state &= ~DOOR_CLOSE_ALL;
2072 if (door_state & DOOR_ACTION)
2074 if (!(door_state & DOOR_NO_DELAY))
2076 /* opening door sound has priority over simultaneously closing door */
2077 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
2078 PlaySoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
2079 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
2080 PlaySoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
2083 start = ((door_state & DOOR_NO_DELAY) ? DXSIZE : 0);
2085 for(x=start; x<=DXSIZE; x+=stepsize)
2087 Bitmap *bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
2088 GC gc = bitmap->stored_clip_gc;
2090 if (!(door_state & DOOR_NO_DELAY))
2091 WaitUntilDelayReached(&door_delay, door_delay_value);
2093 if (door_state & DOOR_ACTION_1)
2095 int i = (door_state & DOOR_OPEN_1 ? DXSIZE-x : x);
2096 int j = (DXSIZE - i) / 3;
2098 BlitBitmap(bitmap_db_door, drawto,
2099 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + i/2,
2100 DXSIZE,DYSIZE - i/2, DX, DY);
2102 ClearRectangle(drawto, DX, DY + DYSIZE - i/2, DXSIZE,i/2);
2104 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2105 BlitBitmapMasked(bitmap, drawto,
2106 DXSIZE, DOOR_GFX_PAGEY1, i, 77,
2107 DX + DXSIZE - i, DY + j);
2108 BlitBitmapMasked(bitmap, drawto,
2109 DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63,
2110 DX + DXSIZE - i, DY + 140 + j);
2111 SetClipOrigin(bitmap, gc, DX - DXSIZE + i, DY - (DOOR_GFX_PAGEY1 + j));
2112 BlitBitmapMasked(bitmap, drawto,
2113 DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j,
2115 BlitBitmapMasked(bitmap, drawto,
2116 DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63,
2119 BlitBitmapMasked(bitmap, drawto,
2120 DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
2122 BlitBitmapMasked(bitmap, drawto,
2123 DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
2125 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2126 BlitBitmapMasked(bitmap, drawto,
2127 DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
2128 DX + DXSIZE - i, DY + 77 + j);
2129 BlitBitmapMasked(bitmap, drawto,
2130 DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
2131 DX + DXSIZE - i, DY + 203 + j);
2133 redraw_mask |= REDRAW_DOOR_1;
2136 if (door_state & DOOR_ACTION_2)
2138 int i = (door_state & DOOR_OPEN_2 ? VXSIZE - x : x);
2139 int j = (VXSIZE - i) / 3;
2141 BlitBitmap(bitmap_db_door, drawto,
2142 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + i/2,
2143 VXSIZE, VYSIZE - i/2, VX, VY);
2145 ClearRectangle(drawto, VX, VY + VYSIZE-i/2, VXSIZE, i/2);
2147 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2148 BlitBitmapMasked(bitmap, drawto,
2149 VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2,
2150 VX + VXSIZE-i, VY+j);
2151 SetClipOrigin(bitmap, gc,
2152 VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
2153 BlitBitmapMasked(bitmap, drawto,
2154 VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j,
2157 BlitBitmapMasked(bitmap, drawto,
2158 VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2,
2159 i, VYSIZE / 2, VX, VY + VYSIZE / 2 - j);
2160 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2161 BlitBitmapMasked(bitmap, drawto,
2162 VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2,
2164 VX + VXSIZE - i, VY + VYSIZE / 2 + j);
2166 redraw_mask |= REDRAW_DOOR_2;
2171 if (game_status == GAME_MODE_MAIN)
2176 if (setup.quick_doors)
2178 StopSound(SND_DOOR_OPENING);
2179 StopSound(SND_DOOR_CLOSING);
2182 if (door_state & DOOR_ACTION_1)
2183 door1 = door_state & DOOR_ACTION_1;
2184 if (door_state & DOOR_ACTION_2)
2185 door2 = door_state & DOOR_ACTION_2;
2187 return (door1 | door2);
2190 void DrawSpecialEditorDoor()
2192 /* draw bigger toolbox window */
2193 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
2194 DOOR_GFX_PAGEX7, 0, EXSIZE + 8, 8,
2196 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
2197 EX - 4, VY - 4, EXSIZE + 8, EYSIZE - VYSIZE + 4,
2200 redraw_mask |= REDRAW_ALL;
2203 void UndrawSpecialEditorDoor()
2205 /* draw normal tape recorder window */
2206 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
2207 EX - 4, EY - 12, EXSIZE + 8, EYSIZE - VYSIZE + 12,
2210 redraw_mask |= REDRAW_ALL;
2214 /* ---------- new tool button stuff ---------------------------------------- */
2216 /* graphic position values for tool buttons */
2217 #define TOOL_BUTTON_YES_XPOS 2
2218 #define TOOL_BUTTON_YES_YPOS 250
2219 #define TOOL_BUTTON_YES_GFX_YPOS 0
2220 #define TOOL_BUTTON_YES_XSIZE 46
2221 #define TOOL_BUTTON_YES_YSIZE 28
2222 #define TOOL_BUTTON_NO_XPOS 52
2223 #define TOOL_BUTTON_NO_YPOS TOOL_BUTTON_YES_YPOS
2224 #define TOOL_BUTTON_NO_GFX_YPOS TOOL_BUTTON_YES_GFX_YPOS
2225 #define TOOL_BUTTON_NO_XSIZE TOOL_BUTTON_YES_XSIZE
2226 #define TOOL_BUTTON_NO_YSIZE TOOL_BUTTON_YES_YSIZE
2227 #define TOOL_BUTTON_CONFIRM_XPOS TOOL_BUTTON_YES_XPOS
2228 #define TOOL_BUTTON_CONFIRM_YPOS TOOL_BUTTON_YES_YPOS
2229 #define TOOL_BUTTON_CONFIRM_GFX_YPOS 30
2230 #define TOOL_BUTTON_CONFIRM_XSIZE 96
2231 #define TOOL_BUTTON_CONFIRM_YSIZE TOOL_BUTTON_YES_YSIZE
2232 #define TOOL_BUTTON_PLAYER_XSIZE 30
2233 #define TOOL_BUTTON_PLAYER_YSIZE 30
2234 #define TOOL_BUTTON_PLAYER_GFX_XPOS 5
2235 #define TOOL_BUTTON_PLAYER_GFX_YPOS 185
2236 #define TOOL_BUTTON_PLAYER_XPOS (5 + TOOL_BUTTON_PLAYER_XSIZE / 2)
2237 #define TOOL_BUTTON_PLAYER_YPOS (215 - TOOL_BUTTON_PLAYER_YSIZE / 2)
2238 #define TOOL_BUTTON_PLAYER1_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2239 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2240 #define TOOL_BUTTON_PLAYER2_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2241 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2242 #define TOOL_BUTTON_PLAYER3_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2243 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2244 #define TOOL_BUTTON_PLAYER4_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2245 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2246 #define TOOL_BUTTON_PLAYER1_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2247 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2248 #define TOOL_BUTTON_PLAYER2_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2249 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2250 #define TOOL_BUTTON_PLAYER3_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2251 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2252 #define TOOL_BUTTON_PLAYER4_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2253 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2262 } toolbutton_info[NUM_TOOL_BUTTONS] =
2265 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_GFX_YPOS,
2266 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_YPOS,
2267 TOOL_BUTTON_YES_XSIZE, TOOL_BUTTON_YES_YSIZE,
2272 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_GFX_YPOS,
2273 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_YPOS,
2274 TOOL_BUTTON_NO_XSIZE, TOOL_BUTTON_NO_YSIZE,
2279 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_GFX_YPOS,
2280 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_YPOS,
2281 TOOL_BUTTON_CONFIRM_XSIZE, TOOL_BUTTON_CONFIRM_YSIZE,
2282 TOOL_CTRL_ID_CONFIRM,
2286 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2287 TOOL_BUTTON_PLAYER1_XPOS, TOOL_BUTTON_PLAYER1_YPOS,
2288 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2289 TOOL_CTRL_ID_PLAYER_1,
2293 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2294 TOOL_BUTTON_PLAYER2_XPOS, TOOL_BUTTON_PLAYER2_YPOS,
2295 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2296 TOOL_CTRL_ID_PLAYER_2,
2300 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2301 TOOL_BUTTON_PLAYER3_XPOS, TOOL_BUTTON_PLAYER3_YPOS,
2302 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2303 TOOL_CTRL_ID_PLAYER_3,
2307 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2308 TOOL_BUTTON_PLAYER4_XPOS, TOOL_BUTTON_PLAYER4_YPOS,
2309 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2310 TOOL_CTRL_ID_PLAYER_4,
2315 void CreateToolButtons()
2319 for (i=0; i<NUM_TOOL_BUTTONS; i++)
2321 Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
2322 Bitmap *deco_bitmap = None;
2323 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
2324 struct GadgetInfo *gi;
2325 unsigned long event_mask;
2326 int gd_xoffset, gd_yoffset;
2327 int gd_x1, gd_x2, gd_y;
2330 event_mask = GD_EVENT_RELEASED;
2332 gd_xoffset = toolbutton_info[i].xpos;
2333 gd_yoffset = toolbutton_info[i].ypos;
2334 gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
2335 gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
2336 gd_y = DOOR_GFX_PAGEY1 + gd_yoffset;
2338 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
2340 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
2342 getMiniGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr),
2343 &deco_bitmap, &deco_x, &deco_y);
2344 deco_xpos = (toolbutton_info[i].width - MINI_TILEX) / 2;
2345 deco_ypos = (toolbutton_info[i].height - MINI_TILEY) / 2;
2348 gi = CreateGadget(GDI_CUSTOM_ID, id,
2349 GDI_INFO_TEXT, toolbutton_info[i].infotext,
2350 GDI_X, DX + toolbutton_info[i].x,
2351 GDI_Y, DY + toolbutton_info[i].y,
2352 GDI_WIDTH, toolbutton_info[i].width,
2353 GDI_HEIGHT, toolbutton_info[i].height,
2354 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
2355 GDI_STATE, GD_BUTTON_UNPRESSED,
2356 GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
2357 GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
2358 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
2359 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
2360 GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
2361 GDI_DECORATION_SHIFTING, 1, 1,
2362 GDI_EVENT_MASK, event_mask,
2363 GDI_CALLBACK_ACTION, HandleToolButtons,
2367 Error(ERR_EXIT, "cannot create gadget");
2369 tool_gadget[id] = gi;
2373 void FreeToolButtons()
2377 for (i=0; i<NUM_TOOL_BUTTONS; i++)
2378 FreeGadget(tool_gadget[i]);
2381 static void UnmapToolButtons()
2385 for (i=0; i<NUM_TOOL_BUTTONS; i++)
2386 UnmapGadget(tool_gadget[i]);
2389 static void HandleToolButtons(struct GadgetInfo *gi)
2391 request_gadget_id = gi->custom_id;
2394 int get_next_element(int element)
2398 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
2399 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
2400 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
2401 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
2402 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
2403 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
2404 case EL_AMOEBA_DROPPING: return EL_AMOEBA_WET;
2406 default: return element;
2410 int el_act_dir2img(int element, int action, int direction)
2412 element = GFX_ELEMENT(element);
2413 direction = MV_DIR_BIT(direction);
2415 return element_info[element].direction_graphic[action][direction];
2418 int el_act2img(int element, int action)
2420 element = GFX_ELEMENT(element);
2422 return element_info[element].graphic[action];
2425 int el_dir2img(int element, int direction)
2427 element = GFX_ELEMENT(element);
2429 return el_act_dir2img(element, ACTION_DEFAULT, direction);
2432 int el2img(int element)
2434 element = GFX_ELEMENT(element);
2436 return element_info[element].graphic[ACTION_DEFAULT];
2439 int el2edimg(int element)
2441 element = GFX_ELEMENT(element);
2443 return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
2446 int el2preimg(int element)
2448 element = GFX_ELEMENT(element);
2450 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];