1 /***********************************************************
2 * Rocks'n'Diamonds -- McDuffin Strikes Back! *
3 *----------------------------------------------------------*
4 * (c) 1995-2002 Artsoft Entertainment *
6 * Detmolder Strasse 189 *
9 * e-mail: info@artsoft.org *
10 *----------------------------------------------------------*
12 ***********************************************************/
14 #include "libgame/libgame.h"
23 /* tool button identifiers */
24 #define TOOL_CTRL_ID_YES 0
25 #define TOOL_CTRL_ID_NO 1
26 #define TOOL_CTRL_ID_CONFIRM 2
27 #define TOOL_CTRL_ID_PLAYER_1 3
28 #define TOOL_CTRL_ID_PLAYER_2 4
29 #define TOOL_CTRL_ID_PLAYER_3 5
30 #define TOOL_CTRL_ID_PLAYER_4 6
32 #define NUM_TOOL_BUTTONS 7
34 /* forward declaration for internal use */
35 static void UnmapToolButtons();
36 static void HandleToolButtons(struct GadgetInfo *);
38 static struct GadgetInfo *tool_gadget[NUM_TOOL_BUTTONS];
39 static int request_gadget_id = -1;
41 void SetDrawtoField(int mode)
43 if (mode == DRAW_BUFFERED && setup.soft_scrolling)
54 drawto_field = fieldbuffer;
56 else /* DRAW_DIRECT, DRAW_BACKBUFFER */
67 drawto_field = (mode == DRAW_DIRECT ? window : backbuffer);
71 void RedrawPlayfield(boolean force_redraw, int x, int y, int width, int height)
73 if (game_status == GAME_MODE_PLAYING)
79 width = gfx.sxsize + 2 * TILEX;
80 height = gfx.sysize + 2 * TILEY;
83 if (force_redraw || setup.direct_draw)
86 int x1 = (x - SX) / TILEX, y1 = (y - SY) / TILEY;
87 int x2 = (x - SX + width) / TILEX, y2 = (y - SY + height) / TILEY;
89 if (setup.direct_draw)
90 SetDrawtoField(DRAW_BACKBUFFER);
92 for(xx=BX1; xx<=BX2; xx++)
93 for(yy=BY1; yy<=BY2; yy++)
94 if (xx >= x1 && xx <= x2 && yy >= y1 && yy <= y2)
95 DrawScreenField(xx, yy);
98 if (setup.direct_draw)
99 SetDrawtoField(DRAW_DIRECT);
102 if (setup.soft_scrolling)
104 int fx = FX, fy = FY;
106 fx += (ScreenMovDir & (MV_LEFT|MV_RIGHT) ? ScreenGfxPos : 0);
107 fy += (ScreenMovDir & (MV_UP|MV_DOWN) ? ScreenGfxPos : 0);
109 BlitBitmap(fieldbuffer, backbuffer, fx,fy, SXSIZE,SYSIZE, SX,SY);
113 BlitBitmap(drawto, window, x, y, width, height, x, y);
119 DrawBuffer *buffer = (drawto_field == window ? backbuffer : drawto_field);
121 if (setup.direct_draw && game_status == GAME_MODE_PLAYING)
122 redraw_mask &= ~REDRAW_MAIN;
124 if (redraw_mask & REDRAW_TILES && redraw_tiles > REDRAWTILES_THRESHOLD)
125 redraw_mask |= REDRAW_FIELD;
127 if (redraw_mask & REDRAW_FIELD)
128 redraw_mask &= ~REDRAW_TILES;
130 if (redraw_mask == REDRAW_NONE)
133 if (global.fps_slowdown && game_status == GAME_MODE_PLAYING)
135 static boolean last_frame_skipped = FALSE;
136 boolean skip_even_when_not_scrolling = TRUE;
137 boolean just_scrolling = (ScreenMovDir != 0);
138 boolean verbose = FALSE;
140 if (global.fps_slowdown_factor > 1 &&
141 (FrameCounter % global.fps_slowdown_factor) &&
142 (just_scrolling || skip_even_when_not_scrolling))
144 redraw_mask &= ~REDRAW_MAIN;
146 last_frame_skipped = TRUE;
149 printf("FRAME SKIPPED\n");
153 if (last_frame_skipped)
154 redraw_mask |= REDRAW_FIELD;
156 last_frame_skipped = FALSE;
159 printf("frame not skipped\n");
163 /* synchronize X11 graphics at this point; if we would synchronize the
164 display immediately after the buffer switching (after the XFlush),
165 this could mean that we have to wait for the graphics to complete,
166 although we could go on doing calculations for the next frame */
170 if (redraw_mask & REDRAW_ALL)
172 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
176 if (redraw_mask & REDRAW_FIELD)
178 if (game_status != GAME_MODE_PLAYING ||
179 redraw_mask & REDRAW_FROM_BACKBUFFER)
181 BlitBitmap(backbuffer, window,
182 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE, REAL_SX, REAL_SY);
186 int fx = FX, fy = FY;
188 if (setup.soft_scrolling)
190 fx += (ScreenMovDir & (MV_LEFT | MV_RIGHT) ? ScreenGfxPos : 0);
191 fy += (ScreenMovDir & (MV_UP | MV_DOWN) ? ScreenGfxPos : 0);
194 if (setup.soft_scrolling ||
195 ABS(ScreenMovPos) + ScrollStepSize == TILEX ||
196 ABS(ScreenMovPos) == ScrollStepSize ||
197 redraw_tiles > REDRAWTILES_THRESHOLD)
199 BlitBitmap(buffer, window, fx, fy, SXSIZE, SYSIZE, SX, SY);
203 printf("redrawing all (ScreenGfxPos == %d) because %s\n",
205 (setup.soft_scrolling ?
206 "setup.soft_scrolling" :
207 ABS(ScreenGfxPos) + ScrollStepSize == TILEX ?
208 "ABS(ScreenGfxPos) + ScrollStepSize == TILEX" :
209 ABS(ScreenGfxPos) == ScrollStepSize ?
210 "ABS(ScreenGfxPos) == ScrollStepSize" :
211 "redraw_tiles > REDRAWTILES_THRESHOLD"));
217 redraw_mask &= ~REDRAW_MAIN;
220 if (redraw_mask & REDRAW_DOORS)
222 if (redraw_mask & REDRAW_DOOR_1)
223 BlitBitmap(backbuffer, window, DX, DY, DXSIZE, DYSIZE, DX, DY);
224 if (redraw_mask & REDRAW_DOOR_2)
226 if ((redraw_mask & REDRAW_DOOR_2) == REDRAW_DOOR_2)
227 BlitBitmap(backbuffer, window, VX,VY, VXSIZE,VYSIZE, VX,VY);
230 if (redraw_mask & REDRAW_VIDEO_1)
231 BlitBitmap(backbuffer, window,
232 VX+VIDEO_DISPLAY1_XPOS,VY+VIDEO_DISPLAY1_YPOS,
233 VIDEO_DISPLAY_XSIZE,VIDEO_DISPLAY_YSIZE,
234 VX+VIDEO_DISPLAY1_XPOS,VY+VIDEO_DISPLAY1_YPOS);
235 if (redraw_mask & REDRAW_VIDEO_2)
236 BlitBitmap(backbuffer, window,
237 VX+VIDEO_DISPLAY2_XPOS,VY+VIDEO_DISPLAY2_YPOS,
238 VIDEO_DISPLAY_XSIZE,VIDEO_DISPLAY_YSIZE,
239 VX+VIDEO_DISPLAY2_XPOS,VY+VIDEO_DISPLAY2_YPOS);
240 if (redraw_mask & REDRAW_VIDEO_3)
241 BlitBitmap(backbuffer, window,
242 VX+VIDEO_CONTROL_XPOS,VY+VIDEO_CONTROL_YPOS,
243 VIDEO_CONTROL_XSIZE,VIDEO_CONTROL_YSIZE,
244 VX+VIDEO_CONTROL_XPOS,VY+VIDEO_CONTROL_YPOS);
248 if (redraw_mask & REDRAW_DOOR_3)
249 BlitBitmap(backbuffer, window, EX, EY, EXSIZE, EYSIZE, EX, EY);
251 redraw_mask &= ~REDRAW_DOORS;
254 if (redraw_mask & REDRAW_MICROLEVEL)
256 BlitBitmap(backbuffer, window, SX, SY + 10 * TILEY, SXSIZE, 7 * TILEY,
257 SX, SY + 10 * TILEY);
259 redraw_mask &= ~REDRAW_MICROLEVEL;
262 if (redraw_mask & REDRAW_TILES)
264 for(x=0; x<SCR_FIELDX; x++)
265 for(y=0; y<SCR_FIELDY; y++)
266 if (redraw[redraw_x1 + x][redraw_y1 + y])
267 BlitBitmap(buffer, window,
268 FX + x * TILEX, FX + y * TILEY, TILEX, TILEY,
269 SX + x * TILEX, SY + y * TILEY);
272 if (redraw_mask & REDRAW_FPS) /* display frames per second */
277 sprintf(info1, " (only every %d. frame)", global.fps_slowdown_factor);
278 if (!global.fps_slowdown)
281 sprintf(text, "%.1f fps%s", global.frames_per_second, info1);
282 DrawTextExt(window, SX, SY, text, FONT_TEXT_2, BLIT_OPAQUE);
287 for(x=0; x<MAX_BUF_XSIZE; x++)
288 for(y=0; y<MAX_BUF_YSIZE; y++)
291 redraw_mask = REDRAW_NONE;
297 long fading_delay = 300;
299 if (setup.fading && (redraw_mask & REDRAW_FIELD))
306 ClearRectangle(window, REAL_SX,REAL_SY,FULL_SXSIZE,FULL_SYSIZE);
309 for(i=0;i<2*FULL_SYSIZE;i++)
311 for(y=0;y<FULL_SYSIZE;y++)
313 BlitBitmap(backbuffer, window,
314 REAL_SX,REAL_SY+i, FULL_SXSIZE,1, REAL_SX,REAL_SY+i);
322 for(i=1;i<FULL_SYSIZE;i+=2)
323 BlitBitmap(backbuffer, window,
324 REAL_SX,REAL_SY+i, FULL_SXSIZE,1, REAL_SX,REAL_SY+i);
330 SetClipOrigin(clip_gc[PIX_FADEMASK], 0, 0);
331 BlitBitmapMasked(backbuffer, window,
332 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
337 SetClipOrigin(clip_gc[PIX_FADEMASK], -1, -1);
338 BlitBitmapMasked(backbuffer, window,
339 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
344 SetClipOrigin(clip_gc[PIX_FADEMASK], 0, -1);
345 BlitBitmapMasked(backbuffer, window,
346 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
351 SetClipOrigin(clip_gc[PIX_FADEMASK], -1, 0);
352 BlitBitmapMasked(backbuffer, window,
353 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
358 redraw_mask &= ~REDRAW_MAIN;
365 void SetMainBackgroundImage(int graphic)
367 SetMainBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
368 graphic_info[graphic].bitmap ?
369 graphic_info[graphic].bitmap :
370 graphic_info[IMG_BACKGROUND].bitmap);
373 void SetDoorBackgroundImage(int graphic)
375 SetDoorBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
376 graphic_info[graphic].bitmap ?
377 graphic_info[graphic].bitmap :
378 graphic_info[IMG_BACKGROUND].bitmap);
381 void DrawBackground(int dest_x, int dest_y, int width, int height)
383 ClearRectangleOnBackground(backbuffer, dest_x, dest_y, width, height);
385 redraw_mask |= REDRAW_FIELD;
390 DrawBackground(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
392 if (setup.soft_scrolling && game_status == GAME_MODE_PLAYING)
394 ClearRectangle(fieldbuffer, 0, 0, FXSIZE, FYSIZE);
395 SetDrawtoField(DRAW_BUFFERED);
398 SetDrawtoField(DRAW_BACKBUFFER);
400 if (setup.direct_draw && game_status == GAME_MODE_PLAYING)
402 ClearRectangle(window, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
403 SetDrawtoField(DRAW_DIRECT);
407 void MarkTileDirty(int x, int y)
409 int xx = redraw_x1 + x;
410 int yy = redraw_y1 + y;
415 redraw[xx][yy] = TRUE;
416 redraw_mask |= REDRAW_TILES;
419 void SetBorderElement()
423 BorderElement = EL_EMPTY;
425 for(y=0; y<lev_fieldy && BorderElement == EL_EMPTY; y++)
427 for(x=0; x<lev_fieldx; x++)
429 if (!IS_INDESTRUCTIBLE(Feld[x][y]))
430 BorderElement = EL_STEELWALL;
432 if (y != 0 && y != lev_fieldy - 1 && x != lev_fieldx - 1)
438 void SetRandomAnimationValue(int x, int y)
440 gfx.anim_random_frame = GfxRandom[x][y];
443 inline int getGraphicAnimationFrame(int graphic, int sync_frame)
445 /* animation synchronized with global frame counter, not move position */
446 if (graphic_info[graphic].anim_global_sync || sync_frame < 0)
447 sync_frame = FrameCounter;
449 return getAnimationFrame(graphic_info[graphic].anim_frames,
450 graphic_info[graphic].anim_delay,
451 graphic_info[graphic].anim_mode,
452 graphic_info[graphic].anim_start_frame,
456 inline void DrawGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
457 int graphic, int sync_frame, int mask_mode)
459 int frame = getGraphicAnimationFrame(graphic, sync_frame);
461 if (mask_mode == USE_MASKING)
462 DrawGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
464 DrawGraphicExt(dst_bitmap, x, y, graphic, frame);
467 inline void DrawGraphicAnimation(int x, int y, int graphic)
469 int lx = LEVELX(x), ly = LEVELY(y);
471 if (!IN_SCR_FIELD(x, y))
474 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
475 graphic, GfxFrame[lx][ly], NO_MASKING);
479 void DrawLevelGraphicAnimation(int x, int y, int graphic)
481 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
484 void DrawLevelElementAnimation(int x, int y, int element)
487 int graphic = el_act_dir2img(element, GfxAction[x][y], MovDir[x][y]);
489 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
491 DrawGraphicAnimation(SCREENX(x), SCREENY(y), el2img(element));
495 inline void DrawLevelGraphicAnimationIfNeeded(int x, int y, int graphic)
497 int sx = SCREENX(x), sy = SCREENY(y);
499 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
502 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
505 DrawGraphicAnimation(sx, sy, graphic);
508 void DrawLevelElementAnimationIfNeeded(int x, int y, int element)
510 int sx = SCREENX(x), sy = SCREENY(y);
513 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
516 graphic = el_act_dir2img(element, GfxAction[x][y], MovDir[x][y]);
518 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
521 DrawGraphicAnimation(sx, sy, graphic);
524 void DrawAllPlayers()
528 for(i=0; i<MAX_PLAYERS; i++)
529 if (stored_player[i].active)
530 DrawPlayer(&stored_player[i]);
533 void DrawPlayerField(int x, int y)
535 if (!IS_PLAYER(x, y))
538 DrawPlayer(PLAYERINFO(x, y));
541 void DrawPlayer(struct PlayerInfo *player)
543 int jx = player->jx, jy = player->jy;
544 int last_jx = player->last_jx, last_jy = player->last_jy;
545 int next_jx = jx + (jx - last_jx), next_jy = jy + (jy - last_jy);
546 int sx = SCREENX(jx), sy = SCREENY(jy);
547 int sxx = 0, syy = 0;
548 int element = Feld[jx][jy], last_element = Feld[last_jx][last_jy];
551 boolean player_is_moving = (last_jx != jx || last_jy != jy ? TRUE : FALSE);
552 int move_dir = player->MovDir;
553 int action = ACTION_DEFAULT;
555 if (!player->active || !IN_SCR_FIELD(SCREENX(last_jx), SCREENY(last_jy)))
559 if (!IN_LEV_FIELD(jx,jy))
561 printf("DrawPlayerField(): x = %d, y = %d\n",jx,jy);
562 printf("DrawPlayerField(): sx = %d, sy = %d\n",sx,sy);
563 printf("DrawPlayerField(): This should never happen!\n");
568 if (element == EL_EXPLOSION)
571 action = (player->Pushing ? ACTION_PUSHING :
572 player->is_digging ? ACTION_DIGGING :
573 player->is_collecting ? ACTION_COLLECTING :
574 player->is_moving ? ACTION_MOVING :
575 player->snapped ? ACTION_SNAPPING : ACTION_DEFAULT);
577 InitPlayerGfxAnimation(player, action, move_dir);
579 /* ----------------------------------------------------------------------- */
580 /* draw things in the field the player is leaving, if needed */
581 /* ----------------------------------------------------------------------- */
583 if (player_is_moving)
585 if (Back[last_jx][last_jy] && IS_DRAWABLE(last_element))
587 DrawLevelElement(last_jx, last_jy, Back[last_jx][last_jy]);
589 if (last_element == EL_DYNAMITE_ACTIVE ||
590 last_element == EL_SP_DISK_RED_ACTIVE)
591 DrawDynamite(last_jx, last_jy);
593 DrawLevelFieldThruMask(last_jx, last_jy);
595 else if (last_element == EL_DYNAMITE_ACTIVE ||
596 last_element == EL_SP_DISK_RED_ACTIVE)
597 DrawDynamite(last_jx, last_jy);
599 DrawLevelField(last_jx, last_jy);
601 if (player->Pushing && IN_SCR_FIELD(SCREENX(next_jx), SCREENY(next_jy)))
605 if (Feld[next_jx][next_jy] == EL_SOKOBAN_FIELD_FULL)
606 DrawLevelElement(next_jx, next_jy, EL_SOKOBAN_FIELD_EMPTY);
608 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
611 DrawLevelField(next_jx, next_jy);
615 if (!IN_SCR_FIELD(sx, sy))
618 if (setup.direct_draw)
619 SetDrawtoField(DRAW_BUFFERED);
621 /* ----------------------------------------------------------------------- */
622 /* draw things behind the player, if needed */
623 /* ----------------------------------------------------------------------- */
626 DrawLevelElement(jx, jy, Back[jx][jy]);
627 else if (IS_ACTIVE_BOMB(element))
628 DrawLevelElement(jx, jy, EL_EMPTY);
631 if (player_is_moving && GfxElement[jx][jy] != EL_UNDEFINED)
633 if (GfxElement[jx][jy] == EL_SAND)
634 DrawLevelFieldCrumbledSandDigging(jx, jy, move_dir, player->StepFrame);
637 int old_element = GfxElement[jx][jy];
638 int old_graphic = el_act_dir2img(old_element, action, move_dir);
639 int frame = getGraphicAnimationFrame(old_graphic, player->StepFrame);
641 DrawGraphic(sx, sy, old_graphic, frame);
646 GfxElement[jx][jy] = EL_UNDEFINED;
648 DrawLevelField(jx, jy);
652 /* ----------------------------------------------------------------------- */
653 /* draw player himself */
654 /* ----------------------------------------------------------------------- */
656 if (player->use_murphy_graphic)
658 static int last_horizontal_dir = MV_LEFT;
661 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
662 last_horizontal_dir = move_dir;
664 direction = (player->snapped ? move_dir : last_horizontal_dir);
666 graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, direction);
669 graphic = el_act_dir2img(player->element_nr, player->GfxAction, move_dir);
671 frame = getGraphicAnimationFrame(graphic, player->Frame);
675 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
676 sxx = player->GfxPos;
678 syy = player->GfxPos;
681 if (!setup.soft_scrolling && ScreenMovPos)
684 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
686 if (SHIELD_ON(player))
688 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
689 IMG_SHIELD_NORMAL_ACTIVE);
690 int frame = getGraphicAnimationFrame(graphic, -1);
692 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
695 /* ----------------------------------------------------------------------- */
696 /* draw things the player is pushing, if needed */
697 /* ----------------------------------------------------------------------- */
699 if (player->Pushing && player_is_moving)
701 int px = SCREENX(next_jx), py = SCREENY(next_jy);
704 (element == EL_SOKOBAN_FIELD_EMPTY ||
705 Feld[next_jx][next_jy] == EL_SOKOBAN_FIELD_FULL))
706 DrawGraphicShiftedThruMask(px, py, sxx, syy, IMG_SOKOBAN_OBJECT, 0,
710 int element = Feld[next_jx][next_jy];
711 int graphic = el2img(element);
714 if ((sxx || syy) && IS_PUSHABLE(element))
716 graphic = el_act_dir2img(element, ACTION_MOVING, move_dir);
717 frame = getGraphicAnimationFrame(graphic, player->Frame);
720 DrawGraphicShifted(px, py, sxx, syy, graphic, frame,
721 NO_CUTTING, NO_MASKING);
725 /* ----------------------------------------------------------------------- */
726 /* draw things in front of player (active dynamite or dynabombs) */
727 /* ----------------------------------------------------------------------- */
729 if (IS_ACTIVE_BOMB(element))
731 graphic = el2img(element);
732 frame = getGraphicAnimationFrame(graphic, GfxFrame[jx][jy]);
734 if (game.emulation == EMU_SUPAPLEX)
735 DrawGraphic(sx, sy, IMG_SP_DISK_RED, frame);
737 DrawGraphicThruMask(sx, sy, graphic, frame);
740 if (player_is_moving && last_element == EL_EXPLOSION)
743 int graphic = el_act2img(GfxElement[last_jx][last_jy], ACTION_EXPLODING);
745 int stored = Store[last_jx][last_jy];
746 int graphic = (game.emulation != EMU_SUPAPLEX ? IMG_EXPLOSION :
747 stored == EL_SP_INFOTRON ? IMG_SP_EXPLOSION_INFOTRON :
750 int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
751 int phase = ExplodePhase[last_jx][last_jy] - 1;
752 int frame = getGraphicAnimationFrame(graphic, phase - delay);
755 DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy), graphic, frame);
758 /* ----------------------------------------------------------------------- */
759 /* draw elements the player is just walking/passing through/under */
760 /* ----------------------------------------------------------------------- */
762 /* handle the field the player is leaving ... */
763 if (player_is_moving && IS_ACCESSIBLE_INSIDE(last_element))
764 DrawLevelField(last_jx, last_jy);
765 else if (player_is_moving && IS_ACCESSIBLE_UNDER(last_element))
766 DrawLevelFieldThruMask(last_jx, last_jy);
768 /* ... and the field the player is entering */
769 if (IS_ACCESSIBLE_INSIDE(element))
770 DrawLevelField(jx, jy);
771 else if (IS_ACCESSIBLE_UNDER(element))
772 DrawLevelFieldThruMask(jx, jy);
774 if (setup.direct_draw)
776 int dest_x = SX + SCREENX(MIN(jx, last_jx)) * TILEX;
777 int dest_y = SY + SCREENY(MIN(jy, last_jy)) * TILEY;
778 int x_size = TILEX * (1 + ABS(jx - last_jx));
779 int y_size = TILEY * (1 + ABS(jy - last_jy));
781 BlitBitmap(drawto_field, window,
782 dest_x, dest_y, x_size, y_size, dest_x, dest_y);
783 SetDrawtoField(DRAW_DIRECT);
786 MarkTileDirty(sx,sy);
789 void getGraphicSource(int graphic, int frame, Bitmap **bitmap, int *x, int *y)
791 struct GraphicInfo *g = &graphic_info[graphic];
795 if (g->offset_y == 0) /* frames are ordered horizontally */
797 int max_width = g->anim_frames_per_line * g->width;
799 *x = (g->src_x + frame * g->offset_x) % max_width;
800 *y = g->src_y + (g->src_x + frame * g->offset_x) / max_width * g->height;
802 else if (g->offset_x == 0) /* frames are ordered vertically */
804 int max_height = g->anim_frames_per_line * g->height;
806 *x = g->src_x + (g->src_y + frame * g->offset_y) / max_height * g->width;
807 *y = (g->src_y + frame * g->offset_y) % max_height;
809 else /* frames are ordered diagonally */
811 *x = g->src_x + frame * g->offset_x;
812 *y = g->src_y + frame * g->offset_y;
816 void DrawGraphic(int x, int y, int graphic, int frame)
819 if (!IN_SCR_FIELD(x, y))
821 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
822 printf("DrawGraphic(): This should never happen!\n");
827 DrawGraphicExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic, frame);
832 void DrawOldGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic)
837 getOldGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
838 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
842 void DrawGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
849 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
851 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
852 int src_x = graphic_info[graphic].src_x;
853 int src_y = graphic_info[graphic].src_y;
854 int offset_x = graphic_info[graphic].offset_x;
855 int offset_y = graphic_info[graphic].offset_y;
857 src_x += frame * offset_x;
858 src_y += frame * offset_y;
861 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
864 void DrawGraphicThruMask(int x, int y, int graphic, int frame)
867 if (!IN_SCR_FIELD(x, y))
869 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
870 printf("DrawGraphicThruMask(): This should never happen!\n");
875 DrawGraphicThruMaskExt(drawto_field, FX + x * TILEX, FY + y *TILEY, graphic,
880 void DrawGraphicThruMaskExt(DrawBuffer *d, int dest_x, int dest_y, int graphic,
888 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
889 drawing_gc = src_bitmap->stored_clip_gc;
891 GC drawing_gc = src_bitmap->stored_clip_gc;
892 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
893 int src_x = graphic_info[graphic].src_x;
894 int src_y = graphic_info[graphic].src_y;
895 int offset_x = graphic_info[graphic].offset_x;
896 int offset_y = graphic_info[graphic].offset_y;
898 src_x += frame * offset_x;
899 src_y += frame * offset_y;
903 SetClipOrigin(src_bitmap, drawing_gc, dest_x - src_x, dest_y - src_y);
904 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX, TILEY, dest_x, dest_y);
907 void DrawMiniGraphic(int x, int y, int graphic)
909 DrawMiniGraphicExt(drawto, SX + x * MINI_TILEX,SY + y * MINI_TILEY, graphic);
910 MarkTileDirty(x / 2, y / 2);
913 void getMiniGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
915 struct GraphicInfo *g = &graphic_info[graphic];
917 int mini_starty = g->bitmap->height * 2 / 3;
920 *x = mini_startx + g->src_x / 2;
921 *y = mini_starty + g->src_y / 2;
924 void DrawMiniGraphicExt(DrawBuffer *d, int x, int y, int graphic)
929 getMiniGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
930 BlitBitmap(src_bitmap, d, src_x, src_y, MINI_TILEX, MINI_TILEY, x, y);
933 void DrawGraphicShifted(int x,int y, int dx,int dy, int graphic, int frame,
934 int cut_mode, int mask_mode)
939 int width = TILEX, height = TILEY;
945 DrawGraphic(x, y, graphic, frame);
949 if (dx || dy) /* shifted graphic */
951 if (x < BX1) /* object enters playfield from the left */
958 else if (x > BX2) /* object enters playfield from the right */
964 else if (x==BX1 && dx < 0) /* object leaves playfield to the left */
970 else if (x==BX2 && dx > 0) /* object leaves playfield to the right */
972 else if (dx) /* general horizontal movement */
973 MarkTileDirty(x + SIGN(dx), y);
975 if (y < BY1) /* object enters playfield from the top */
977 if (cut_mode==CUT_BELOW) /* object completely above top border */
985 else if (y > BY2) /* object enters playfield from the bottom */
991 else if (y==BY1 && dy < 0) /* object leaves playfield to the top */
997 else if (dy > 0 && cut_mode == CUT_ABOVE)
999 if (y == BY2) /* object completely above bottom border */
1005 MarkTileDirty(x, y + 1);
1006 } /* object leaves playfield to the bottom */
1007 else if (dy > 0 && (y == BY2 || cut_mode == CUT_BELOW))
1009 else if (dy) /* general vertical movement */
1010 MarkTileDirty(x, y + SIGN(dy));
1014 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1016 src_bitmap = graphic_info[graphic].bitmap;
1017 src_x = graphic_info[graphic].src_x;
1018 src_y = graphic_info[graphic].src_y;
1019 offset_x = graphic_info[graphic].offset_x;
1020 offset_y = graphic_info[graphic].offset_y;
1022 src_x += frame * offset_x;
1023 src_y += frame * offset_y;
1026 drawing_gc = src_bitmap->stored_clip_gc;
1031 dest_x = FX + x * TILEX + dx;
1032 dest_y = FY + y * TILEY + dy;
1035 if (!IN_SCR_FIELD(x,y))
1037 printf("DrawGraphicShifted(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
1038 printf("DrawGraphicShifted(): This should never happen!\n");
1043 if (mask_mode == USE_MASKING)
1045 SetClipOrigin(src_bitmap, drawing_gc, dest_x - src_x, dest_y - src_y);
1046 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1050 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1056 void DrawGraphicShiftedThruMask(int x, int y, int dx, int dy, int graphic,
1057 int frame, int cut_mode)
1059 DrawGraphicShifted(x,y, dx,dy, graphic, frame, cut_mode, USE_MASKING);
1062 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
1063 int cut_mode, int mask_mode)
1065 int lx = LEVELX(x), ly = LEVELY(y);
1069 if (IN_LEV_FIELD(lx, ly))
1071 SetRandomAnimationValue(lx, ly);
1073 graphic = el_act_dir2img(element, GfxAction[lx][ly], MovDir[lx][ly]);
1074 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1076 else /* border element */
1078 graphic = el2img(element);
1079 frame = getGraphicAnimationFrame(graphic, -1);
1082 if (element == EL_EXPANDABLE_WALL)
1084 boolean left_stopped = FALSE, right_stopped = FALSE;
1086 if (!IN_LEV_FIELD(lx - 1, ly) || IS_WALL(Feld[lx - 1][ly]))
1087 left_stopped = TRUE;
1088 if (!IN_LEV_FIELD(lx + 1, ly) || IS_WALL(Feld[lx + 1][ly]))
1089 right_stopped = TRUE;
1091 if (left_stopped && right_stopped)
1093 else if (left_stopped)
1095 graphic = IMG_EXPANDABLE_WALL_GROWING_RIGHT;
1096 frame = graphic_info[graphic].anim_frames - 1;
1098 else if (right_stopped)
1100 graphic = IMG_EXPANDABLE_WALL_GROWING_LEFT;
1101 frame = graphic_info[graphic].anim_frames - 1;
1105 else if (IS_AMOEBOID(element) || element == EL_AMOEBA_DROPPING)
1107 graphic = (element == EL_BD_AMOEBA ? IMG_BD_AMOEBA_PART1 :
1108 element == EL_AMOEBA_WET ? IMG_AMOEBA_WET_PART1 :
1109 element == EL_AMOEBA_DRY ? IMG_AMOEBA_DRY_PART1 :
1110 element == EL_AMOEBA_FULL ? IMG_AMOEBA_FULL_PART1 :
1111 IMG_AMOEBA_DEAD_PART1);
1113 graphic += (x + 2 * y + 4) % 4;
1118 if (IS_AMOEBOID(element) || element == EL_AMOEBA_DROPPING)
1120 if (Feld[lx][ly] == EL_AMOEBA_DROPPING)
1121 printf("---> %d -> %d / %d [%d]\n",
1122 element, graphic, frame, GfxRandom[lx][ly]);
1127 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, mask_mode);
1128 else if (mask_mode == USE_MASKING)
1129 DrawGraphicThruMask(x, y, graphic, frame);
1131 DrawGraphic(x, y, graphic, frame);
1134 void DrawLevelElementExt(int x, int y, int dx, int dy, int element,
1135 int cut_mode, int mask_mode)
1137 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1138 DrawScreenElementExt(SCREENX(x), SCREENY(y), dx, dy, element,
1139 cut_mode, mask_mode);
1142 void DrawScreenElementShifted(int x, int y, int dx, int dy, int element,
1145 DrawScreenElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1148 void DrawLevelElementShifted(int x, int y, int dx, int dy, int element,
1151 DrawLevelElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1155 void DrawOldScreenElementThruMask(int x, int y, int element)
1157 DrawOldScreenElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1160 void DrawScreenElementThruMask(int x, int y, int element)
1162 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1166 void DrawLevelElementThruMask(int x, int y, int element)
1168 DrawLevelElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1171 void DrawLevelFieldThruMask(int x, int y)
1173 DrawLevelElementExt(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
1176 static void DrawLevelFieldCrumbledSandExt(int x, int y, int graphic, int frame)
1180 int sx = SCREENX(x), sy = SCREENY(y);
1182 int width, height, cx, cy, i;
1183 int snip = TILEX / 8; /* number of border pixels from "crumbled graphic" */
1184 static int xy[4][2] =
1192 if (!IN_LEV_FIELD(x, y))
1195 element = (GfxElement[x][y] != EL_UNDEFINED ? GfxElement[x][y] : Feld[x][y]);
1197 /* crumble field itself */
1198 if (CAN_BE_CRUMBLED(element) && !IS_MOVING(x, y))
1200 if (!IN_SCR_FIELD(sx, sy))
1203 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1207 int xx = x + xy[i][0];
1208 int yy = y + xy[i][1];
1210 element = (IN_LEV_FIELD(xx, yy) ? Feld[xx][yy] : EL_STEELWALL);
1212 /* check if neighbour field is of same type */
1213 if (CAN_BE_CRUMBLED(element) && !IS_MOVING(xx, yy))
1216 if (i == 1 || i == 2)
1220 cx = (i == 2 ? TILEX - snip : 0);
1228 cy = (i == 3 ? TILEY - snip : 0);
1231 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1232 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
1235 MarkTileDirty(sx, sy);
1237 else /* crumble neighbour fields */
1239 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1243 int xx = x + xy[i][0];
1244 int yy = y + xy[i][1];
1245 int sxx = sx + xy[i][0];
1246 int syy = sy + xy[i][1];
1248 if (!IN_LEV_FIELD(xx, yy) ||
1249 !IN_SCR_FIELD(sxx, syy) ||
1250 !CAN_BE_CRUMBLED(Feld[xx][yy]) ||
1254 if (i == 1 || i == 2)
1258 cx = (i == 1 ? TILEX - snip : 0);
1266 cy = (i==0 ? TILEY-snip : 0);
1269 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1270 width, height, FX + sxx * TILEX + cx, FY + syy * TILEY + cy);
1272 MarkTileDirty(sxx, syy);
1277 void DrawLevelFieldCrumbledSand(int x, int y)
1279 DrawLevelFieldCrumbledSandExt(x, y, IMG_SAND_CRUMBLED, 0);
1282 void DrawLevelFieldCrumbledSandDigging(int x, int y, int direction,
1285 int graphic1 = el_act_dir2img(EL_SAND, ACTION_DIGGING, direction);
1286 int graphic2 = el_act_dir2img(EL_SAND_CRUMBLED, ACTION_DIGGING, direction);
1287 int frame1 = getGraphicAnimationFrame(graphic1, step_frame);
1288 int frame2 = getGraphicAnimationFrame(graphic2, step_frame);
1289 int sx = SCREENX(x), sy = SCREENY(y);
1291 DrawGraphic(sx, sy, graphic1, frame1);
1292 DrawLevelFieldCrumbledSandExt(x, y, graphic2, frame2);
1295 static int getBorderElement(int x, int y)
1299 { EL_STEELWALL_TOPLEFT, EL_INVISIBLE_STEELWALL_TOPLEFT },
1300 { EL_STEELWALL_TOPRIGHT, EL_INVISIBLE_STEELWALL_TOPRIGHT },
1301 { EL_STEELWALL_BOTTOMLEFT, EL_INVISIBLE_STEELWALL_BOTTOMLEFT },
1302 { EL_STEELWALL_BOTTOMRIGHT, EL_INVISIBLE_STEELWALL_BOTTOMRIGHT },
1303 { EL_STEELWALL_VERTICAL, EL_INVISIBLE_STEELWALL_VERTICAL },
1304 { EL_STEELWALL_HORIZONTAL, EL_INVISIBLE_STEELWALL_HORIZONTAL },
1305 { EL_STEELWALL, EL_INVISIBLE_STEELWALL }
1307 int steel_type = (BorderElement == EL_STEELWALL ? 0 : 1);
1308 int steel_position = (x == -1 && y == -1 ? 0 :
1309 x == lev_fieldx && y == -1 ? 1 :
1310 x == -1 && y == lev_fieldy ? 2 :
1311 x == lev_fieldx && y == lev_fieldy ? 3 :
1312 x == -1 || x == lev_fieldx ? 4 :
1313 y == -1 || y == lev_fieldy ? 5 : 6);
1315 return border[steel_position][steel_type];
1318 void DrawScreenElement(int x, int y, int element)
1320 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
1321 DrawLevelFieldCrumbledSand(LEVELX(x), LEVELY(y));
1324 void DrawLevelElement(int x, int y, int element)
1326 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1327 DrawScreenElement(SCREENX(x), SCREENY(y), element);
1330 void DrawScreenField(int x, int y)
1332 int lx = LEVELX(x), ly = LEVELY(y);
1333 int element, content;
1335 if (!IN_LEV_FIELD(lx, ly))
1337 if (lx < -1 || lx > lev_fieldx || ly < -1 || ly > lev_fieldy)
1340 element = getBorderElement(lx, ly);
1342 DrawScreenElement(x, y, element);
1346 element = Feld[lx][ly];
1347 content = Store[lx][ly];
1349 if (IS_MOVING(lx, ly))
1351 int horiz_move = (MovDir[lx][ly] == MV_LEFT || MovDir[lx][ly] == MV_RIGHT);
1352 boolean cut_mode = NO_CUTTING;
1354 if (element == EL_QUICKSAND_EMPTYING ||
1355 element == EL_MAGIC_WALL_EMPTYING ||
1356 element == EL_BD_MAGIC_WALL_EMPTYING ||
1357 element == EL_AMOEBA_DROPPING)
1358 cut_mode = CUT_ABOVE;
1359 else if (element == EL_QUICKSAND_FILLING ||
1360 element == EL_MAGIC_WALL_FILLING ||
1361 element == EL_BD_MAGIC_WALL_FILLING)
1362 cut_mode = CUT_BELOW;
1364 if (cut_mode == CUT_ABOVE)
1365 DrawScreenElementShifted(x, y, 0, 0, element, NO_CUTTING);
1367 DrawScreenElement(x, y, EL_EMPTY);
1370 DrawScreenElementShifted(x, y, MovPos[lx][ly], 0, element, NO_CUTTING);
1371 else if (cut_mode == NO_CUTTING)
1372 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], element, cut_mode);
1374 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], content, cut_mode);
1376 if (content == EL_ACID)
1377 DrawLevelElementThruMask(lx, ly + 1, EL_ACID);
1379 else if (IS_BLOCKED(lx, ly))
1384 boolean cut_mode = NO_CUTTING;
1385 int element_old, content_old;
1387 Blocked2Moving(lx, ly, &oldx, &oldy);
1390 horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
1391 MovDir[oldx][oldy] == MV_RIGHT);
1393 element_old = Feld[oldx][oldy];
1394 content_old = Store[oldx][oldy];
1396 if (element_old == EL_QUICKSAND_EMPTYING ||
1397 element_old == EL_MAGIC_WALL_EMPTYING ||
1398 element_old == EL_BD_MAGIC_WALL_EMPTYING ||
1399 element_old == EL_AMOEBA_DROPPING)
1400 cut_mode = CUT_ABOVE;
1402 DrawScreenElement(x, y, EL_EMPTY);
1405 DrawScreenElementShifted(sx, sy, MovPos[oldx][oldy], 0, element_old,
1407 else if (cut_mode == NO_CUTTING)
1408 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], element_old,
1411 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], content_old,
1414 else if (IS_DRAWABLE(element))
1415 DrawScreenElement(x, y, element);
1417 DrawScreenElement(x, y, EL_EMPTY);
1420 void DrawLevelField(int x, int y)
1422 if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1423 DrawScreenField(SCREENX(x), SCREENY(y));
1424 else if (IS_MOVING(x, y))
1428 Moving2Blocked(x, y, &newx, &newy);
1429 if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
1430 DrawScreenField(SCREENX(newx), SCREENY(newy));
1432 else if (IS_BLOCKED(x, y))
1436 Blocked2Moving(x, y, &oldx, &oldy);
1437 if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
1438 DrawScreenField(SCREENX(oldx), SCREENY(oldy));
1442 void DrawMiniElement(int x, int y, int element)
1446 graphic = el2edimg(element);
1447 DrawMiniGraphic(x, y, graphic);
1450 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
1452 int x = sx + scroll_x, y = sy + scroll_y;
1454 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
1455 DrawMiniElement(sx, sy, EL_EMPTY);
1456 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
1457 DrawMiniElement(sx, sy, Feld[x][y]);
1459 DrawMiniGraphic(sx, sy, el2edimg(getBorderElement(x, y)));
1462 void getMicroGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
1464 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
1465 int mini_startx = src_bitmap->width * 3 / 4;
1466 int mini_starty = src_bitmap->height * 2 / 3;
1467 int src_x = mini_startx + graphic_info[graphic].src_x / 8;
1468 int src_y = mini_starty + graphic_info[graphic].src_y / 8;
1471 if (src_x + MICRO_TILEX > src_bitmap->width ||
1472 src_y + MICRO_TILEY > src_bitmap->height)
1474 /* graphic of desired size seems not to be contained in this image;
1475 dirty workaround: get it from the middle of the normal sized image */
1477 getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
1478 src_x += (TILEX / 2 - MICRO_TILEX / 2);
1479 src_y += (TILEY / 2 - MICRO_TILEY / 2);
1483 *bitmap = src_bitmap;
1488 void DrawMicroElement(int xpos, int ypos, int element)
1492 int graphic = el2preimg(element);
1494 getMicroGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
1495 BlitBitmap(src_bitmap, drawto, src_x, src_y, MICRO_TILEX, MICRO_TILEY,
1503 SetDrawBackgroundMask(REDRAW_NONE);
1506 for(x=BX1; x<=BX2; x++)
1507 for(y=BY1; y<=BY2; y++)
1508 DrawScreenField(x, y);
1510 redraw_mask |= REDRAW_FIELD;
1513 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
1517 for(x=0; x<size_x; x++)
1518 for(y=0; y<size_y; y++)
1519 DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
1521 redraw_mask |= REDRAW_FIELD;
1524 static void DrawMicroLevelExt(int xpos, int ypos, int from_x, int from_y)
1528 DrawBackground(xpos, ypos, MICROLEV_XSIZE, MICROLEV_YSIZE);
1530 if (lev_fieldx < STD_LEV_FIELDX)
1531 xpos += (STD_LEV_FIELDX - lev_fieldx) / 2 * MICRO_TILEX;
1532 if (lev_fieldy < STD_LEV_FIELDY)
1533 ypos += (STD_LEV_FIELDY - lev_fieldy) / 2 * MICRO_TILEY;
1535 xpos += MICRO_TILEX;
1536 ypos += MICRO_TILEY;
1538 for(x=-1; x<=STD_LEV_FIELDX; x++)
1540 for(y=-1; y<=STD_LEV_FIELDY; y++)
1542 int lx = from_x + x, ly = from_y + y;
1544 if (lx >= 0 && lx < lev_fieldx && ly >= 0 && ly < lev_fieldy)
1545 DrawMicroElement(xpos + x * MICRO_TILEX, ypos + y * MICRO_TILEY,
1547 else if (lx >= -1 && lx < lev_fieldx+1 && ly >= -1 && ly < lev_fieldy+1
1548 && BorderElement != EL_EMPTY)
1549 DrawMicroElement(xpos + x * MICRO_TILEX, ypos + y * MICRO_TILEY,
1550 getBorderElement(lx, ly));
1554 redraw_mask |= REDRAW_MICROLEVEL;
1557 #define MICROLABEL_EMPTY 0
1558 #define MICROLABEL_LEVEL_NAME 1
1559 #define MICROLABEL_CREATED_BY 2
1560 #define MICROLABEL_LEVEL_AUTHOR 3
1561 #define MICROLABEL_IMPORTED_FROM 4
1562 #define MICROLABEL_LEVEL_IMPORT_INFO 5
1564 static void DrawMicroLevelLabelExt(int mode)
1566 char label_text[MAX_OUTPUT_LINESIZE + 1];
1567 int max_len_label_text;
1568 int font_nr = FONT_TEXT_2;
1570 if (mode == MICROLABEL_CREATED_BY || mode == MICROLABEL_IMPORTED_FROM)
1571 font_nr = FONT_TEXT_3;
1573 max_len_label_text = SXSIZE / getFontWidth(font_nr);
1575 DrawBackground(SX, MICROLABEL_YPOS, SXSIZE, getFontHeight(font_nr));
1577 strncpy(label_text, (mode == MICROLABEL_LEVEL_NAME ? level.name :
1578 mode == MICROLABEL_CREATED_BY ? "created by" :
1579 mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
1580 mode == MICROLABEL_IMPORTED_FROM ? "imported from" :
1581 mode == MICROLABEL_LEVEL_IMPORT_INFO ?
1582 leveldir_current->imported_from : ""),
1583 max_len_label_text);
1584 label_text[max_len_label_text] = '\0';
1586 if (strlen(label_text) > 0)
1588 int text_width = strlen(label_text) * getFontWidth(font_nr);
1589 int lxpos = SX + (SXSIZE - text_width) / 2;
1590 int lypos = MICROLABEL_YPOS;
1592 DrawText(lxpos, lypos, label_text, font_nr);
1595 redraw_mask |= REDRAW_MICROLEVEL;
1598 void DrawMicroLevel(int xpos, int ypos, boolean restart)
1600 static unsigned long scroll_delay = 0;
1601 static unsigned long label_delay = 0;
1602 static int from_x, from_y, scroll_direction;
1603 static int label_state, label_counter;
1604 int last_game_status = game_status; /* save current game status */
1606 /* force PREVIEW font on preview level */
1607 game_status = GAME_MODE_PSEUDO_PREVIEW;
1611 from_x = from_y = 0;
1612 scroll_direction = MV_RIGHT;
1616 DrawMicroLevelExt(xpos, ypos, from_x, from_y);
1617 DrawMicroLevelLabelExt(label_state);
1619 /* initialize delay counters */
1620 DelayReached(&scroll_delay, 0);
1621 DelayReached(&label_delay, 0);
1623 if (leveldir_current->name)
1625 int len = strlen(leveldir_current->name);
1626 int lxpos = SX + (SXSIZE - len * getFontWidth(FONT_TEXT_1)) / 2;
1627 int lypos = SY + 352;
1629 DrawText(lxpos, lypos, leveldir_current->name, FONT_TEXT_1);
1632 game_status = last_game_status; /* restore current game status */
1637 /* scroll micro level, if needed */
1638 if ((lev_fieldx > STD_LEV_FIELDX || lev_fieldy > STD_LEV_FIELDY) &&
1639 DelayReached(&scroll_delay, MICROLEVEL_SCROLL_DELAY))
1641 switch (scroll_direction)
1647 scroll_direction = MV_UP;
1651 if (from_x < lev_fieldx - STD_LEV_FIELDX)
1654 scroll_direction = MV_DOWN;
1661 scroll_direction = MV_RIGHT;
1665 if (from_y < lev_fieldy - STD_LEV_FIELDY)
1668 scroll_direction = MV_LEFT;
1675 DrawMicroLevelExt(xpos, ypos, from_x, from_y);
1678 /* redraw micro level label, if needed */
1679 if (strcmp(level.name, NAMELESS_LEVEL_NAME) != 0 &&
1680 strcmp(level.author, ANONYMOUS_NAME) != 0 &&
1681 strcmp(level.author, leveldir_current->name) != 0 &&
1682 DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
1684 int max_label_counter = 23;
1686 if (leveldir_current->imported_from != NULL)
1687 max_label_counter += 14;
1689 label_counter = (label_counter + 1) % max_label_counter;
1690 label_state = (label_counter >= 0 && label_counter <= 7 ?
1691 MICROLABEL_LEVEL_NAME :
1692 label_counter >= 9 && label_counter <= 12 ?
1693 MICROLABEL_CREATED_BY :
1694 label_counter >= 14 && label_counter <= 21 ?
1695 MICROLABEL_LEVEL_AUTHOR :
1696 label_counter >= 23 && label_counter <= 26 ?
1697 MICROLABEL_IMPORTED_FROM :
1698 label_counter >= 28 && label_counter <= 35 ?
1699 MICROLABEL_LEVEL_IMPORT_INFO : MICROLABEL_EMPTY);
1700 DrawMicroLevelLabelExt(label_state);
1703 game_status = last_game_status; /* restore current game status */
1706 int REQ_in_range(int x, int y)
1708 if (y > DY+249 && y < DY+278)
1710 if (x > DX+1 && x < DX+48)
1712 else if (x > DX+51 && x < DX+98)
1718 #define MAX_REQUEST_LINES 13
1719 #define MAX_REQUEST_LINE_LEN 7
1721 boolean Request(char *text, unsigned int req_state)
1723 int mx, my, ty, result = -1;
1724 unsigned int old_door_state;
1725 int last_game_status = game_status; /* save current game status */
1727 #if defined(PLATFORM_UNIX)
1728 /* pause network game while waiting for request to answer */
1729 if (options.network &&
1730 game_status == GAME_MODE_PLAYING &&
1731 req_state & REQUEST_WAIT_FOR)
1732 SendToServer_PausePlaying();
1735 old_door_state = GetDoorState();
1739 CloseDoor(DOOR_CLOSE_1);
1741 /* save old door content */
1742 BlitBitmap(bitmap_db_door, bitmap_db_door,
1743 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
1744 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
1746 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
1748 /* clear door drawing field */
1749 DrawBackground(DX, DY, DXSIZE, DYSIZE);
1751 /* force DOOR font on preview level */
1752 game_status = GAME_MODE_PSEUDO_DOOR;
1754 /* write text for request */
1755 for(ty=0; ty < MAX_REQUEST_LINES; ty++)
1757 char text_line[MAX_REQUEST_LINE_LEN + 1];
1763 for(tl=0,tx=0; tx < MAX_REQUEST_LINE_LEN; tl++,tx++)
1766 if (!tc || tc == ' ')
1777 strncpy(text_line, text, tl);
1780 DrawText(DX + (DXSIZE - tl * getFontWidth(FONT_TEXT_2)) / 2,
1781 DY + 8 + ty * (getFontHeight(FONT_TEXT_2) + 2),
1782 text_line, FONT_TEXT_2);
1784 text += tl + (tc == ' ' ? 1 : 0);
1787 game_status = last_game_status; /* restore current game status */
1789 if (req_state & REQ_ASK)
1791 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
1792 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
1794 else if (req_state & REQ_CONFIRM)
1796 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
1798 else if (req_state & REQ_PLAYER)
1800 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
1801 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
1802 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
1803 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
1806 /* copy request gadgets to door backbuffer */
1807 BlitBitmap(drawto, bitmap_db_door,
1808 DX, DY, DXSIZE, DYSIZE,
1809 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
1811 OpenDoor(DOOR_OPEN_1);
1817 if (!(req_state & REQUEST_WAIT_FOR))
1819 SetDrawBackgroundMask(REDRAW_FIELD);
1824 if (game_status != GAME_MODE_MAIN)
1827 button_status = MB_RELEASED;
1829 request_gadget_id = -1;
1831 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
1843 case EVENT_BUTTONPRESS:
1844 case EVENT_BUTTONRELEASE:
1845 case EVENT_MOTIONNOTIFY:
1847 if (event.type == EVENT_MOTIONNOTIFY)
1849 if (!PointerInWindow(window))
1850 continue; /* window and pointer are on different screens */
1855 motion_status = TRUE;
1856 mx = ((MotionEvent *) &event)->x;
1857 my = ((MotionEvent *) &event)->y;
1861 motion_status = FALSE;
1862 mx = ((ButtonEvent *) &event)->x;
1863 my = ((ButtonEvent *) &event)->y;
1864 if (event.type == EVENT_BUTTONPRESS)
1865 button_status = ((ButtonEvent *) &event)->button;
1867 button_status = MB_RELEASED;
1870 /* this sets 'request_gadget_id' */
1871 HandleGadgets(mx, my, button_status);
1873 switch(request_gadget_id)
1875 case TOOL_CTRL_ID_YES:
1878 case TOOL_CTRL_ID_NO:
1881 case TOOL_CTRL_ID_CONFIRM:
1882 result = TRUE | FALSE;
1885 case TOOL_CTRL_ID_PLAYER_1:
1888 case TOOL_CTRL_ID_PLAYER_2:
1891 case TOOL_CTRL_ID_PLAYER_3:
1894 case TOOL_CTRL_ID_PLAYER_4:
1905 case EVENT_KEYPRESS:
1906 switch(GetEventKey((KeyEvent *)&event, TRUE))
1919 if (req_state & REQ_PLAYER)
1923 case EVENT_KEYRELEASE:
1924 ClearPlayerAction();
1928 HandleOtherEvents(&event);
1932 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
1934 int joy = AnyJoystick();
1936 if (joy & JOY_BUTTON_1)
1938 else if (joy & JOY_BUTTON_2)
1944 /* don't eat all CPU time */
1948 if (game_status != GAME_MODE_MAIN)
1953 if (!(req_state & REQ_STAY_OPEN))
1955 CloseDoor(DOOR_CLOSE_1);
1957 if (!(req_state & REQ_STAY_CLOSED) && (old_door_state & DOOR_OPEN_1))
1959 BlitBitmap(bitmap_db_door, bitmap_db_door,
1960 DOOR_GFX_PAGEX2,DOOR_GFX_PAGEY1, DXSIZE,DYSIZE,
1961 DOOR_GFX_PAGEX1,DOOR_GFX_PAGEY1);
1962 OpenDoor(DOOR_OPEN_1);
1968 SetDrawBackgroundMask(REDRAW_FIELD);
1970 #if defined(PLATFORM_UNIX)
1971 /* continue network game after request */
1972 if (options.network &&
1973 game_status == GAME_MODE_PLAYING &&
1974 req_state & REQUEST_WAIT_FOR)
1975 SendToServer_ContinuePlaying();
1981 unsigned int OpenDoor(unsigned int door_state)
1983 unsigned int new_door_state;
1985 if (door_state & DOOR_COPY_BACK)
1987 BlitBitmap(bitmap_db_door, bitmap_db_door,
1988 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE + VYSIZE,
1989 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
1990 door_state &= ~DOOR_COPY_BACK;
1993 new_door_state = MoveDoor(door_state);
1995 return(new_door_state);
1998 unsigned int CloseDoor(unsigned int door_state)
2000 unsigned int new_door_state;
2002 BlitBitmap(backbuffer, bitmap_db_door,
2003 DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2004 BlitBitmap(backbuffer, bitmap_db_door,
2005 VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
2007 new_door_state = MoveDoor(door_state);
2009 return(new_door_state);
2012 unsigned int GetDoorState()
2014 return MoveDoor(DOOR_GET_STATE);
2017 unsigned int SetDoorState(unsigned int door_state)
2019 return MoveDoor(door_state | DOOR_SET_STATE);
2022 unsigned int MoveDoor(unsigned int door_state)
2024 static int door1 = DOOR_OPEN_1;
2025 static int door2 = DOOR_CLOSE_2;
2026 static unsigned long door_delay = 0;
2027 int x, start, stepsize = door.step_offset;
2028 unsigned long door_delay_value = door.step_delay;
2030 if (door_state == DOOR_GET_STATE)
2031 return(door1 | door2);
2033 if (door_state & DOOR_SET_STATE)
2035 if (door_state & DOOR_ACTION_1)
2036 door1 = door_state & DOOR_ACTION_1;
2037 if (door_state & DOOR_ACTION_2)
2038 door2 = door_state & DOOR_ACTION_2;
2040 return(door1 | door2);
2043 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
2044 door_state &= ~DOOR_OPEN_1;
2045 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
2046 door_state &= ~DOOR_CLOSE_1;
2047 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
2048 door_state &= ~DOOR_OPEN_2;
2049 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
2050 door_state &= ~DOOR_CLOSE_2;
2052 if (setup.quick_doors)
2055 door_delay_value = 0;
2057 StopSound(SND_DOOR_OPENING);
2058 StopSound(SND_DOOR_CLOSING);
2061 if (global.autoplay_leveldir)
2063 door_state |= DOOR_NO_DELAY;
2064 door_state &= ~DOOR_CLOSE_ALL;
2067 if (door_state & DOOR_ACTION)
2069 if (!(door_state & DOOR_NO_DELAY))
2071 /* opening door sound has priority over simultaneously closing door */
2072 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
2073 PlaySoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
2074 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
2075 PlaySoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
2078 start = ((door_state & DOOR_NO_DELAY) ? DXSIZE : 0);
2080 for(x=start; x<=DXSIZE; x+=stepsize)
2082 Bitmap *bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
2083 GC gc = bitmap->stored_clip_gc;
2085 if (!(door_state & DOOR_NO_DELAY))
2086 WaitUntilDelayReached(&door_delay, door_delay_value);
2088 if (door_state & DOOR_ACTION_1)
2090 int i = (door_state & DOOR_OPEN_1 ? DXSIZE-x : x);
2091 int j = (DXSIZE - i) / 3;
2093 BlitBitmap(bitmap_db_door, drawto,
2094 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + i/2,
2095 DXSIZE,DYSIZE - i/2, DX, DY);
2097 ClearRectangle(drawto, DX, DY + DYSIZE - i/2, DXSIZE,i/2);
2099 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2100 BlitBitmapMasked(bitmap, drawto,
2101 DXSIZE, DOOR_GFX_PAGEY1, i, 77,
2102 DX + DXSIZE - i, DY + j);
2103 BlitBitmapMasked(bitmap, drawto,
2104 DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63,
2105 DX + DXSIZE - i, DY + 140 + j);
2106 SetClipOrigin(bitmap, gc, DX - DXSIZE + i, DY - (DOOR_GFX_PAGEY1 + j));
2107 BlitBitmapMasked(bitmap, drawto,
2108 DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j,
2110 BlitBitmapMasked(bitmap, drawto,
2111 DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63,
2114 BlitBitmapMasked(bitmap, drawto,
2115 DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
2117 BlitBitmapMasked(bitmap, drawto,
2118 DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
2120 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2121 BlitBitmapMasked(bitmap, drawto,
2122 DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
2123 DX + DXSIZE - i, DY + 77 + j);
2124 BlitBitmapMasked(bitmap, drawto,
2125 DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
2126 DX + DXSIZE - i, DY + 203 + j);
2128 redraw_mask |= REDRAW_DOOR_1;
2131 if (door_state & DOOR_ACTION_2)
2133 int i = (door_state & DOOR_OPEN_2 ? VXSIZE - x : x);
2134 int j = (VXSIZE - i) / 3;
2136 BlitBitmap(bitmap_db_door, drawto,
2137 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + i/2,
2138 VXSIZE, VYSIZE - i/2, VX, VY);
2140 ClearRectangle(drawto, VX, VY + VYSIZE-i/2, VXSIZE, i/2);
2142 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2143 BlitBitmapMasked(bitmap, drawto,
2144 VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2,
2145 VX + VXSIZE-i, VY+j);
2146 SetClipOrigin(bitmap, gc,
2147 VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
2148 BlitBitmapMasked(bitmap, drawto,
2149 VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j,
2152 BlitBitmapMasked(bitmap, drawto,
2153 VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2,
2154 i, VYSIZE / 2, VX, VY + VYSIZE / 2 - j);
2155 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2156 BlitBitmapMasked(bitmap, drawto,
2157 VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2,
2159 VX + VXSIZE - i, VY + VYSIZE / 2 + j);
2161 redraw_mask |= REDRAW_DOOR_2;
2166 if (game_status == GAME_MODE_MAIN)
2171 if (setup.quick_doors)
2173 StopSound(SND_DOOR_OPENING);
2174 StopSound(SND_DOOR_CLOSING);
2177 if (door_state & DOOR_ACTION_1)
2178 door1 = door_state & DOOR_ACTION_1;
2179 if (door_state & DOOR_ACTION_2)
2180 door2 = door_state & DOOR_ACTION_2;
2182 return (door1 | door2);
2185 void DrawSpecialEditorDoor()
2187 /* draw bigger toolbox window */
2188 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
2189 DOOR_GFX_PAGEX7, 0, EXSIZE + 8, 8,
2191 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
2192 EX - 4, VY - 4, EXSIZE + 8, EYSIZE - VYSIZE + 4,
2195 redraw_mask |= REDRAW_ALL;
2198 void UndrawSpecialEditorDoor()
2200 /* draw normal tape recorder window */
2201 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
2202 EX - 4, EY - 12, EXSIZE + 8, EYSIZE - VYSIZE + 12,
2205 redraw_mask |= REDRAW_ALL;
2209 /* ---------- new tool button stuff ---------------------------------------- */
2211 /* graphic position values for tool buttons */
2212 #define TOOL_BUTTON_YES_XPOS 2
2213 #define TOOL_BUTTON_YES_YPOS 250
2214 #define TOOL_BUTTON_YES_GFX_YPOS 0
2215 #define TOOL_BUTTON_YES_XSIZE 46
2216 #define TOOL_BUTTON_YES_YSIZE 28
2217 #define TOOL_BUTTON_NO_XPOS 52
2218 #define TOOL_BUTTON_NO_YPOS TOOL_BUTTON_YES_YPOS
2219 #define TOOL_BUTTON_NO_GFX_YPOS TOOL_BUTTON_YES_GFX_YPOS
2220 #define TOOL_BUTTON_NO_XSIZE TOOL_BUTTON_YES_XSIZE
2221 #define TOOL_BUTTON_NO_YSIZE TOOL_BUTTON_YES_YSIZE
2222 #define TOOL_BUTTON_CONFIRM_XPOS TOOL_BUTTON_YES_XPOS
2223 #define TOOL_BUTTON_CONFIRM_YPOS TOOL_BUTTON_YES_YPOS
2224 #define TOOL_BUTTON_CONFIRM_GFX_YPOS 30
2225 #define TOOL_BUTTON_CONFIRM_XSIZE 96
2226 #define TOOL_BUTTON_CONFIRM_YSIZE TOOL_BUTTON_YES_YSIZE
2227 #define TOOL_BUTTON_PLAYER_XSIZE 30
2228 #define TOOL_BUTTON_PLAYER_YSIZE 30
2229 #define TOOL_BUTTON_PLAYER_GFX_XPOS 5
2230 #define TOOL_BUTTON_PLAYER_GFX_YPOS 185
2231 #define TOOL_BUTTON_PLAYER_XPOS (5 + TOOL_BUTTON_PLAYER_XSIZE / 2)
2232 #define TOOL_BUTTON_PLAYER_YPOS (215 - TOOL_BUTTON_PLAYER_YSIZE / 2)
2233 #define TOOL_BUTTON_PLAYER1_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2234 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2235 #define TOOL_BUTTON_PLAYER2_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2236 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2237 #define TOOL_BUTTON_PLAYER3_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2238 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2239 #define TOOL_BUTTON_PLAYER4_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2240 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2241 #define TOOL_BUTTON_PLAYER1_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2242 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2243 #define TOOL_BUTTON_PLAYER2_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2244 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2245 #define TOOL_BUTTON_PLAYER3_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2246 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2247 #define TOOL_BUTTON_PLAYER4_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2248 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2257 } toolbutton_info[NUM_TOOL_BUTTONS] =
2260 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_GFX_YPOS,
2261 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_YPOS,
2262 TOOL_BUTTON_YES_XSIZE, TOOL_BUTTON_YES_YSIZE,
2267 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_GFX_YPOS,
2268 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_YPOS,
2269 TOOL_BUTTON_NO_XSIZE, TOOL_BUTTON_NO_YSIZE,
2274 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_GFX_YPOS,
2275 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_YPOS,
2276 TOOL_BUTTON_CONFIRM_XSIZE, TOOL_BUTTON_CONFIRM_YSIZE,
2277 TOOL_CTRL_ID_CONFIRM,
2281 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2282 TOOL_BUTTON_PLAYER1_XPOS, TOOL_BUTTON_PLAYER1_YPOS,
2283 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2284 TOOL_CTRL_ID_PLAYER_1,
2288 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2289 TOOL_BUTTON_PLAYER2_XPOS, TOOL_BUTTON_PLAYER2_YPOS,
2290 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2291 TOOL_CTRL_ID_PLAYER_2,
2295 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2296 TOOL_BUTTON_PLAYER3_XPOS, TOOL_BUTTON_PLAYER3_YPOS,
2297 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2298 TOOL_CTRL_ID_PLAYER_3,
2302 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2303 TOOL_BUTTON_PLAYER4_XPOS, TOOL_BUTTON_PLAYER4_YPOS,
2304 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2305 TOOL_CTRL_ID_PLAYER_4,
2310 void CreateToolButtons()
2314 for (i=0; i<NUM_TOOL_BUTTONS; i++)
2316 Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
2317 Bitmap *deco_bitmap = None;
2318 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
2319 struct GadgetInfo *gi;
2320 unsigned long event_mask;
2321 int gd_xoffset, gd_yoffset;
2322 int gd_x1, gd_x2, gd_y;
2325 event_mask = GD_EVENT_RELEASED;
2327 gd_xoffset = toolbutton_info[i].xpos;
2328 gd_yoffset = toolbutton_info[i].ypos;
2329 gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
2330 gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
2331 gd_y = DOOR_GFX_PAGEY1 + gd_yoffset;
2333 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
2335 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
2337 getMiniGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr),
2338 &deco_bitmap, &deco_x, &deco_y);
2339 deco_xpos = (toolbutton_info[i].width - MINI_TILEX) / 2;
2340 deco_ypos = (toolbutton_info[i].height - MINI_TILEY) / 2;
2343 gi = CreateGadget(GDI_CUSTOM_ID, id,
2344 GDI_INFO_TEXT, toolbutton_info[i].infotext,
2345 GDI_X, DX + toolbutton_info[i].x,
2346 GDI_Y, DY + toolbutton_info[i].y,
2347 GDI_WIDTH, toolbutton_info[i].width,
2348 GDI_HEIGHT, toolbutton_info[i].height,
2349 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
2350 GDI_STATE, GD_BUTTON_UNPRESSED,
2351 GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
2352 GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
2353 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
2354 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
2355 GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
2356 GDI_DECORATION_SHIFTING, 1, 1,
2357 GDI_EVENT_MASK, event_mask,
2358 GDI_CALLBACK_ACTION, HandleToolButtons,
2362 Error(ERR_EXIT, "cannot create gadget");
2364 tool_gadget[id] = gi;
2368 void FreeToolButtons()
2372 for (i=0; i<NUM_TOOL_BUTTONS; i++)
2373 FreeGadget(tool_gadget[i]);
2376 static void UnmapToolButtons()
2380 for (i=0; i<NUM_TOOL_BUTTONS; i++)
2381 UnmapGadget(tool_gadget[i]);
2384 static void HandleToolButtons(struct GadgetInfo *gi)
2386 request_gadget_id = gi->custom_id;
2389 int get_next_element(int element)
2393 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
2394 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
2395 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
2396 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
2397 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
2398 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
2399 case EL_AMOEBA_DROPPING: return EL_AMOEBA_WET;
2401 default: return element;
2405 int el_act_dir2img(int element, int action, int direction)
2407 element = GFX_ELEMENT(element);
2408 direction = MV_DIR_BIT(direction);
2410 return element_info[element].direction_graphic[action][direction];
2413 int el_act2img(int element, int action)
2415 element = GFX_ELEMENT(element);
2417 return element_info[element].graphic[action];
2420 int el_dir2img(int element, int direction)
2422 element = GFX_ELEMENT(element);
2424 return el_act_dir2img(element, ACTION_DEFAULT, direction);
2427 int el2img(int element)
2429 element = GFX_ELEMENT(element);
2431 return element_info[element].graphic[ACTION_DEFAULT];
2434 int el2edimg(int element)
2436 element = GFX_ELEMENT(element);
2438 return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
2441 int el2preimg(int element)
2443 element = GFX_ELEMENT(element);
2445 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];