1 /***********************************************************
2 * Rocks'n'Diamonds -- McDuffin Strikes Back! *
3 *----------------------------------------------------------*
4 * (c) 1995-2002 Artsoft Entertainment *
6 * Detmolder Strasse 189 *
9 * e-mail: info@artsoft.org *
10 *----------------------------------------------------------*
12 ***********************************************************/
14 #include "libgame/libgame.h"
23 /* tool button identifiers */
24 #define TOOL_CTRL_ID_YES 0
25 #define TOOL_CTRL_ID_NO 1
26 #define TOOL_CTRL_ID_CONFIRM 2
27 #define TOOL_CTRL_ID_PLAYER_1 3
28 #define TOOL_CTRL_ID_PLAYER_2 4
29 #define TOOL_CTRL_ID_PLAYER_3 5
30 #define TOOL_CTRL_ID_PLAYER_4 6
32 #define NUM_TOOL_BUTTONS 7
34 /* forward declaration for internal use */
35 static void UnmapToolButtons();
36 static void HandleToolButtons(struct GadgetInfo *);
38 static struct GadgetInfo *tool_gadget[NUM_TOOL_BUTTONS];
39 static int request_gadget_id = -1;
41 void SetDrawtoField(int mode)
43 if (mode == DRAW_BUFFERED && setup.soft_scrolling)
54 drawto_field = fieldbuffer;
56 else /* DRAW_DIRECT, DRAW_BACKBUFFER */
67 drawto_field = (mode == DRAW_DIRECT ? window : backbuffer);
71 void RedrawPlayfield(boolean force_redraw, int x, int y, int width, int height)
73 if (game_status == GAME_MODE_PLAYING)
79 width = gfx.sxsize + 2 * TILEX;
80 height = gfx.sysize + 2 * TILEY;
83 if (force_redraw || setup.direct_draw)
86 int x1 = (x - SX) / TILEX, y1 = (y - SY) / TILEY;
87 int x2 = (x - SX + width) / TILEX, y2 = (y - SY + height) / TILEY;
89 if (setup.direct_draw)
90 SetDrawtoField(DRAW_BACKBUFFER);
92 for(xx=BX1; xx<=BX2; xx++)
93 for(yy=BY1; yy<=BY2; yy++)
94 if (xx >= x1 && xx <= x2 && yy >= y1 && yy <= y2)
95 DrawScreenField(xx, yy);
98 if (setup.direct_draw)
99 SetDrawtoField(DRAW_DIRECT);
102 if (setup.soft_scrolling)
104 int fx = FX, fy = FY;
106 fx += (ScreenMovDir & (MV_LEFT|MV_RIGHT) ? ScreenGfxPos : 0);
107 fy += (ScreenMovDir & (MV_UP|MV_DOWN) ? ScreenGfxPos : 0);
109 BlitBitmap(fieldbuffer, backbuffer, fx,fy, SXSIZE,SYSIZE, SX,SY);
113 BlitBitmap(drawto, window, x, y, width, height, x, y);
119 DrawBuffer *buffer = (drawto_field == window ? backbuffer : drawto_field);
121 if (setup.direct_draw && game_status == GAME_MODE_PLAYING)
122 redraw_mask &= ~REDRAW_MAIN;
124 if (redraw_mask & REDRAW_TILES && redraw_tiles > REDRAWTILES_THRESHOLD)
125 redraw_mask |= REDRAW_FIELD;
127 if (redraw_mask & REDRAW_FIELD)
128 redraw_mask &= ~REDRAW_TILES;
130 if (redraw_mask == REDRAW_NONE)
133 if (global.fps_slowdown && game_status == GAME_MODE_PLAYING)
135 static boolean last_frame_skipped = FALSE;
136 boolean skip_even_when_not_scrolling = TRUE;
137 boolean just_scrolling = (ScreenMovDir != 0);
138 boolean verbose = FALSE;
140 if (global.fps_slowdown_factor > 1 &&
141 (FrameCounter % global.fps_slowdown_factor) &&
142 (just_scrolling || skip_even_when_not_scrolling))
144 redraw_mask &= ~REDRAW_MAIN;
146 last_frame_skipped = TRUE;
149 printf("FRAME SKIPPED\n");
153 if (last_frame_skipped)
154 redraw_mask |= REDRAW_FIELD;
156 last_frame_skipped = FALSE;
159 printf("frame not skipped\n");
163 /* synchronize X11 graphics at this point; if we would synchronize the
164 display immediately after the buffer switching (after the XFlush),
165 this could mean that we have to wait for the graphics to complete,
166 although we could go on doing calculations for the next frame */
170 if (redraw_mask & REDRAW_ALL)
172 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
176 if (redraw_mask & REDRAW_FIELD)
178 if (game_status != GAME_MODE_PLAYING ||
179 redraw_mask & REDRAW_FROM_BACKBUFFER)
181 BlitBitmap(backbuffer, window,
182 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE, REAL_SX, REAL_SY);
186 int fx = FX, fy = FY;
188 if (setup.soft_scrolling)
190 fx += (ScreenMovDir & (MV_LEFT | MV_RIGHT) ? ScreenGfxPos : 0);
191 fy += (ScreenMovDir & (MV_UP | MV_DOWN) ? ScreenGfxPos : 0);
194 if (setup.soft_scrolling ||
195 ABS(ScreenMovPos) + ScrollStepSize == TILEX ||
196 ABS(ScreenMovPos) == ScrollStepSize ||
197 redraw_tiles > REDRAWTILES_THRESHOLD)
199 BlitBitmap(buffer, window, fx, fy, SXSIZE, SYSIZE, SX, SY);
203 printf("redrawing all (ScreenGfxPos == %d) because %s\n",
205 (setup.soft_scrolling ?
206 "setup.soft_scrolling" :
207 ABS(ScreenGfxPos) + ScrollStepSize == TILEX ?
208 "ABS(ScreenGfxPos) + ScrollStepSize == TILEX" :
209 ABS(ScreenGfxPos) == ScrollStepSize ?
210 "ABS(ScreenGfxPos) == ScrollStepSize" :
211 "redraw_tiles > REDRAWTILES_THRESHOLD"));
217 redraw_mask &= ~REDRAW_MAIN;
220 if (redraw_mask & REDRAW_DOORS)
222 if (redraw_mask & REDRAW_DOOR_1)
223 BlitBitmap(backbuffer, window, DX, DY, DXSIZE, DYSIZE, DX, DY);
224 if (redraw_mask & REDRAW_DOOR_2)
226 if ((redraw_mask & REDRAW_DOOR_2) == REDRAW_DOOR_2)
227 BlitBitmap(backbuffer, window, VX,VY, VXSIZE,VYSIZE, VX,VY);
230 if (redraw_mask & REDRAW_VIDEO_1)
231 BlitBitmap(backbuffer, window,
232 VX+VIDEO_DISPLAY1_XPOS,VY+VIDEO_DISPLAY1_YPOS,
233 VIDEO_DISPLAY_XSIZE,VIDEO_DISPLAY_YSIZE,
234 VX+VIDEO_DISPLAY1_XPOS,VY+VIDEO_DISPLAY1_YPOS);
235 if (redraw_mask & REDRAW_VIDEO_2)
236 BlitBitmap(backbuffer, window,
237 VX+VIDEO_DISPLAY2_XPOS,VY+VIDEO_DISPLAY2_YPOS,
238 VIDEO_DISPLAY_XSIZE,VIDEO_DISPLAY_YSIZE,
239 VX+VIDEO_DISPLAY2_XPOS,VY+VIDEO_DISPLAY2_YPOS);
240 if (redraw_mask & REDRAW_VIDEO_3)
241 BlitBitmap(backbuffer, window,
242 VX+VIDEO_CONTROL_XPOS,VY+VIDEO_CONTROL_YPOS,
243 VIDEO_CONTROL_XSIZE,VIDEO_CONTROL_YSIZE,
244 VX+VIDEO_CONTROL_XPOS,VY+VIDEO_CONTROL_YPOS);
248 if (redraw_mask & REDRAW_DOOR_3)
249 BlitBitmap(backbuffer, window, EX, EY, EXSIZE, EYSIZE, EX, EY);
251 redraw_mask &= ~REDRAW_DOORS;
254 if (redraw_mask & REDRAW_MICROLEVEL)
256 BlitBitmap(backbuffer, window, SX, SY + 10 * TILEY, SXSIZE, 7 * TILEY,
257 SX, SY + 10 * TILEY);
259 redraw_mask &= ~REDRAW_MICROLEVEL;
262 if (redraw_mask & REDRAW_TILES)
264 for(x=0; x<SCR_FIELDX; x++)
265 for(y=0; y<SCR_FIELDY; y++)
266 if (redraw[redraw_x1 + x][redraw_y1 + y])
267 BlitBitmap(buffer, window,
268 FX + x * TILEX, FX + y * TILEY, TILEX, TILEY,
269 SX + x * TILEX, SY + y * TILEY);
272 if (redraw_mask & REDRAW_FPS) /* display frames per second */
277 sprintf(info1, " (only every %d. frame)", global.fps_slowdown_factor);
278 if (!global.fps_slowdown)
281 sprintf(text, "%.1f fps%s", global.frames_per_second, info1);
282 DrawTextExt(window, SX, SY, text, FONT_TEXT_2, BLIT_OPAQUE);
287 for(x=0; x<MAX_BUF_XSIZE; x++)
288 for(y=0; y<MAX_BUF_YSIZE; y++)
291 redraw_mask = REDRAW_NONE;
297 long fading_delay = 300;
299 if (setup.fading && (redraw_mask & REDRAW_FIELD))
306 ClearRectangle(window, REAL_SX,REAL_SY,FULL_SXSIZE,FULL_SYSIZE);
309 for(i=0;i<2*FULL_SYSIZE;i++)
311 for(y=0;y<FULL_SYSIZE;y++)
313 BlitBitmap(backbuffer, window,
314 REAL_SX,REAL_SY+i, FULL_SXSIZE,1, REAL_SX,REAL_SY+i);
322 for(i=1;i<FULL_SYSIZE;i+=2)
323 BlitBitmap(backbuffer, window,
324 REAL_SX,REAL_SY+i, FULL_SXSIZE,1, REAL_SX,REAL_SY+i);
330 SetClipOrigin(clip_gc[PIX_FADEMASK], 0, 0);
331 BlitBitmapMasked(backbuffer, window,
332 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
337 SetClipOrigin(clip_gc[PIX_FADEMASK], -1, -1);
338 BlitBitmapMasked(backbuffer, window,
339 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
344 SetClipOrigin(clip_gc[PIX_FADEMASK], 0, -1);
345 BlitBitmapMasked(backbuffer, window,
346 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
351 SetClipOrigin(clip_gc[PIX_FADEMASK], -1, 0);
352 BlitBitmapMasked(backbuffer, window,
353 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
358 redraw_mask &= ~REDRAW_MAIN;
365 void SetMainBackgroundImage(int graphic)
367 SetMainBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
368 graphic_info[graphic].bitmap ?
369 graphic_info[graphic].bitmap :
370 graphic_info[IMG_BACKGROUND].bitmap);
373 void SetDoorBackgroundImage(int graphic)
375 SetDoorBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
376 graphic_info[graphic].bitmap ?
377 graphic_info[graphic].bitmap :
378 graphic_info[IMG_BACKGROUND].bitmap);
381 void DrawBackground(int dest_x, int dest_y, int width, int height)
383 ClearRectangleOnBackground(backbuffer, dest_x, dest_y, width, height);
385 redraw_mask |= REDRAW_FIELD;
390 DrawBackground(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
392 if (setup.soft_scrolling && game_status == GAME_MODE_PLAYING)
394 ClearRectangle(fieldbuffer, 0, 0, FXSIZE, FYSIZE);
395 SetDrawtoField(DRAW_BUFFERED);
398 SetDrawtoField(DRAW_BACKBUFFER);
400 if (setup.direct_draw && game_status == GAME_MODE_PLAYING)
402 ClearRectangle(window, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
403 SetDrawtoField(DRAW_DIRECT);
407 void MarkTileDirty(int x, int y)
409 int xx = redraw_x1 + x;
410 int yy = redraw_y1 + y;
415 redraw[xx][yy] = TRUE;
416 redraw_mask |= REDRAW_TILES;
419 void SetBorderElement()
423 BorderElement = EL_EMPTY;
425 for(y=0; y<lev_fieldy && BorderElement == EL_EMPTY; y++)
427 for(x=0; x<lev_fieldx; x++)
429 if (!IS_INDESTRUCTIBLE(Feld[x][y]))
430 BorderElement = EL_STEELWALL;
432 if (y != 0 && y != lev_fieldy - 1 && x != lev_fieldx - 1)
438 void SetRandomAnimationValue(int x, int y)
440 gfx.anim_random_frame = GfxRandom[x][y];
443 inline int getGraphicAnimationFrame(int graphic, int sync_frame)
445 /* animation synchronized with global frame counter, not move position */
446 if (graphic_info[graphic].anim_global_sync || sync_frame < 0)
447 sync_frame = FrameCounter;
449 return getAnimationFrame(graphic_info[graphic].anim_frames,
450 graphic_info[graphic].anim_delay,
451 graphic_info[graphic].anim_mode,
452 graphic_info[graphic].anim_start_frame,
456 inline void DrawGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
457 int graphic, int sync_frame, int mask_mode)
459 int frame = getGraphicAnimationFrame(graphic, sync_frame);
461 if (mask_mode == USE_MASKING)
462 DrawGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
464 DrawGraphicExt(dst_bitmap, x, y, graphic, frame);
467 inline void DrawGraphicAnimation(int x, int y, int graphic)
469 int lx = LEVELX(x), ly = LEVELY(y);
471 if (!IN_SCR_FIELD(x, y))
474 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
475 graphic, GfxFrame[lx][ly], NO_MASKING);
479 void DrawLevelGraphicAnimation(int x, int y, int graphic)
481 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
484 void DrawLevelElementAnimation(int x, int y, int element)
487 int graphic = el_act_dir2img(element, GfxAction[x][y], MovDir[x][y]);
489 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
491 DrawGraphicAnimation(SCREENX(x), SCREENY(y), el2img(element));
495 inline void DrawLevelGraphicAnimationIfNeeded(int x, int y, int graphic)
497 int sx = SCREENX(x), sy = SCREENY(y);
499 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
502 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
505 DrawGraphicAnimation(sx, sy, graphic);
508 void DrawLevelElementAnimationIfNeeded(int x, int y, int element)
510 int sx = SCREENX(x), sy = SCREENY(y);
513 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
516 graphic = el_act_dir2img(element, GfxAction[x][y], MovDir[x][y]);
518 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
521 DrawGraphicAnimation(sx, sy, graphic);
524 void DrawAllPlayers()
528 for(i=0; i<MAX_PLAYERS; i++)
529 if (stored_player[i].active)
530 DrawPlayer(&stored_player[i]);
533 void DrawPlayerField(int x, int y)
535 if (!IS_PLAYER(x, y))
538 DrawPlayer(PLAYERINFO(x, y));
541 void DrawPlayer(struct PlayerInfo *player)
543 int jx = player->jx, jy = player->jy;
544 int last_jx = player->last_jx, last_jy = player->last_jy;
545 int next_jx = jx + (jx - last_jx), next_jy = jy + (jy - last_jy);
546 int sx = SCREENX(jx), sy = SCREENY(jy);
547 int sxx = 0, syy = 0;
548 int element = Feld[jx][jy], last_element = Feld[last_jx][last_jy];
551 boolean player_is_moving = (last_jx != jx || last_jy != jy ? TRUE : FALSE);
552 int move_dir = player->MovDir;
553 int action = ACTION_DEFAULT;
555 if (!player->active || !IN_SCR_FIELD(SCREENX(last_jx), SCREENY(last_jy)))
559 if (!IN_LEV_FIELD(jx,jy))
561 printf("DrawPlayerField(): x = %d, y = %d\n",jx,jy);
562 printf("DrawPlayerField(): sx = %d, sy = %d\n",sx,sy);
563 printf("DrawPlayerField(): This should never happen!\n");
568 if (element == EL_EXPLOSION)
571 action = (player->Pushing ? ACTION_PUSHING :
572 player->is_digging ? ACTION_DIGGING :
573 player->is_collecting ? ACTION_COLLECTING :
574 player->is_moving ? ACTION_MOVING :
575 player->snapped ? ACTION_SNAPPING : ACTION_DEFAULT);
577 InitPlayerGfxAnimation(player, action, move_dir);
579 /* ----------------------------------------------------------------------- */
580 /* draw things in the field the player is leaving, if needed */
581 /* ----------------------------------------------------------------------- */
583 if (player_is_moving)
585 if (Back[last_jx][last_jy] && IS_DRAWABLE(last_element))
587 DrawLevelElement(last_jx, last_jy, Back[last_jx][last_jy]);
589 if (last_element == EL_DYNAMITE_ACTIVE ||
590 last_element == EL_SP_DISK_RED_ACTIVE)
591 DrawDynamite(last_jx, last_jy);
593 DrawLevelFieldThruMask(last_jx, last_jy);
595 else if (last_element == EL_DYNAMITE_ACTIVE ||
596 last_element == EL_SP_DISK_RED_ACTIVE)
597 DrawDynamite(last_jx, last_jy);
599 DrawLevelField(last_jx, last_jy);
601 if (player->Pushing && IN_SCR_FIELD(SCREENX(next_jx), SCREENY(next_jy)))
604 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
608 if (Feld[next_jx][next_jy] == EL_SOKOBAN_FIELD_FULL)
609 DrawLevelElement(next_jx, next_jy, EL_SOKOBAN_FIELD_EMPTY);
611 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
614 DrawLevelField(next_jx, next_jy);
619 if (!IN_SCR_FIELD(sx, sy))
622 if (setup.direct_draw)
623 SetDrawtoField(DRAW_BUFFERED);
625 /* ----------------------------------------------------------------------- */
626 /* draw things behind the player, if needed */
627 /* ----------------------------------------------------------------------- */
630 DrawLevelElement(jx, jy, Back[jx][jy]);
631 else if (IS_ACTIVE_BOMB(element))
632 DrawLevelElement(jx, jy, EL_EMPTY);
635 if (player_is_moving && GfxElement[jx][jy] != EL_UNDEFINED)
637 if (GfxElement[jx][jy] == EL_SAND)
638 DrawLevelFieldCrumbledSandDigging(jx, jy, move_dir, player->StepFrame);
641 int old_element = GfxElement[jx][jy];
642 int old_graphic = el_act_dir2img(old_element, action, move_dir);
643 int frame = getGraphicAnimationFrame(old_graphic, player->StepFrame);
645 DrawGraphic(sx, sy, old_graphic, frame);
650 GfxElement[jx][jy] = EL_UNDEFINED;
652 DrawLevelField(jx, jy);
656 /* ----------------------------------------------------------------------- */
657 /* draw player himself */
658 /* ----------------------------------------------------------------------- */
660 if (player->use_murphy_graphic)
662 static int last_horizontal_dir = MV_LEFT;
665 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
666 last_horizontal_dir = move_dir;
668 direction = (player->snapped ? move_dir : last_horizontal_dir);
670 graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, direction);
673 graphic = el_act_dir2img(player->element_nr, player->GfxAction, move_dir);
675 frame = getGraphicAnimationFrame(graphic, player->Frame);
679 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
680 sxx = player->GfxPos;
682 syy = player->GfxPos;
685 if (!setup.soft_scrolling && ScreenMovPos)
688 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
690 if (SHIELD_ON(player))
692 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
693 IMG_SHIELD_NORMAL_ACTIVE);
694 int frame = getGraphicAnimationFrame(graphic, -1);
696 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
699 /* ----------------------------------------------------------------------- */
700 /* draw things the player is pushing, if needed */
701 /* ----------------------------------------------------------------------- */
703 if (player->Pushing && player_is_moving)
705 int px = SCREENX(next_jx), py = SCREENY(next_jy);
707 if (Back[next_jx][next_jy])
708 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
711 if ((sxx || syy) && element == EL_SOKOBAN_OBJECT)
712 DrawGraphicShiftedThruMask(px, py, sxx, syy, IMG_SOKOBAN_OBJECT, 0,
716 (element == EL_SOKOBAN_FIELD_EMPTY ||
717 Feld[next_jx][next_jy] == EL_SOKOBAN_FIELD_FULL))
718 DrawGraphicShiftedThruMask(px, py, sxx, syy, IMG_SOKOBAN_OBJECT, 0,
724 int element = Feld[jx][jy];
726 int element = Feld[next_jx][next_jy];
729 int graphic = el2img(element);
732 if ((sxx || syy) && IS_PUSHABLE(element))
734 graphic = el_act_dir2img(element, ACTION_MOVING, move_dir);
735 frame = getGraphicAnimationFrame(graphic, player->Frame);
738 DrawGraphicShifted(px, py, sxx, syy, graphic, frame,
739 NO_CUTTING, NO_MASKING);
743 /* ----------------------------------------------------------------------- */
744 /* draw things in front of player (active dynamite or dynabombs) */
745 /* ----------------------------------------------------------------------- */
747 if (IS_ACTIVE_BOMB(element))
749 graphic = el2img(element);
750 frame = getGraphicAnimationFrame(graphic, GfxFrame[jx][jy]);
752 if (game.emulation == EMU_SUPAPLEX)
753 DrawGraphic(sx, sy, IMG_SP_DISK_RED, frame);
755 DrawGraphicThruMask(sx, sy, graphic, frame);
758 if (player_is_moving && last_element == EL_EXPLOSION)
761 int graphic = el_act2img(GfxElement[last_jx][last_jy], ACTION_EXPLODING);
763 int stored = Store[last_jx][last_jy];
764 int graphic = (game.emulation != EMU_SUPAPLEX ? IMG_EXPLOSION :
765 stored == EL_SP_INFOTRON ? IMG_SP_EXPLOSION_INFOTRON :
768 int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
769 int phase = ExplodePhase[last_jx][last_jy] - 1;
770 int frame = getGraphicAnimationFrame(graphic, phase - delay);
773 DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy), graphic, frame);
776 /* ----------------------------------------------------------------------- */
777 /* draw elements the player is just walking/passing through/under */
778 /* ----------------------------------------------------------------------- */
780 /* handle the field the player is leaving ... */
781 if (player_is_moving && IS_ACCESSIBLE_INSIDE(last_element))
782 DrawLevelField(last_jx, last_jy);
783 else if (player_is_moving && IS_ACCESSIBLE_UNDER(last_element))
784 DrawLevelFieldThruMask(last_jx, last_jy);
786 /* ... and the field the player is entering */
787 if (IS_ACCESSIBLE_INSIDE(element))
788 DrawLevelField(jx, jy);
789 else if (IS_ACCESSIBLE_UNDER(element))
790 DrawLevelFieldThruMask(jx, jy);
792 if (setup.direct_draw)
794 int dest_x = SX + SCREENX(MIN(jx, last_jx)) * TILEX;
795 int dest_y = SY + SCREENY(MIN(jy, last_jy)) * TILEY;
796 int x_size = TILEX * (1 + ABS(jx - last_jx));
797 int y_size = TILEY * (1 + ABS(jy - last_jy));
799 BlitBitmap(drawto_field, window,
800 dest_x, dest_y, x_size, y_size, dest_x, dest_y);
801 SetDrawtoField(DRAW_DIRECT);
804 MarkTileDirty(sx,sy);
807 void getGraphicSource(int graphic, int frame, Bitmap **bitmap, int *x, int *y)
809 struct GraphicInfo *g = &graphic_info[graphic];
813 if (g->offset_y == 0) /* frames are ordered horizontally */
815 int max_width = g->anim_frames_per_line * g->width;
817 *x = (g->src_x + frame * g->offset_x) % max_width;
818 *y = g->src_y + (g->src_x + frame * g->offset_x) / max_width * g->height;
820 else if (g->offset_x == 0) /* frames are ordered vertically */
822 int max_height = g->anim_frames_per_line * g->height;
824 *x = g->src_x + (g->src_y + frame * g->offset_y) / max_height * g->width;
825 *y = (g->src_y + frame * g->offset_y) % max_height;
827 else /* frames are ordered diagonally */
829 *x = g->src_x + frame * g->offset_x;
830 *y = g->src_y + frame * g->offset_y;
834 void DrawGraphic(int x, int y, int graphic, int frame)
837 if (!IN_SCR_FIELD(x, y))
839 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
840 printf("DrawGraphic(): This should never happen!\n");
845 DrawGraphicExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic, frame);
850 void DrawOldGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic)
855 getOldGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
856 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
860 void DrawGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
867 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
869 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
870 int src_x = graphic_info[graphic].src_x;
871 int src_y = graphic_info[graphic].src_y;
872 int offset_x = graphic_info[graphic].offset_x;
873 int offset_y = graphic_info[graphic].offset_y;
875 src_x += frame * offset_x;
876 src_y += frame * offset_y;
879 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
882 void DrawGraphicThruMask(int x, int y, int graphic, int frame)
885 if (!IN_SCR_FIELD(x, y))
887 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
888 printf("DrawGraphicThruMask(): This should never happen!\n");
893 DrawGraphicThruMaskExt(drawto_field, FX + x * TILEX, FY + y *TILEY, graphic,
898 void DrawGraphicThruMaskExt(DrawBuffer *d, int dest_x, int dest_y, int graphic,
906 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
907 drawing_gc = src_bitmap->stored_clip_gc;
909 GC drawing_gc = src_bitmap->stored_clip_gc;
910 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
911 int src_x = graphic_info[graphic].src_x;
912 int src_y = graphic_info[graphic].src_y;
913 int offset_x = graphic_info[graphic].offset_x;
914 int offset_y = graphic_info[graphic].offset_y;
916 src_x += frame * offset_x;
917 src_y += frame * offset_y;
921 SetClipOrigin(src_bitmap, drawing_gc, dest_x - src_x, dest_y - src_y);
922 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX, TILEY, dest_x, dest_y);
925 void DrawMiniGraphic(int x, int y, int graphic)
927 DrawMiniGraphicExt(drawto, SX + x * MINI_TILEX,SY + y * MINI_TILEY, graphic);
928 MarkTileDirty(x / 2, y / 2);
931 void getMiniGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
933 struct GraphicInfo *g = &graphic_info[graphic];
935 int mini_starty = g->bitmap->height * 2 / 3;
938 *x = mini_startx + g->src_x / 2;
939 *y = mini_starty + g->src_y / 2;
942 void DrawMiniGraphicExt(DrawBuffer *d, int x, int y, int graphic)
947 getMiniGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
948 BlitBitmap(src_bitmap, d, src_x, src_y, MINI_TILEX, MINI_TILEY, x, y);
951 void DrawGraphicShifted(int x,int y, int dx,int dy, int graphic, int frame,
952 int cut_mode, int mask_mode)
957 int width = TILEX, height = TILEY;
963 DrawGraphic(x, y, graphic, frame);
967 if (dx || dy) /* shifted graphic */
969 if (x < BX1) /* object enters playfield from the left */
976 else if (x > BX2) /* object enters playfield from the right */
982 else if (x==BX1 && dx < 0) /* object leaves playfield to the left */
988 else if (x==BX2 && dx > 0) /* object leaves playfield to the right */
990 else if (dx) /* general horizontal movement */
991 MarkTileDirty(x + SIGN(dx), y);
993 if (y < BY1) /* object enters playfield from the top */
995 if (cut_mode==CUT_BELOW) /* object completely above top border */
1003 else if (y > BY2) /* object enters playfield from the bottom */
1009 else if (y==BY1 && dy < 0) /* object leaves playfield to the top */
1015 else if (dy > 0 && cut_mode == CUT_ABOVE)
1017 if (y == BY2) /* object completely above bottom border */
1023 MarkTileDirty(x, y + 1);
1024 } /* object leaves playfield to the bottom */
1025 else if (dy > 0 && (y == BY2 || cut_mode == CUT_BELOW))
1027 else if (dy) /* general vertical movement */
1028 MarkTileDirty(x, y + SIGN(dy));
1032 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1034 src_bitmap = graphic_info[graphic].bitmap;
1035 src_x = graphic_info[graphic].src_x;
1036 src_y = graphic_info[graphic].src_y;
1037 offset_x = graphic_info[graphic].offset_x;
1038 offset_y = graphic_info[graphic].offset_y;
1040 src_x += frame * offset_x;
1041 src_y += frame * offset_y;
1044 drawing_gc = src_bitmap->stored_clip_gc;
1049 dest_x = FX + x * TILEX + dx;
1050 dest_y = FY + y * TILEY + dy;
1053 if (!IN_SCR_FIELD(x,y))
1055 printf("DrawGraphicShifted(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
1056 printf("DrawGraphicShifted(): This should never happen!\n");
1061 if (mask_mode == USE_MASKING)
1063 SetClipOrigin(src_bitmap, drawing_gc, dest_x - src_x, dest_y - src_y);
1064 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1068 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1074 void DrawGraphicShiftedThruMask(int x, int y, int dx, int dy, int graphic,
1075 int frame, int cut_mode)
1077 DrawGraphicShifted(x,y, dx,dy, graphic, frame, cut_mode, USE_MASKING);
1080 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
1081 int cut_mode, int mask_mode)
1083 int lx = LEVELX(x), ly = LEVELY(y);
1087 if (IN_LEV_FIELD(lx, ly))
1089 SetRandomAnimationValue(lx, ly);
1091 graphic = el_act_dir2img(element, GfxAction[lx][ly], MovDir[lx][ly]);
1092 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1094 else /* border element */
1096 graphic = el2img(element);
1097 frame = getGraphicAnimationFrame(graphic, -1);
1100 if (element == EL_EXPANDABLE_WALL)
1102 boolean left_stopped = FALSE, right_stopped = FALSE;
1104 if (!IN_LEV_FIELD(lx - 1, ly) || IS_WALL(Feld[lx - 1][ly]))
1105 left_stopped = TRUE;
1106 if (!IN_LEV_FIELD(lx + 1, ly) || IS_WALL(Feld[lx + 1][ly]))
1107 right_stopped = TRUE;
1109 if (left_stopped && right_stopped)
1111 else if (left_stopped)
1113 graphic = IMG_EXPANDABLE_WALL_GROWING_RIGHT;
1114 frame = graphic_info[graphic].anim_frames - 1;
1116 else if (right_stopped)
1118 graphic = IMG_EXPANDABLE_WALL_GROWING_LEFT;
1119 frame = graphic_info[graphic].anim_frames - 1;
1123 else if (IS_AMOEBOID(element) || element == EL_AMOEBA_DROPPING)
1125 graphic = (element == EL_BD_AMOEBA ? IMG_BD_AMOEBA_PART1 :
1126 element == EL_AMOEBA_WET ? IMG_AMOEBA_WET_PART1 :
1127 element == EL_AMOEBA_DRY ? IMG_AMOEBA_DRY_PART1 :
1128 element == EL_AMOEBA_FULL ? IMG_AMOEBA_FULL_PART1 :
1129 IMG_AMOEBA_DEAD_PART1);
1131 graphic += (x + 2 * y + 4) % 4;
1136 if (IS_AMOEBOID(element) || element == EL_AMOEBA_DROPPING)
1138 if (Feld[lx][ly] == EL_AMOEBA_DROPPING)
1139 printf("---> %d -> %d / %d [%d]\n",
1140 element, graphic, frame, GfxRandom[lx][ly]);
1145 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, mask_mode);
1146 else if (mask_mode == USE_MASKING)
1147 DrawGraphicThruMask(x, y, graphic, frame);
1149 DrawGraphic(x, y, graphic, frame);
1152 void DrawLevelElementExt(int x, int y, int dx, int dy, int element,
1153 int cut_mode, int mask_mode)
1155 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1156 DrawScreenElementExt(SCREENX(x), SCREENY(y), dx, dy, element,
1157 cut_mode, mask_mode);
1160 void DrawScreenElementShifted(int x, int y, int dx, int dy, int element,
1163 DrawScreenElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1166 void DrawLevelElementShifted(int x, int y, int dx, int dy, int element,
1169 DrawLevelElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1173 void DrawOldScreenElementThruMask(int x, int y, int element)
1175 DrawOldScreenElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1178 void DrawScreenElementThruMask(int x, int y, int element)
1180 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1184 void DrawLevelElementThruMask(int x, int y, int element)
1186 DrawLevelElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1189 void DrawLevelFieldThruMask(int x, int y)
1191 DrawLevelElementExt(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
1194 static void DrawLevelFieldCrumbledSandExt(int x, int y, int graphic, int frame)
1198 int sx = SCREENX(x), sy = SCREENY(y);
1200 int width, height, cx, cy, i;
1201 int snip = TILEX / 8; /* number of border pixels from "crumbled graphic" */
1202 static int xy[4][2] =
1210 if (!IN_LEV_FIELD(x, y))
1213 element = (GfxElement[x][y] != EL_UNDEFINED ? GfxElement[x][y] : Feld[x][y]);
1215 /* crumble field itself */
1216 if (CAN_BE_CRUMBLED(element) && !IS_MOVING(x, y))
1218 if (!IN_SCR_FIELD(sx, sy))
1221 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1225 int xx = x + xy[i][0];
1226 int yy = y + xy[i][1];
1228 element = (IN_LEV_FIELD(xx, yy) ? Feld[xx][yy] : EL_STEELWALL);
1230 /* check if neighbour field is of same type */
1231 if (CAN_BE_CRUMBLED(element) && !IS_MOVING(xx, yy))
1234 if (i == 1 || i == 2)
1238 cx = (i == 2 ? TILEX - snip : 0);
1246 cy = (i == 3 ? TILEY - snip : 0);
1249 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1250 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
1253 MarkTileDirty(sx, sy);
1255 else /* crumble neighbour fields */
1257 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1261 int xx = x + xy[i][0];
1262 int yy = y + xy[i][1];
1263 int sxx = sx + xy[i][0];
1264 int syy = sy + xy[i][1];
1266 if (!IN_LEV_FIELD(xx, yy) ||
1267 !IN_SCR_FIELD(sxx, syy) ||
1268 !CAN_BE_CRUMBLED(Feld[xx][yy]) ||
1272 if (i == 1 || i == 2)
1276 cx = (i == 1 ? TILEX - snip : 0);
1284 cy = (i==0 ? TILEY-snip : 0);
1287 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1288 width, height, FX + sxx * TILEX + cx, FY + syy * TILEY + cy);
1290 MarkTileDirty(sxx, syy);
1295 void DrawLevelFieldCrumbledSand(int x, int y)
1297 DrawLevelFieldCrumbledSandExt(x, y, IMG_SAND_CRUMBLED, 0);
1300 void DrawLevelFieldCrumbledSandDigging(int x, int y, int direction,
1303 int graphic1 = el_act_dir2img(EL_SAND, ACTION_DIGGING, direction);
1304 int graphic2 = el_act_dir2img(EL_SAND_CRUMBLED, ACTION_DIGGING, direction);
1305 int frame1 = getGraphicAnimationFrame(graphic1, step_frame);
1306 int frame2 = getGraphicAnimationFrame(graphic2, step_frame);
1307 int sx = SCREENX(x), sy = SCREENY(y);
1309 DrawGraphic(sx, sy, graphic1, frame1);
1310 DrawLevelFieldCrumbledSandExt(x, y, graphic2, frame2);
1313 static int getBorderElement(int x, int y)
1317 { EL_STEELWALL_TOPLEFT, EL_INVISIBLE_STEELWALL_TOPLEFT },
1318 { EL_STEELWALL_TOPRIGHT, EL_INVISIBLE_STEELWALL_TOPRIGHT },
1319 { EL_STEELWALL_BOTTOMLEFT, EL_INVISIBLE_STEELWALL_BOTTOMLEFT },
1320 { EL_STEELWALL_BOTTOMRIGHT, EL_INVISIBLE_STEELWALL_BOTTOMRIGHT },
1321 { EL_STEELWALL_VERTICAL, EL_INVISIBLE_STEELWALL_VERTICAL },
1322 { EL_STEELWALL_HORIZONTAL, EL_INVISIBLE_STEELWALL_HORIZONTAL },
1323 { EL_STEELWALL, EL_INVISIBLE_STEELWALL }
1325 int steel_type = (BorderElement == EL_STEELWALL ? 0 : 1);
1326 int steel_position = (x == -1 && y == -1 ? 0 :
1327 x == lev_fieldx && y == -1 ? 1 :
1328 x == -1 && y == lev_fieldy ? 2 :
1329 x == lev_fieldx && y == lev_fieldy ? 3 :
1330 x == -1 || x == lev_fieldx ? 4 :
1331 y == -1 || y == lev_fieldy ? 5 : 6);
1333 return border[steel_position][steel_type];
1336 void DrawScreenElement(int x, int y, int element)
1338 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
1339 DrawLevelFieldCrumbledSand(LEVELX(x), LEVELY(y));
1342 void DrawLevelElement(int x, int y, int element)
1344 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1345 DrawScreenElement(SCREENX(x), SCREENY(y), element);
1348 void DrawScreenField(int x, int y)
1350 int lx = LEVELX(x), ly = LEVELY(y);
1351 int element, content;
1353 if (!IN_LEV_FIELD(lx, ly))
1355 if (lx < -1 || lx > lev_fieldx || ly < -1 || ly > lev_fieldy)
1358 element = getBorderElement(lx, ly);
1360 DrawScreenElement(x, y, element);
1364 element = Feld[lx][ly];
1365 content = Store[lx][ly];
1367 if (IS_MOVING(lx, ly))
1369 int horiz_move = (MovDir[lx][ly] == MV_LEFT || MovDir[lx][ly] == MV_RIGHT);
1370 boolean cut_mode = NO_CUTTING;
1372 if (element == EL_QUICKSAND_EMPTYING ||
1373 element == EL_MAGIC_WALL_EMPTYING ||
1374 element == EL_BD_MAGIC_WALL_EMPTYING ||
1375 element == EL_AMOEBA_DROPPING)
1376 cut_mode = CUT_ABOVE;
1377 else if (element == EL_QUICKSAND_FILLING ||
1378 element == EL_MAGIC_WALL_FILLING ||
1379 element == EL_BD_MAGIC_WALL_FILLING)
1380 cut_mode = CUT_BELOW;
1382 if (cut_mode == CUT_ABOVE)
1383 DrawScreenElementShifted(x, y, 0, 0, element, NO_CUTTING);
1385 DrawScreenElement(x, y, EL_EMPTY);
1388 DrawScreenElementShifted(x, y, MovPos[lx][ly], 0, element, NO_CUTTING);
1389 else if (cut_mode == NO_CUTTING)
1390 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], element, cut_mode);
1392 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], content, cut_mode);
1394 if (content == EL_ACID)
1395 DrawLevelElementThruMask(lx, ly + 1, EL_ACID);
1397 else if (IS_BLOCKED(lx, ly))
1402 boolean cut_mode = NO_CUTTING;
1403 int element_old, content_old;
1405 Blocked2Moving(lx, ly, &oldx, &oldy);
1408 horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
1409 MovDir[oldx][oldy] == MV_RIGHT);
1411 element_old = Feld[oldx][oldy];
1412 content_old = Store[oldx][oldy];
1414 if (element_old == EL_QUICKSAND_EMPTYING ||
1415 element_old == EL_MAGIC_WALL_EMPTYING ||
1416 element_old == EL_BD_MAGIC_WALL_EMPTYING ||
1417 element_old == EL_AMOEBA_DROPPING)
1418 cut_mode = CUT_ABOVE;
1420 DrawScreenElement(x, y, EL_EMPTY);
1423 DrawScreenElementShifted(sx, sy, MovPos[oldx][oldy], 0, element_old,
1425 else if (cut_mode == NO_CUTTING)
1426 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], element_old,
1429 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], content_old,
1432 else if (IS_DRAWABLE(element))
1433 DrawScreenElement(x, y, element);
1435 DrawScreenElement(x, y, EL_EMPTY);
1438 void DrawLevelField(int x, int y)
1440 if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1441 DrawScreenField(SCREENX(x), SCREENY(y));
1442 else if (IS_MOVING(x, y))
1446 Moving2Blocked(x, y, &newx, &newy);
1447 if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
1448 DrawScreenField(SCREENX(newx), SCREENY(newy));
1450 else if (IS_BLOCKED(x, y))
1454 Blocked2Moving(x, y, &oldx, &oldy);
1455 if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
1456 DrawScreenField(SCREENX(oldx), SCREENY(oldy));
1460 void DrawMiniElement(int x, int y, int element)
1464 graphic = el2edimg(element);
1465 DrawMiniGraphic(x, y, graphic);
1468 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
1470 int x = sx + scroll_x, y = sy + scroll_y;
1472 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
1473 DrawMiniElement(sx, sy, EL_EMPTY);
1474 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
1475 DrawMiniElement(sx, sy, Feld[x][y]);
1477 DrawMiniGraphic(sx, sy, el2edimg(getBorderElement(x, y)));
1480 void getMicroGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
1482 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
1483 int mini_startx = src_bitmap->width * 3 / 4;
1484 int mini_starty = src_bitmap->height * 2 / 3;
1485 int src_x = mini_startx + graphic_info[graphic].src_x / 8;
1486 int src_y = mini_starty + graphic_info[graphic].src_y / 8;
1489 if (src_x + MICRO_TILEX > src_bitmap->width ||
1490 src_y + MICRO_TILEY > src_bitmap->height)
1492 /* graphic of desired size seems not to be contained in this image;
1493 dirty workaround: get it from the middle of the normal sized image */
1495 getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
1496 src_x += (TILEX / 2 - MICRO_TILEX / 2);
1497 src_y += (TILEY / 2 - MICRO_TILEY / 2);
1501 *bitmap = src_bitmap;
1506 void DrawMicroElement(int xpos, int ypos, int element)
1510 int graphic = el2preimg(element);
1512 getMicroGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
1513 BlitBitmap(src_bitmap, drawto, src_x, src_y, MICRO_TILEX, MICRO_TILEY,
1521 SetDrawBackgroundMask(REDRAW_NONE);
1524 for(x=BX1; x<=BX2; x++)
1525 for(y=BY1; y<=BY2; y++)
1526 DrawScreenField(x, y);
1528 redraw_mask |= REDRAW_FIELD;
1531 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
1535 for(x=0; x<size_x; x++)
1536 for(y=0; y<size_y; y++)
1537 DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
1539 redraw_mask |= REDRAW_FIELD;
1542 static void DrawMicroLevelExt(int xpos, int ypos, int from_x, int from_y)
1546 DrawBackground(xpos, ypos, MICROLEV_XSIZE, MICROLEV_YSIZE);
1548 if (lev_fieldx < STD_LEV_FIELDX)
1549 xpos += (STD_LEV_FIELDX - lev_fieldx) / 2 * MICRO_TILEX;
1550 if (lev_fieldy < STD_LEV_FIELDY)
1551 ypos += (STD_LEV_FIELDY - lev_fieldy) / 2 * MICRO_TILEY;
1553 xpos += MICRO_TILEX;
1554 ypos += MICRO_TILEY;
1556 for(x=-1; x<=STD_LEV_FIELDX; x++)
1558 for(y=-1; y<=STD_LEV_FIELDY; y++)
1560 int lx = from_x + x, ly = from_y + y;
1562 if (lx >= 0 && lx < lev_fieldx && ly >= 0 && ly < lev_fieldy)
1563 DrawMicroElement(xpos + x * MICRO_TILEX, ypos + y * MICRO_TILEY,
1565 else if (lx >= -1 && lx < lev_fieldx+1 && ly >= -1 && ly < lev_fieldy+1
1566 && BorderElement != EL_EMPTY)
1567 DrawMicroElement(xpos + x * MICRO_TILEX, ypos + y * MICRO_TILEY,
1568 getBorderElement(lx, ly));
1572 redraw_mask |= REDRAW_MICROLEVEL;
1575 #define MICROLABEL_EMPTY 0
1576 #define MICROLABEL_LEVEL_NAME 1
1577 #define MICROLABEL_CREATED_BY 2
1578 #define MICROLABEL_LEVEL_AUTHOR 3
1579 #define MICROLABEL_IMPORTED_FROM 4
1580 #define MICROLABEL_LEVEL_IMPORT_INFO 5
1582 static void DrawMicroLevelLabelExt(int mode)
1584 char label_text[MAX_OUTPUT_LINESIZE + 1];
1585 int max_len_label_text;
1586 int font_nr = FONT_TEXT_2;
1588 if (mode == MICROLABEL_CREATED_BY || mode == MICROLABEL_IMPORTED_FROM)
1589 font_nr = FONT_TEXT_3;
1591 max_len_label_text = SXSIZE / getFontWidth(font_nr);
1593 DrawBackground(SX, MICROLABEL_YPOS, SXSIZE, getFontHeight(font_nr));
1595 strncpy(label_text, (mode == MICROLABEL_LEVEL_NAME ? level.name :
1596 mode == MICROLABEL_CREATED_BY ? "created by" :
1597 mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
1598 mode == MICROLABEL_IMPORTED_FROM ? "imported from" :
1599 mode == MICROLABEL_LEVEL_IMPORT_INFO ?
1600 leveldir_current->imported_from : ""),
1601 max_len_label_text);
1602 label_text[max_len_label_text] = '\0';
1604 if (strlen(label_text) > 0)
1606 int text_width = strlen(label_text) * getFontWidth(font_nr);
1607 int lxpos = SX + (SXSIZE - text_width) / 2;
1608 int lypos = MICROLABEL_YPOS;
1610 DrawText(lxpos, lypos, label_text, font_nr);
1613 redraw_mask |= REDRAW_MICROLEVEL;
1616 void DrawMicroLevel(int xpos, int ypos, boolean restart)
1618 static unsigned long scroll_delay = 0;
1619 static unsigned long label_delay = 0;
1620 static int from_x, from_y, scroll_direction;
1621 static int label_state, label_counter;
1622 int last_game_status = game_status; /* save current game status */
1624 /* force PREVIEW font on preview level */
1625 game_status = GAME_MODE_PSEUDO_PREVIEW;
1629 from_x = from_y = 0;
1630 scroll_direction = MV_RIGHT;
1634 DrawMicroLevelExt(xpos, ypos, from_x, from_y);
1635 DrawMicroLevelLabelExt(label_state);
1637 /* initialize delay counters */
1638 DelayReached(&scroll_delay, 0);
1639 DelayReached(&label_delay, 0);
1641 if (leveldir_current->name)
1643 int len = strlen(leveldir_current->name);
1644 int lxpos = SX + (SXSIZE - len * getFontWidth(FONT_TEXT_1)) / 2;
1645 int lypos = SY + 352;
1647 DrawText(lxpos, lypos, leveldir_current->name, FONT_TEXT_1);
1650 game_status = last_game_status; /* restore current game status */
1655 /* scroll micro level, if needed */
1656 if ((lev_fieldx > STD_LEV_FIELDX || lev_fieldy > STD_LEV_FIELDY) &&
1657 DelayReached(&scroll_delay, MICROLEVEL_SCROLL_DELAY))
1659 switch (scroll_direction)
1665 scroll_direction = MV_UP;
1669 if (from_x < lev_fieldx - STD_LEV_FIELDX)
1672 scroll_direction = MV_DOWN;
1679 scroll_direction = MV_RIGHT;
1683 if (from_y < lev_fieldy - STD_LEV_FIELDY)
1686 scroll_direction = MV_LEFT;
1693 DrawMicroLevelExt(xpos, ypos, from_x, from_y);
1696 /* redraw micro level label, if needed */
1697 if (strcmp(level.name, NAMELESS_LEVEL_NAME) != 0 &&
1698 strcmp(level.author, ANONYMOUS_NAME) != 0 &&
1699 strcmp(level.author, leveldir_current->name) != 0 &&
1700 DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
1702 int max_label_counter = 23;
1704 if (leveldir_current->imported_from != NULL)
1705 max_label_counter += 14;
1707 label_counter = (label_counter + 1) % max_label_counter;
1708 label_state = (label_counter >= 0 && label_counter <= 7 ?
1709 MICROLABEL_LEVEL_NAME :
1710 label_counter >= 9 && label_counter <= 12 ?
1711 MICROLABEL_CREATED_BY :
1712 label_counter >= 14 && label_counter <= 21 ?
1713 MICROLABEL_LEVEL_AUTHOR :
1714 label_counter >= 23 && label_counter <= 26 ?
1715 MICROLABEL_IMPORTED_FROM :
1716 label_counter >= 28 && label_counter <= 35 ?
1717 MICROLABEL_LEVEL_IMPORT_INFO : MICROLABEL_EMPTY);
1718 DrawMicroLevelLabelExt(label_state);
1721 game_status = last_game_status; /* restore current game status */
1724 int REQ_in_range(int x, int y)
1726 if (y > DY+249 && y < DY+278)
1728 if (x > DX+1 && x < DX+48)
1730 else if (x > DX+51 && x < DX+98)
1736 #define MAX_REQUEST_LINES 13
1737 #define MAX_REQUEST_LINE_LEN 7
1739 boolean Request(char *text, unsigned int req_state)
1741 int mx, my, ty, result = -1;
1742 unsigned int old_door_state;
1743 int last_game_status = game_status; /* save current game status */
1745 #if defined(PLATFORM_UNIX)
1746 /* pause network game while waiting for request to answer */
1747 if (options.network &&
1748 game_status == GAME_MODE_PLAYING &&
1749 req_state & REQUEST_WAIT_FOR)
1750 SendToServer_PausePlaying();
1753 old_door_state = GetDoorState();
1757 CloseDoor(DOOR_CLOSE_1);
1759 /* save old door content */
1760 BlitBitmap(bitmap_db_door, bitmap_db_door,
1761 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
1762 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
1764 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
1766 /* clear door drawing field */
1767 DrawBackground(DX, DY, DXSIZE, DYSIZE);
1769 /* force DOOR font on preview level */
1770 game_status = GAME_MODE_PSEUDO_DOOR;
1772 /* write text for request */
1773 for(ty=0; ty < MAX_REQUEST_LINES; ty++)
1775 char text_line[MAX_REQUEST_LINE_LEN + 1];
1781 for(tl=0,tx=0; tx < MAX_REQUEST_LINE_LEN; tl++,tx++)
1784 if (!tc || tc == ' ')
1795 strncpy(text_line, text, tl);
1798 DrawText(DX + (DXSIZE - tl * getFontWidth(FONT_TEXT_2)) / 2,
1799 DY + 8 + ty * (getFontHeight(FONT_TEXT_2) + 2),
1800 text_line, FONT_TEXT_2);
1802 text += tl + (tc == ' ' ? 1 : 0);
1805 game_status = last_game_status; /* restore current game status */
1807 if (req_state & REQ_ASK)
1809 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
1810 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
1812 else if (req_state & REQ_CONFIRM)
1814 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
1816 else if (req_state & REQ_PLAYER)
1818 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
1819 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
1820 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
1821 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
1824 /* copy request gadgets to door backbuffer */
1825 BlitBitmap(drawto, bitmap_db_door,
1826 DX, DY, DXSIZE, DYSIZE,
1827 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
1829 OpenDoor(DOOR_OPEN_1);
1835 if (!(req_state & REQUEST_WAIT_FOR))
1837 SetDrawBackgroundMask(REDRAW_FIELD);
1842 if (game_status != GAME_MODE_MAIN)
1845 button_status = MB_RELEASED;
1847 request_gadget_id = -1;
1849 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
1861 case EVENT_BUTTONPRESS:
1862 case EVENT_BUTTONRELEASE:
1863 case EVENT_MOTIONNOTIFY:
1865 if (event.type == EVENT_MOTIONNOTIFY)
1867 if (!PointerInWindow(window))
1868 continue; /* window and pointer are on different screens */
1873 motion_status = TRUE;
1874 mx = ((MotionEvent *) &event)->x;
1875 my = ((MotionEvent *) &event)->y;
1879 motion_status = FALSE;
1880 mx = ((ButtonEvent *) &event)->x;
1881 my = ((ButtonEvent *) &event)->y;
1882 if (event.type == EVENT_BUTTONPRESS)
1883 button_status = ((ButtonEvent *) &event)->button;
1885 button_status = MB_RELEASED;
1888 /* this sets 'request_gadget_id' */
1889 HandleGadgets(mx, my, button_status);
1891 switch(request_gadget_id)
1893 case TOOL_CTRL_ID_YES:
1896 case TOOL_CTRL_ID_NO:
1899 case TOOL_CTRL_ID_CONFIRM:
1900 result = TRUE | FALSE;
1903 case TOOL_CTRL_ID_PLAYER_1:
1906 case TOOL_CTRL_ID_PLAYER_2:
1909 case TOOL_CTRL_ID_PLAYER_3:
1912 case TOOL_CTRL_ID_PLAYER_4:
1923 case EVENT_KEYPRESS:
1924 switch(GetEventKey((KeyEvent *)&event, TRUE))
1937 if (req_state & REQ_PLAYER)
1941 case EVENT_KEYRELEASE:
1942 ClearPlayerAction();
1946 HandleOtherEvents(&event);
1950 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
1952 int joy = AnyJoystick();
1954 if (joy & JOY_BUTTON_1)
1956 else if (joy & JOY_BUTTON_2)
1962 /* don't eat all CPU time */
1966 if (game_status != GAME_MODE_MAIN)
1971 if (!(req_state & REQ_STAY_OPEN))
1973 CloseDoor(DOOR_CLOSE_1);
1975 if (!(req_state & REQ_STAY_CLOSED) && (old_door_state & DOOR_OPEN_1))
1977 BlitBitmap(bitmap_db_door, bitmap_db_door,
1978 DOOR_GFX_PAGEX2,DOOR_GFX_PAGEY1, DXSIZE,DYSIZE,
1979 DOOR_GFX_PAGEX1,DOOR_GFX_PAGEY1);
1980 OpenDoor(DOOR_OPEN_1);
1986 SetDrawBackgroundMask(REDRAW_FIELD);
1988 #if defined(PLATFORM_UNIX)
1989 /* continue network game after request */
1990 if (options.network &&
1991 game_status == GAME_MODE_PLAYING &&
1992 req_state & REQUEST_WAIT_FOR)
1993 SendToServer_ContinuePlaying();
1999 unsigned int OpenDoor(unsigned int door_state)
2001 unsigned int new_door_state;
2003 if (door_state & DOOR_COPY_BACK)
2005 BlitBitmap(bitmap_db_door, bitmap_db_door,
2006 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE + VYSIZE,
2007 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2008 door_state &= ~DOOR_COPY_BACK;
2011 new_door_state = MoveDoor(door_state);
2013 return(new_door_state);
2016 unsigned int CloseDoor(unsigned int door_state)
2018 unsigned int new_door_state;
2020 BlitBitmap(backbuffer, bitmap_db_door,
2021 DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2022 BlitBitmap(backbuffer, bitmap_db_door,
2023 VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
2025 new_door_state = MoveDoor(door_state);
2027 return(new_door_state);
2030 unsigned int GetDoorState()
2032 return MoveDoor(DOOR_GET_STATE);
2035 unsigned int SetDoorState(unsigned int door_state)
2037 return MoveDoor(door_state | DOOR_SET_STATE);
2040 unsigned int MoveDoor(unsigned int door_state)
2042 static int door1 = DOOR_OPEN_1;
2043 static int door2 = DOOR_CLOSE_2;
2044 static unsigned long door_delay = 0;
2045 int x, start, stepsize = door.step_offset;
2046 unsigned long door_delay_value = door.step_delay;
2048 if (door_state == DOOR_GET_STATE)
2049 return(door1 | door2);
2051 if (door_state & DOOR_SET_STATE)
2053 if (door_state & DOOR_ACTION_1)
2054 door1 = door_state & DOOR_ACTION_1;
2055 if (door_state & DOOR_ACTION_2)
2056 door2 = door_state & DOOR_ACTION_2;
2058 return(door1 | door2);
2061 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
2062 door_state &= ~DOOR_OPEN_1;
2063 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
2064 door_state &= ~DOOR_CLOSE_1;
2065 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
2066 door_state &= ~DOOR_OPEN_2;
2067 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
2068 door_state &= ~DOOR_CLOSE_2;
2070 if (setup.quick_doors)
2073 door_delay_value = 0;
2075 StopSound(SND_DOOR_OPENING);
2076 StopSound(SND_DOOR_CLOSING);
2079 if (global.autoplay_leveldir)
2081 door_state |= DOOR_NO_DELAY;
2082 door_state &= ~DOOR_CLOSE_ALL;
2085 if (door_state & DOOR_ACTION)
2087 if (!(door_state & DOOR_NO_DELAY))
2089 /* opening door sound has priority over simultaneously closing door */
2090 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
2091 PlaySoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
2092 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
2093 PlaySoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
2096 start = ((door_state & DOOR_NO_DELAY) ? DXSIZE : 0);
2098 for(x=start; x<=DXSIZE; x+=stepsize)
2100 Bitmap *bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
2101 GC gc = bitmap->stored_clip_gc;
2103 if (!(door_state & DOOR_NO_DELAY))
2104 WaitUntilDelayReached(&door_delay, door_delay_value);
2106 if (door_state & DOOR_ACTION_1)
2108 int i = (door_state & DOOR_OPEN_1 ? DXSIZE-x : x);
2109 int j = (DXSIZE - i) / 3;
2111 BlitBitmap(bitmap_db_door, drawto,
2112 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + i/2,
2113 DXSIZE,DYSIZE - i/2, DX, DY);
2115 ClearRectangle(drawto, DX, DY + DYSIZE - i/2, DXSIZE,i/2);
2117 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2118 BlitBitmapMasked(bitmap, drawto,
2119 DXSIZE, DOOR_GFX_PAGEY1, i, 77,
2120 DX + DXSIZE - i, DY + j);
2121 BlitBitmapMasked(bitmap, drawto,
2122 DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63,
2123 DX + DXSIZE - i, DY + 140 + j);
2124 SetClipOrigin(bitmap, gc, DX - DXSIZE + i, DY - (DOOR_GFX_PAGEY1 + j));
2125 BlitBitmapMasked(bitmap, drawto,
2126 DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j,
2128 BlitBitmapMasked(bitmap, drawto,
2129 DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63,
2132 BlitBitmapMasked(bitmap, drawto,
2133 DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
2135 BlitBitmapMasked(bitmap, drawto,
2136 DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
2138 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2139 BlitBitmapMasked(bitmap, drawto,
2140 DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
2141 DX + DXSIZE - i, DY + 77 + j);
2142 BlitBitmapMasked(bitmap, drawto,
2143 DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
2144 DX + DXSIZE - i, DY + 203 + j);
2146 redraw_mask |= REDRAW_DOOR_1;
2149 if (door_state & DOOR_ACTION_2)
2151 int i = (door_state & DOOR_OPEN_2 ? VXSIZE - x : x);
2152 int j = (VXSIZE - i) / 3;
2154 BlitBitmap(bitmap_db_door, drawto,
2155 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + i/2,
2156 VXSIZE, VYSIZE - i/2, VX, VY);
2158 ClearRectangle(drawto, VX, VY + VYSIZE-i/2, VXSIZE, i/2);
2160 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2161 BlitBitmapMasked(bitmap, drawto,
2162 VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2,
2163 VX + VXSIZE-i, VY+j);
2164 SetClipOrigin(bitmap, gc,
2165 VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
2166 BlitBitmapMasked(bitmap, drawto,
2167 VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j,
2170 BlitBitmapMasked(bitmap, drawto,
2171 VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2,
2172 i, VYSIZE / 2, VX, VY + VYSIZE / 2 - j);
2173 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2174 BlitBitmapMasked(bitmap, drawto,
2175 VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2,
2177 VX + VXSIZE - i, VY + VYSIZE / 2 + j);
2179 redraw_mask |= REDRAW_DOOR_2;
2184 if (game_status == GAME_MODE_MAIN)
2189 if (setup.quick_doors)
2191 StopSound(SND_DOOR_OPENING);
2192 StopSound(SND_DOOR_CLOSING);
2195 if (door_state & DOOR_ACTION_1)
2196 door1 = door_state & DOOR_ACTION_1;
2197 if (door_state & DOOR_ACTION_2)
2198 door2 = door_state & DOOR_ACTION_2;
2200 return (door1 | door2);
2203 void DrawSpecialEditorDoor()
2205 /* draw bigger toolbox window */
2206 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
2207 DOOR_GFX_PAGEX7, 0, EXSIZE + 8, 8,
2209 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
2210 EX - 4, VY - 4, EXSIZE + 8, EYSIZE - VYSIZE + 4,
2213 redraw_mask |= REDRAW_ALL;
2216 void UndrawSpecialEditorDoor()
2218 /* draw normal tape recorder window */
2219 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
2220 EX - 4, EY - 12, EXSIZE + 8, EYSIZE - VYSIZE + 12,
2223 redraw_mask |= REDRAW_ALL;
2227 /* ---------- new tool button stuff ---------------------------------------- */
2229 /* graphic position values for tool buttons */
2230 #define TOOL_BUTTON_YES_XPOS 2
2231 #define TOOL_BUTTON_YES_YPOS 250
2232 #define TOOL_BUTTON_YES_GFX_YPOS 0
2233 #define TOOL_BUTTON_YES_XSIZE 46
2234 #define TOOL_BUTTON_YES_YSIZE 28
2235 #define TOOL_BUTTON_NO_XPOS 52
2236 #define TOOL_BUTTON_NO_YPOS TOOL_BUTTON_YES_YPOS
2237 #define TOOL_BUTTON_NO_GFX_YPOS TOOL_BUTTON_YES_GFX_YPOS
2238 #define TOOL_BUTTON_NO_XSIZE TOOL_BUTTON_YES_XSIZE
2239 #define TOOL_BUTTON_NO_YSIZE TOOL_BUTTON_YES_YSIZE
2240 #define TOOL_BUTTON_CONFIRM_XPOS TOOL_BUTTON_YES_XPOS
2241 #define TOOL_BUTTON_CONFIRM_YPOS TOOL_BUTTON_YES_YPOS
2242 #define TOOL_BUTTON_CONFIRM_GFX_YPOS 30
2243 #define TOOL_BUTTON_CONFIRM_XSIZE 96
2244 #define TOOL_BUTTON_CONFIRM_YSIZE TOOL_BUTTON_YES_YSIZE
2245 #define TOOL_BUTTON_PLAYER_XSIZE 30
2246 #define TOOL_BUTTON_PLAYER_YSIZE 30
2247 #define TOOL_BUTTON_PLAYER_GFX_XPOS 5
2248 #define TOOL_BUTTON_PLAYER_GFX_YPOS 185
2249 #define TOOL_BUTTON_PLAYER_XPOS (5 + TOOL_BUTTON_PLAYER_XSIZE / 2)
2250 #define TOOL_BUTTON_PLAYER_YPOS (215 - TOOL_BUTTON_PLAYER_YSIZE / 2)
2251 #define TOOL_BUTTON_PLAYER1_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2252 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2253 #define TOOL_BUTTON_PLAYER2_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2254 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2255 #define TOOL_BUTTON_PLAYER3_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2256 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2257 #define TOOL_BUTTON_PLAYER4_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2258 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2259 #define TOOL_BUTTON_PLAYER1_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2260 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2261 #define TOOL_BUTTON_PLAYER2_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2262 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2263 #define TOOL_BUTTON_PLAYER3_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2264 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2265 #define TOOL_BUTTON_PLAYER4_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2266 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2275 } toolbutton_info[NUM_TOOL_BUTTONS] =
2278 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_GFX_YPOS,
2279 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_YPOS,
2280 TOOL_BUTTON_YES_XSIZE, TOOL_BUTTON_YES_YSIZE,
2285 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_GFX_YPOS,
2286 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_YPOS,
2287 TOOL_BUTTON_NO_XSIZE, TOOL_BUTTON_NO_YSIZE,
2292 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_GFX_YPOS,
2293 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_YPOS,
2294 TOOL_BUTTON_CONFIRM_XSIZE, TOOL_BUTTON_CONFIRM_YSIZE,
2295 TOOL_CTRL_ID_CONFIRM,
2299 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2300 TOOL_BUTTON_PLAYER1_XPOS, TOOL_BUTTON_PLAYER1_YPOS,
2301 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2302 TOOL_CTRL_ID_PLAYER_1,
2306 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2307 TOOL_BUTTON_PLAYER2_XPOS, TOOL_BUTTON_PLAYER2_YPOS,
2308 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2309 TOOL_CTRL_ID_PLAYER_2,
2313 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2314 TOOL_BUTTON_PLAYER3_XPOS, TOOL_BUTTON_PLAYER3_YPOS,
2315 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2316 TOOL_CTRL_ID_PLAYER_3,
2320 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2321 TOOL_BUTTON_PLAYER4_XPOS, TOOL_BUTTON_PLAYER4_YPOS,
2322 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2323 TOOL_CTRL_ID_PLAYER_4,
2328 void CreateToolButtons()
2332 for (i=0; i<NUM_TOOL_BUTTONS; i++)
2334 Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
2335 Bitmap *deco_bitmap = None;
2336 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
2337 struct GadgetInfo *gi;
2338 unsigned long event_mask;
2339 int gd_xoffset, gd_yoffset;
2340 int gd_x1, gd_x2, gd_y;
2343 event_mask = GD_EVENT_RELEASED;
2345 gd_xoffset = toolbutton_info[i].xpos;
2346 gd_yoffset = toolbutton_info[i].ypos;
2347 gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
2348 gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
2349 gd_y = DOOR_GFX_PAGEY1 + gd_yoffset;
2351 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
2353 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
2355 getMiniGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr),
2356 &deco_bitmap, &deco_x, &deco_y);
2357 deco_xpos = (toolbutton_info[i].width - MINI_TILEX) / 2;
2358 deco_ypos = (toolbutton_info[i].height - MINI_TILEY) / 2;
2361 gi = CreateGadget(GDI_CUSTOM_ID, id,
2362 GDI_INFO_TEXT, toolbutton_info[i].infotext,
2363 GDI_X, DX + toolbutton_info[i].x,
2364 GDI_Y, DY + toolbutton_info[i].y,
2365 GDI_WIDTH, toolbutton_info[i].width,
2366 GDI_HEIGHT, toolbutton_info[i].height,
2367 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
2368 GDI_STATE, GD_BUTTON_UNPRESSED,
2369 GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
2370 GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
2371 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
2372 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
2373 GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
2374 GDI_DECORATION_SHIFTING, 1, 1,
2375 GDI_EVENT_MASK, event_mask,
2376 GDI_CALLBACK_ACTION, HandleToolButtons,
2380 Error(ERR_EXIT, "cannot create gadget");
2382 tool_gadget[id] = gi;
2386 void FreeToolButtons()
2390 for (i=0; i<NUM_TOOL_BUTTONS; i++)
2391 FreeGadget(tool_gadget[i]);
2394 static void UnmapToolButtons()
2398 for (i=0; i<NUM_TOOL_BUTTONS; i++)
2399 UnmapGadget(tool_gadget[i]);
2402 static void HandleToolButtons(struct GadgetInfo *gi)
2404 request_gadget_id = gi->custom_id;
2407 int get_next_element(int element)
2411 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
2412 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
2413 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
2414 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
2415 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
2416 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
2417 case EL_AMOEBA_DROPPING: return EL_AMOEBA_WET;
2419 default: return element;
2423 int el_act_dir2img(int element, int action, int direction)
2425 element = GFX_ELEMENT(element);
2426 direction = MV_DIR_BIT(direction);
2428 return element_info[element].direction_graphic[action][direction];
2431 int el_act2img(int element, int action)
2433 element = GFX_ELEMENT(element);
2435 return element_info[element].graphic[action];
2438 int el_dir2img(int element, int direction)
2440 element = GFX_ELEMENT(element);
2442 return el_act_dir2img(element, ACTION_DEFAULT, direction);
2445 int el2img(int element)
2447 element = GFX_ELEMENT(element);
2449 return element_info[element].graphic[ACTION_DEFAULT];
2452 int el2edimg(int element)
2454 element = GFX_ELEMENT(element);
2456 return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
2459 int el2preimg(int element)
2461 element = GFX_ELEMENT(element);
2463 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];