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 *);
37 static int el_act_dir2crm(int, int, int);
38 static int el_act2crm(int, int);
40 static struct GadgetInfo *tool_gadget[NUM_TOOL_BUTTONS];
41 static int request_gadget_id = -1;
43 void SetDrawtoField(int mode)
45 if (mode == DRAW_BUFFERED && setup.soft_scrolling)
56 drawto_field = fieldbuffer;
58 else /* DRAW_DIRECT, DRAW_BACKBUFFER */
69 drawto_field = (mode == DRAW_DIRECT ? window : backbuffer);
73 void RedrawPlayfield(boolean force_redraw, int x, int y, int width, int height)
75 if (game_status == GAME_MODE_PLAYING && !game.envelope_active)
81 width = gfx.sxsize + 2 * TILEX;
82 height = gfx.sysize + 2 * TILEY;
85 if (force_redraw || setup.direct_draw)
88 int x1 = (x - SX) / TILEX, y1 = (y - SY) / TILEY;
89 int x2 = (x - SX + width) / TILEX, y2 = (y - SY + height) / TILEY;
91 if (setup.direct_draw)
92 SetDrawtoField(DRAW_BACKBUFFER);
94 for(xx=BX1; xx<=BX2; xx++)
95 for(yy=BY1; yy<=BY2; yy++)
96 if (xx >= x1 && xx <= x2 && yy >= y1 && yy <= y2)
97 DrawScreenField(xx, yy);
100 if (setup.direct_draw)
101 SetDrawtoField(DRAW_DIRECT);
104 if (setup.soft_scrolling)
106 int fx = FX, fy = FY;
108 fx += (ScreenMovDir & (MV_LEFT|MV_RIGHT) ? ScreenGfxPos : 0);
109 fy += (ScreenMovDir & (MV_UP|MV_DOWN) ? ScreenGfxPos : 0);
111 BlitBitmap(fieldbuffer, backbuffer, fx,fy, SXSIZE,SYSIZE, SX,SY);
115 BlitBitmap(drawto, window, x, y, width, height, x, y);
121 DrawBuffer *buffer = (drawto_field == window ? backbuffer : drawto_field);
123 if (setup.direct_draw && game_status == GAME_MODE_PLAYING)
124 redraw_mask &= ~REDRAW_MAIN;
126 if (redraw_mask & REDRAW_TILES && redraw_tiles > REDRAWTILES_THRESHOLD)
127 redraw_mask |= REDRAW_FIELD;
129 if (redraw_mask & REDRAW_FIELD)
130 redraw_mask &= ~REDRAW_TILES;
132 if (redraw_mask == REDRAW_NONE)
135 if (global.fps_slowdown && game_status == GAME_MODE_PLAYING)
137 static boolean last_frame_skipped = FALSE;
138 boolean skip_even_when_not_scrolling = TRUE;
139 boolean just_scrolling = (ScreenMovDir != 0);
140 boolean verbose = FALSE;
142 if (global.fps_slowdown_factor > 1 &&
143 (FrameCounter % global.fps_slowdown_factor) &&
144 (just_scrolling || skip_even_when_not_scrolling))
146 redraw_mask &= ~REDRAW_MAIN;
148 last_frame_skipped = TRUE;
151 printf("FRAME SKIPPED\n");
155 if (last_frame_skipped)
156 redraw_mask |= REDRAW_FIELD;
158 last_frame_skipped = FALSE;
161 printf("frame not skipped\n");
165 /* synchronize X11 graphics at this point; if we would synchronize the
166 display immediately after the buffer switching (after the XFlush),
167 this could mean that we have to wait for the graphics to complete,
168 although we could go on doing calculations for the next frame */
172 if (redraw_mask & REDRAW_ALL)
174 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
178 if (redraw_mask & REDRAW_FIELD)
180 if (game_status != GAME_MODE_PLAYING ||
181 redraw_mask & REDRAW_FROM_BACKBUFFER)
183 BlitBitmap(backbuffer, window,
184 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE, REAL_SX, REAL_SY);
188 int fx = FX, fy = FY;
190 if (setup.soft_scrolling)
192 fx += (ScreenMovDir & (MV_LEFT | MV_RIGHT) ? ScreenGfxPos : 0);
193 fy += (ScreenMovDir & (MV_UP | MV_DOWN) ? ScreenGfxPos : 0);
196 if (setup.soft_scrolling ||
197 ABS(ScreenMovPos) + ScrollStepSize == TILEX ||
198 ABS(ScreenMovPos) == ScrollStepSize ||
199 redraw_tiles > REDRAWTILES_THRESHOLD)
201 BlitBitmap(buffer, window, fx, fy, SXSIZE, SYSIZE, SX, SY);
205 printf("redrawing all (ScreenGfxPos == %d) because %s\n",
207 (setup.soft_scrolling ?
208 "setup.soft_scrolling" :
209 ABS(ScreenGfxPos) + ScrollStepSize == TILEX ?
210 "ABS(ScreenGfxPos) + ScrollStepSize == TILEX" :
211 ABS(ScreenGfxPos) == ScrollStepSize ?
212 "ABS(ScreenGfxPos) == ScrollStepSize" :
213 "redraw_tiles > REDRAWTILES_THRESHOLD"));
219 redraw_mask &= ~REDRAW_MAIN;
222 if (redraw_mask & REDRAW_DOORS)
224 if (redraw_mask & REDRAW_DOOR_1)
225 BlitBitmap(backbuffer, window, DX, DY, DXSIZE, DYSIZE, DX, DY);
226 if (redraw_mask & REDRAW_DOOR_2)
228 if ((redraw_mask & REDRAW_DOOR_2) == REDRAW_DOOR_2)
229 BlitBitmap(backbuffer, window, VX,VY, VXSIZE,VYSIZE, VX,VY);
232 if (redraw_mask & REDRAW_VIDEO_1)
233 BlitBitmap(backbuffer, window,
234 VX+VIDEO_DISPLAY1_XPOS,VY+VIDEO_DISPLAY1_YPOS,
235 VIDEO_DISPLAY_XSIZE,VIDEO_DISPLAY_YSIZE,
236 VX+VIDEO_DISPLAY1_XPOS,VY+VIDEO_DISPLAY1_YPOS);
237 if (redraw_mask & REDRAW_VIDEO_2)
238 BlitBitmap(backbuffer, window,
239 VX+VIDEO_DISPLAY2_XPOS,VY+VIDEO_DISPLAY2_YPOS,
240 VIDEO_DISPLAY_XSIZE,VIDEO_DISPLAY_YSIZE,
241 VX+VIDEO_DISPLAY2_XPOS,VY+VIDEO_DISPLAY2_YPOS);
242 if (redraw_mask & REDRAW_VIDEO_3)
243 BlitBitmap(backbuffer, window,
244 VX+VIDEO_CONTROL_XPOS,VY+VIDEO_CONTROL_YPOS,
245 VIDEO_CONTROL_XSIZE,VIDEO_CONTROL_YSIZE,
246 VX+VIDEO_CONTROL_XPOS,VY+VIDEO_CONTROL_YPOS);
250 if (redraw_mask & REDRAW_DOOR_3)
251 BlitBitmap(backbuffer, window, EX, EY, EXSIZE, EYSIZE, EX, EY);
253 redraw_mask &= ~REDRAW_DOORS;
256 if (redraw_mask & REDRAW_MICROLEVEL)
258 BlitBitmap(backbuffer, window, SX, SY + 10 * TILEY, SXSIZE, 7 * TILEY,
259 SX, SY + 10 * TILEY);
261 redraw_mask &= ~REDRAW_MICROLEVEL;
264 if (redraw_mask & REDRAW_TILES)
266 for(x=0; x<SCR_FIELDX; x++)
267 for(y=0; y<SCR_FIELDY; y++)
268 if (redraw[redraw_x1 + x][redraw_y1 + y])
269 BlitBitmap(buffer, window,
270 FX + x * TILEX, FX + y * TILEY, TILEX, TILEY,
271 SX + x * TILEX, SY + y * TILEY);
274 if (redraw_mask & REDRAW_FPS) /* display frames per second */
279 sprintf(info1, " (only every %d. frame)", global.fps_slowdown_factor);
280 if (!global.fps_slowdown)
283 sprintf(text, "%.1f fps%s", global.frames_per_second, info1);
284 DrawTextExt(window, SX, SY, text, FONT_TEXT_2, BLIT_OPAQUE);
289 for(x=0; x<MAX_BUF_XSIZE; x++)
290 for(y=0; y<MAX_BUF_YSIZE; y++)
293 redraw_mask = REDRAW_NONE;
299 long fading_delay = 300;
301 if (setup.fading && (redraw_mask & REDRAW_FIELD))
308 ClearRectangle(window, REAL_SX,REAL_SY,FULL_SXSIZE,FULL_SYSIZE);
311 for(i=0;i<2*FULL_SYSIZE;i++)
313 for(y=0;y<FULL_SYSIZE;y++)
315 BlitBitmap(backbuffer, window,
316 REAL_SX,REAL_SY+i, FULL_SXSIZE,1, REAL_SX,REAL_SY+i);
324 for(i=1;i<FULL_SYSIZE;i+=2)
325 BlitBitmap(backbuffer, window,
326 REAL_SX,REAL_SY+i, FULL_SXSIZE,1, REAL_SX,REAL_SY+i);
332 SetClipOrigin(clip_gc[PIX_FADEMASK], 0, 0);
333 BlitBitmapMasked(backbuffer, window,
334 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
339 SetClipOrigin(clip_gc[PIX_FADEMASK], -1, -1);
340 BlitBitmapMasked(backbuffer, window,
341 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
346 SetClipOrigin(clip_gc[PIX_FADEMASK], 0, -1);
347 BlitBitmapMasked(backbuffer, window,
348 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
353 SetClipOrigin(clip_gc[PIX_FADEMASK], -1, 0);
354 BlitBitmapMasked(backbuffer, window,
355 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
360 redraw_mask &= ~REDRAW_MAIN;
367 void SetMainBackgroundImage(int graphic)
369 SetMainBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
370 graphic_info[graphic].bitmap ?
371 graphic_info[graphic].bitmap :
372 graphic_info[IMG_BACKGROUND].bitmap);
375 void SetDoorBackgroundImage(int graphic)
377 SetDoorBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
378 graphic_info[graphic].bitmap ?
379 graphic_info[graphic].bitmap :
380 graphic_info[IMG_BACKGROUND].bitmap);
383 void DrawBackground(int dest_x, int dest_y, int width, int height)
385 ClearRectangleOnBackground(backbuffer, dest_x, dest_y, width, height);
387 redraw_mask |= REDRAW_FIELD;
392 DrawBackground(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
394 if (setup.soft_scrolling && game_status == GAME_MODE_PLAYING)
396 ClearRectangle(fieldbuffer, 0, 0, FXSIZE, FYSIZE);
397 SetDrawtoField(DRAW_BUFFERED);
400 SetDrawtoField(DRAW_BACKBUFFER);
402 if (setup.direct_draw && game_status == GAME_MODE_PLAYING)
404 ClearRectangle(window, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
405 SetDrawtoField(DRAW_DIRECT);
409 void MarkTileDirty(int x, int y)
411 int xx = redraw_x1 + x;
412 int yy = redraw_y1 + y;
417 redraw[xx][yy] = TRUE;
418 redraw_mask |= REDRAW_TILES;
421 void SetBorderElement()
425 BorderElement = EL_EMPTY;
427 for(y=0; y<lev_fieldy && BorderElement == EL_EMPTY; y++)
429 for(x=0; x<lev_fieldx; x++)
431 if (!IS_INDESTRUCTIBLE(Feld[x][y]))
432 BorderElement = EL_STEELWALL;
434 if (y != 0 && y != lev_fieldy - 1 && x != lev_fieldx - 1)
440 void SetRandomAnimationValue(int x, int y)
442 gfx.anim_random_frame = GfxRandom[x][y];
445 inline int getGraphicAnimationFrame(int graphic, int sync_frame)
447 /* animation synchronized with global frame counter, not move position */
448 if (graphic_info[graphic].anim_global_sync || sync_frame < 0)
449 sync_frame = FrameCounter;
451 return getAnimationFrame(graphic_info[graphic].anim_frames,
452 graphic_info[graphic].anim_delay,
453 graphic_info[graphic].anim_mode,
454 graphic_info[graphic].anim_start_frame,
458 inline void DrawGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
459 int graphic, int sync_frame, int mask_mode)
461 int frame = getGraphicAnimationFrame(graphic, sync_frame);
463 if (mask_mode == USE_MASKING)
464 DrawGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
466 DrawGraphicExt(dst_bitmap, x, y, graphic, frame);
469 inline void DrawGraphicAnimation(int x, int y, int graphic)
471 int lx = LEVELX(x), ly = LEVELY(y);
473 if (!IN_SCR_FIELD(x, y))
476 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
477 graphic, GfxFrame[lx][ly], NO_MASKING);
481 void DrawLevelGraphicAnimation(int x, int y, int graphic)
483 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
486 void DrawLevelElementAnimation(int x, int y, int element)
489 int graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
491 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
493 DrawGraphicAnimation(SCREENX(x), SCREENY(y), el2img(element));
497 inline void DrawLevelGraphicAnimationIfNeeded(int x, int y, int graphic)
499 int sx = SCREENX(x), sy = SCREENY(y);
501 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
504 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
507 DrawGraphicAnimation(sx, sy, graphic);
509 if (GFX_CRUMBLED(Feld[x][y]))
510 DrawLevelFieldCrumbledSand(x, y);
513 void DrawLevelElementAnimationIfNeeded(int x, int y, int element)
515 int sx = SCREENX(x), sy = SCREENY(y);
518 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
521 graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
523 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
526 DrawGraphicAnimation(sx, sy, graphic);
528 if (GFX_CRUMBLED(element))
529 DrawLevelFieldCrumbledSand(x, y);
532 static int getPlayerGraphic(struct PlayerInfo *player, int move_dir)
534 if (player->use_murphy_graphic)
536 /* this works only because currently only one player can be "murphy" ... */
537 static int last_horizontal_dir = MV_LEFT;
538 int graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, move_dir);
540 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
541 last_horizontal_dir = move_dir;
543 if (graphic == IMG_SP_MURPHY) /* undefined => use special graphic */
545 int direction = (player->is_snapping ? move_dir : last_horizontal_dir);
547 graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, direction);
553 return el_act_dir2img(player->element_nr, player->GfxAction, move_dir);
556 void DrawAllPlayers()
560 for(i=0; i<MAX_PLAYERS; i++)
561 if (stored_player[i].active)
562 DrawPlayer(&stored_player[i]);
565 void DrawPlayerField(int x, int y)
567 if (!IS_PLAYER(x, y))
570 DrawPlayer(PLAYERINFO(x, y));
573 void DrawPlayer(struct PlayerInfo *player)
577 int move_dir = player->MovDir;
579 int last_jx = player->last_jx;
580 int last_jy = player->last_jy;
581 int next_jx = jx + (jx - last_jx);
582 int next_jy = jy + (jy - last_jy);
583 boolean player_is_moving = (last_jx != jx || last_jy != jy ? TRUE : FALSE);
585 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? +1 : 0);
586 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? +1 : 0);
587 int last_jx = (player->is_moving ? jx - dx : jx);
588 int last_jy = (player->is_moving ? jy - dy : jy);
589 int next_jx = jx + dx;
590 int next_jy = jy + dy;
591 boolean player_is_moving = (player->MovPos ? TRUE : FALSE);
593 int sx = SCREENX(jx), sy = SCREENY(jy);
594 int sxx = 0, syy = 0;
595 int element = Feld[jx][jy], last_element = Feld[last_jx][last_jy];
597 int action = ACTION_DEFAULT;
598 int last_player_graphic = getPlayerGraphic(player, move_dir);
599 int last_player_frame = player->Frame;
602 if (!player->active || !IN_SCR_FIELD(SCREENX(last_jx), SCREENY(last_jy)))
606 if (!IN_LEV_FIELD(jx, jy))
608 printf("DrawPlayerField(): x = %d, y = %d\n",jx,jy);
609 printf("DrawPlayerField(): sx = %d, sy = %d\n",sx,sy);
610 printf("DrawPlayerField(): This should never happen!\n");
615 if (element == EL_EXPLOSION)
618 action = (player->is_pushing ? ACTION_PUSHING :
619 player->is_digging ? ACTION_DIGGING :
620 player->is_collecting ? ACTION_COLLECTING :
621 player->is_moving ? ACTION_MOVING :
622 player->is_snapping ? ACTION_SNAPPING : ACTION_DEFAULT);
625 printf("::: '%s'\n", element_action_info[action].suffix);
628 InitPlayerGfxAnimation(player, action, move_dir);
630 /* ----------------------------------------------------------------------- */
631 /* draw things in the field the player is leaving, if needed */
632 /* ----------------------------------------------------------------------- */
635 if (player->is_moving)
637 if (player_is_moving)
640 if (Back[last_jx][last_jy] && IS_DRAWABLE(last_element))
642 DrawLevelElement(last_jx, last_jy, Back[last_jx][last_jy]);
644 if (last_element == EL_DYNAMITE_ACTIVE ||
645 last_element == EL_SP_DISK_RED_ACTIVE)
646 DrawDynamite(last_jx, last_jy);
648 DrawLevelFieldThruMask(last_jx, last_jy);
650 else if (last_element == EL_DYNAMITE_ACTIVE ||
651 last_element == EL_SP_DISK_RED_ACTIVE)
652 DrawDynamite(last_jx, last_jy);
654 DrawLevelField(last_jx, last_jy);
656 if (player->is_pushing && IN_SCR_FIELD(SCREENX(next_jx), SCREENY(next_jy)))
657 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
660 if (!IN_SCR_FIELD(sx, sy))
663 if (setup.direct_draw)
664 SetDrawtoField(DRAW_BUFFERED);
666 /* ----------------------------------------------------------------------- */
667 /* draw things behind the player, if needed */
668 /* ----------------------------------------------------------------------- */
671 DrawLevelElement(jx, jy, Back[jx][jy]);
672 else if (IS_ACTIVE_BOMB(element))
673 DrawLevelElement(jx, jy, EL_EMPTY);
676 if (player_is_moving && GfxElement[jx][jy] != EL_UNDEFINED)
678 if (GFX_CRUMBLED(GfxElement[jx][jy]))
679 DrawLevelFieldCrumbledSandDigging(jx, jy, move_dir, player->StepFrame);
682 int old_element = GfxElement[jx][jy];
683 int old_graphic = el_act_dir2img(old_element, action, move_dir);
684 int frame = getGraphicAnimationFrame(old_graphic, player->StepFrame);
686 DrawGraphic(sx, sy, old_graphic, frame);
691 GfxElement[jx][jy] = EL_UNDEFINED;
693 DrawLevelField(jx, jy);
697 /* ----------------------------------------------------------------------- */
698 /* draw player himself */
699 /* ----------------------------------------------------------------------- */
703 graphic = getPlayerGraphic(player, move_dir);
705 /* in the case of changed player action or direction, prevent the current
706 animation frame from being restarted for identical animations */
707 if (player->Frame == 0 &&
708 graphic_info[graphic].bitmap == graphic_info[last_player_graphic].bitmap)
709 player->Frame = last_player_frame;
713 if (player->use_murphy_graphic)
715 static int last_horizontal_dir = MV_LEFT;
717 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
718 last_horizontal_dir = move_dir;
720 graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, move_dir);
722 if (graphic == IMG_SP_MURPHY) /* undefined => use special graphic */
724 int direction = (player->is_snapping ? move_dir : last_horizontal_dir);
726 graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, direction);
730 graphic = el_act_dir2img(player->element_nr, player->GfxAction, move_dir);
734 frame = getGraphicAnimationFrame(graphic, player->Frame);
738 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
739 sxx = player->GfxPos;
741 syy = player->GfxPos;
744 if (!setup.soft_scrolling && ScreenMovPos)
747 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
749 if (SHIELD_ON(player))
751 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
752 IMG_SHIELD_NORMAL_ACTIVE);
753 int frame = getGraphicAnimationFrame(graphic, -1);
755 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
758 /* ----------------------------------------------------------------------- */
759 /* draw things the player is pushing, if needed */
760 /* ----------------------------------------------------------------------- */
763 printf("::: %d, %d [%d, %d] [%d]\n",
764 player->is_pushing, player_is_moving, player->GfxAction,
765 player->is_moving, player_is_moving);
769 if (player->is_pushing && player->is_moving)
771 if (player->is_pushing && player_is_moving)
774 int px = SCREENX(next_jx), py = SCREENY(next_jy);
776 if (Back[next_jx][next_jy])
777 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
779 if ((sxx || syy) && element == EL_SOKOBAN_OBJECT)
780 DrawGraphicShiftedThruMask(px, py, sxx, syy, IMG_SOKOBAN_OBJECT, 0,
784 int element = MovingOrBlocked2Element(next_jx, next_jy);
785 int graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
787 int frame = getGraphicAnimationFrame(graphic, player->StepFrame);
789 int frame = getGraphicAnimationFrame(graphic, player->Frame);
792 DrawGraphicShifted(px, py, sxx, syy, graphic, frame,
793 NO_CUTTING, NO_MASKING);
797 /* ----------------------------------------------------------------------- */
798 /* draw things in front of player (active dynamite or dynabombs) */
799 /* ----------------------------------------------------------------------- */
801 if (IS_ACTIVE_BOMB(element))
803 graphic = el2img(element);
804 frame = getGraphicAnimationFrame(graphic, GfxFrame[jx][jy]);
806 if (game.emulation == EMU_SUPAPLEX)
807 DrawGraphic(sx, sy, IMG_SP_DISK_RED, frame);
809 DrawGraphicThruMask(sx, sy, graphic, frame);
812 if (player_is_moving && last_element == EL_EXPLOSION)
814 int graphic = el_act2img(GfxElement[last_jx][last_jy], ACTION_EXPLODING);
815 int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
816 int phase = ExplodePhase[last_jx][last_jy] - 1;
817 int frame = getGraphicAnimationFrame(graphic, phase - delay);
820 DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy), graphic, frame);
823 /* ----------------------------------------------------------------------- */
824 /* draw elements the player is just walking/passing through/under */
825 /* ----------------------------------------------------------------------- */
827 /* handle the field the player is leaving ... */
828 if (player_is_moving && IS_ACCESSIBLE_INSIDE(last_element))
829 DrawLevelField(last_jx, last_jy);
830 else if (player_is_moving && IS_ACCESSIBLE_UNDER(last_element))
831 DrawLevelFieldThruMask(last_jx, last_jy);
833 /* ... and the field the player is entering */
834 if (IS_ACCESSIBLE_INSIDE(element))
835 DrawLevelField(jx, jy);
836 else if (IS_ACCESSIBLE_UNDER(element))
837 DrawLevelFieldThruMask(jx, jy);
839 if (setup.direct_draw)
841 int dest_x = SX + SCREENX(MIN(jx, last_jx)) * TILEX;
842 int dest_y = SY + SCREENY(MIN(jy, last_jy)) * TILEY;
843 int x_size = TILEX * (1 + ABS(jx - last_jx));
844 int y_size = TILEY * (1 + ABS(jy - last_jy));
846 BlitBitmap(drawto_field, window,
847 dest_x, dest_y, x_size, y_size, dest_x, dest_y);
848 SetDrawtoField(DRAW_DIRECT);
851 MarkTileDirty(sx,sy);
854 void getGraphicSource(int graphic, int frame, Bitmap **bitmap, int *x, int *y)
856 struct GraphicInfo *g = &graphic_info[graphic];
860 if (g->offset_y == 0) /* frames are ordered horizontally */
862 int max_width = g->anim_frames_per_line * g->width;
864 *x = (g->src_x + frame * g->offset_x) % max_width;
865 *y = g->src_y + (g->src_x + frame * g->offset_x) / max_width * g->height;
867 else if (g->offset_x == 0) /* frames are ordered vertically */
869 int max_height = g->anim_frames_per_line * g->height;
871 *x = g->src_x + (g->src_y + frame * g->offset_y) / max_height * g->width;
872 *y = (g->src_y + frame * g->offset_y) % max_height;
874 else /* frames are ordered diagonally */
876 *x = g->src_x + frame * g->offset_x;
877 *y = g->src_y + frame * g->offset_y;
881 void DrawGraphic(int x, int y, int graphic, int frame)
884 if (!IN_SCR_FIELD(x, y))
886 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
887 printf("DrawGraphic(): This should never happen!\n");
892 DrawGraphicExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic, frame);
896 void DrawGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
902 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
903 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
906 void DrawGraphicThruMask(int x, int y, int graphic, int frame)
909 if (!IN_SCR_FIELD(x, y))
911 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
912 printf("DrawGraphicThruMask(): This should never happen!\n");
917 DrawGraphicThruMaskExt(drawto_field, FX + x * TILEX, FY + y *TILEY, graphic,
922 void DrawGraphicThruMaskExt(DrawBuffer *d, int dest_x, int dest_y, int graphic,
930 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
931 drawing_gc = src_bitmap->stored_clip_gc;
933 GC drawing_gc = src_bitmap->stored_clip_gc;
934 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
935 int src_x = graphic_info[graphic].src_x;
936 int src_y = graphic_info[graphic].src_y;
937 int offset_x = graphic_info[graphic].offset_x;
938 int offset_y = graphic_info[graphic].offset_y;
940 src_x += frame * offset_x;
941 src_y += frame * offset_y;
945 SetClipOrigin(src_bitmap, drawing_gc, dest_x - src_x, dest_y - src_y);
946 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX, TILEY, dest_x, dest_y);
949 void DrawMiniGraphic(int x, int y, int graphic)
951 DrawMiniGraphicExt(drawto, SX + x * MINI_TILEX,SY + y * MINI_TILEY, graphic);
952 MarkTileDirty(x / 2, y / 2);
955 void getMiniGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
957 struct GraphicInfo *g = &graphic_info[graphic];
959 int mini_starty = g->bitmap->height * 2 / 3;
962 *x = mini_startx + g->src_x / 2;
963 *y = mini_starty + g->src_y / 2;
966 void DrawMiniGraphicExt(DrawBuffer *d, int x, int y, int graphic)
971 getMiniGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
972 BlitBitmap(src_bitmap, d, src_x, src_y, MINI_TILEX, MINI_TILEY, x, y);
975 void DrawGraphicShifted(int x,int y, int dx,int dy, int graphic, int frame,
976 int cut_mode, int mask_mode)
981 int width = TILEX, height = TILEY;
987 DrawGraphic(x, y, graphic, frame);
991 if (dx || dy) /* shifted graphic */
993 if (x < BX1) /* object enters playfield from the left */
1000 else if (x > BX2) /* object enters playfield from the right */
1006 else if (x==BX1 && dx < 0) /* object leaves playfield to the left */
1012 else if (x==BX2 && dx > 0) /* object leaves playfield to the right */
1014 else if (dx) /* general horizontal movement */
1015 MarkTileDirty(x + SIGN(dx), y);
1017 if (y < BY1) /* object enters playfield from the top */
1019 if (cut_mode==CUT_BELOW) /* object completely above top border */
1027 else if (y > BY2) /* object enters playfield from the bottom */
1033 else if (y==BY1 && dy < 0) /* object leaves playfield to the top */
1039 else if (dy > 0 && cut_mode == CUT_ABOVE)
1041 if (y == BY2) /* object completely above bottom border */
1047 MarkTileDirty(x, y + 1);
1048 } /* object leaves playfield to the bottom */
1049 else if (dy > 0 && (y == BY2 || cut_mode == CUT_BELOW))
1051 else if (dy) /* general vertical movement */
1052 MarkTileDirty(x, y + SIGN(dy));
1056 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1058 src_bitmap = graphic_info[graphic].bitmap;
1059 src_x = graphic_info[graphic].src_x;
1060 src_y = graphic_info[graphic].src_y;
1061 offset_x = graphic_info[graphic].offset_x;
1062 offset_y = graphic_info[graphic].offset_y;
1064 src_x += frame * offset_x;
1065 src_y += frame * offset_y;
1068 drawing_gc = src_bitmap->stored_clip_gc;
1073 dest_x = FX + x * TILEX + dx;
1074 dest_y = FY + y * TILEY + dy;
1077 if (!IN_SCR_FIELD(x,y))
1079 printf("DrawGraphicShifted(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
1080 printf("DrawGraphicShifted(): This should never happen!\n");
1085 if (mask_mode == USE_MASKING)
1087 SetClipOrigin(src_bitmap, drawing_gc, dest_x - src_x, dest_y - src_y);
1088 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1092 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1098 void DrawGraphicShiftedThruMask(int x, int y, int dx, int dy, int graphic,
1099 int frame, int cut_mode)
1101 DrawGraphicShifted(x,y, dx,dy, graphic, frame, cut_mode, USE_MASKING);
1104 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
1105 int cut_mode, int mask_mode)
1107 int lx = LEVELX(x), ly = LEVELY(y);
1111 if (IN_LEV_FIELD(lx, ly))
1113 SetRandomAnimationValue(lx, ly);
1115 graphic = el_act_dir2img(element, GfxAction[lx][ly], GfxDir[lx][ly]);
1116 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1118 else /* border element */
1120 graphic = el2img(element);
1121 frame = getGraphicAnimationFrame(graphic, -1);
1124 if (element == EL_EXPANDABLE_WALL)
1126 boolean left_stopped = FALSE, right_stopped = FALSE;
1128 if (!IN_LEV_FIELD(lx - 1, ly) || IS_WALL(Feld[lx - 1][ly]))
1129 left_stopped = TRUE;
1130 if (!IN_LEV_FIELD(lx + 1, ly) || IS_WALL(Feld[lx + 1][ly]))
1131 right_stopped = TRUE;
1133 if (left_stopped && right_stopped)
1135 else if (left_stopped)
1137 graphic = IMG_EXPANDABLE_WALL_GROWING_RIGHT;
1138 frame = graphic_info[graphic].anim_frames - 1;
1140 else if (right_stopped)
1142 graphic = IMG_EXPANDABLE_WALL_GROWING_LEFT;
1143 frame = graphic_info[graphic].anim_frames - 1;
1148 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, mask_mode);
1149 else if (mask_mode == USE_MASKING)
1150 DrawGraphicThruMask(x, y, graphic, frame);
1152 DrawGraphic(x, y, graphic, frame);
1155 void DrawLevelElementExt(int x, int y, int dx, int dy, int element,
1156 int cut_mode, int mask_mode)
1158 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1159 DrawScreenElementExt(SCREENX(x), SCREENY(y), dx, dy, element,
1160 cut_mode, mask_mode);
1163 void DrawScreenElementShifted(int x, int y, int dx, int dy, int element,
1166 DrawScreenElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1169 void DrawLevelElementShifted(int x, int y, int dx, int dy, int element,
1172 DrawLevelElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1175 void DrawLevelElementThruMask(int x, int y, int element)
1177 DrawLevelElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1180 void DrawLevelFieldThruMask(int x, int y)
1182 DrawLevelElementExt(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
1185 static void DrawLevelFieldCrumbledSandExt(int x, int y, int graphic, int frame)
1189 int sx = SCREENX(x), sy = SCREENY(y);
1191 int width, height, cx, cy, i;
1193 int crumbled_border_size = graphic_info[graphic].border_size;
1195 int snip = TILEX / 8; /* number of border pixels from "crumbled graphic" */
1197 static int xy[4][2] =
1206 if (x == 0 && y == 7)
1207 printf("::: %d, %d [%d]\n", GfxElement[x][y], Feld[x][y],
1208 crumbled_border_size);
1211 if (!IN_LEV_FIELD(x, y))
1214 element = (GfxElement[x][y] != EL_UNDEFINED && Feld[x][y] != EL_EXPLOSION ?
1215 GfxElement[x][y] : Feld[x][y]);
1217 /* crumble field itself */
1218 if (GFX_CRUMBLED(element) && !IS_MOVING(x, y))
1220 if (!IN_SCR_FIELD(sx, sy))
1223 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1227 int xx = x + xy[i][0];
1228 int yy = y + xy[i][1];
1230 element = (IN_LEV_FIELD(xx, yy) ? Feld[xx][yy] : BorderElement);
1232 /* check if neighbour field is of same type */
1233 if (GFX_CRUMBLED(element) && !IS_MOVING(xx, yy))
1237 if (Feld[x][y] == EL_CUSTOM_START + 123)
1238 printf("::: crumble [%d] THE CHAOS ENGINE (%d, %d): %d, %d\n",
1239 i, Feld[x][y], element,
1240 GFX_CRUMBLED(element), IS_MOVING(x, y));
1243 if (i == 1 || i == 2)
1245 width = crumbled_border_size;
1247 cx = (i == 2 ? TILEX - crumbled_border_size : 0);
1253 height = crumbled_border_size;
1255 cy = (i == 3 ? TILEY - crumbled_border_size : 0);
1258 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1259 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
1262 MarkTileDirty(sx, sy);
1264 else /* crumble neighbour fields */
1267 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1272 int xx = x + xy[i][0];
1273 int yy = y + xy[i][1];
1274 int sxx = sx + xy[i][0];
1275 int syy = sy + xy[i][1];
1277 if (!IN_LEV_FIELD(xx, yy) ||
1278 !IN_SCR_FIELD(sxx, syy) ||
1279 !GFX_CRUMBLED(Feld[xx][yy]) ||
1284 graphic = el_act2crm(Feld[xx][yy], ACTION_DEFAULT);
1285 crumbled_border_size = graphic_info[graphic].border_size;
1287 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1290 if (i == 1 || i == 2)
1292 width = crumbled_border_size;
1294 cx = (i == 1 ? TILEX - crumbled_border_size : 0);
1300 height = crumbled_border_size;
1302 cy = (i == 0 ? TILEY - crumbled_border_size : 0);
1305 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1306 width, height, FX + sxx * TILEX + cx, FY + syy * TILEY + cy);
1308 MarkTileDirty(sxx, syy);
1313 void DrawLevelFieldCrumbledSand(int x, int y)
1318 if (!IN_LEV_FIELD(x, y))
1321 graphic = el_act2crm(Feld[x][y], ACTION_DEFAULT);
1323 DrawLevelFieldCrumbledSandExt(x, y, graphic, 0);
1325 DrawLevelFieldCrumbledSandExt(x, y, IMG_SAND_CRUMBLED, 0);
1329 void DrawLevelFieldCrumbledSandDigging(int x, int y, int direction,
1333 int graphic1 = el_act_dir2img(GfxElement[x][y], ACTION_DIGGING, direction);
1334 int graphic2 = el_act_dir2crm(GfxElement[x][y], ACTION_DIGGING, direction);
1336 int graphic1 = el_act_dir2img(EL_SAND, ACTION_DIGGING, direction);
1337 int graphic2 = el_act_dir2img(EL_SAND_CRUMBLED, ACTION_DIGGING, direction);
1339 int frame1 = getGraphicAnimationFrame(graphic1, step_frame);
1340 int frame2 = getGraphicAnimationFrame(graphic2, step_frame);
1341 int sx = SCREENX(x), sy = SCREENY(y);
1343 DrawGraphic(sx, sy, graphic1, frame1);
1344 DrawLevelFieldCrumbledSandExt(x, y, graphic2, frame2);
1347 void DrawLevelFieldCrumbledSandNeighbours(int x, int y)
1349 int sx = SCREENX(x), sy = SCREENY(y);
1350 static int xy[4][2] =
1361 int xx = x + xy[i][0];
1362 int yy = y + xy[i][1];
1363 int sxx = sx + xy[i][0];
1364 int syy = sy + xy[i][1];
1366 if (!IN_LEV_FIELD(xx, yy) ||
1367 !IN_SCR_FIELD(sxx, syy) ||
1368 !GFX_CRUMBLED(Feld[xx][yy]) ||
1372 DrawLevelField(xx, yy);
1376 static int getBorderElement(int x, int y)
1380 { EL_STEELWALL_TOPLEFT, EL_INVISIBLE_STEELWALL_TOPLEFT },
1381 { EL_STEELWALL_TOPRIGHT, EL_INVISIBLE_STEELWALL_TOPRIGHT },
1382 { EL_STEELWALL_BOTTOMLEFT, EL_INVISIBLE_STEELWALL_BOTTOMLEFT },
1383 { EL_STEELWALL_BOTTOMRIGHT, EL_INVISIBLE_STEELWALL_BOTTOMRIGHT },
1384 { EL_STEELWALL_VERTICAL, EL_INVISIBLE_STEELWALL_VERTICAL },
1385 { EL_STEELWALL_HORIZONTAL, EL_INVISIBLE_STEELWALL_HORIZONTAL },
1386 { EL_STEELWALL, EL_INVISIBLE_STEELWALL }
1388 int steel_type = (BorderElement == EL_STEELWALL ? 0 : 1);
1389 int steel_position = (x == -1 && y == -1 ? 0 :
1390 x == lev_fieldx && y == -1 ? 1 :
1391 x == -1 && y == lev_fieldy ? 2 :
1392 x == lev_fieldx && y == lev_fieldy ? 3 :
1393 x == -1 || x == lev_fieldx ? 4 :
1394 y == -1 || y == lev_fieldy ? 5 : 6);
1396 return border[steel_position][steel_type];
1399 void DrawScreenElement(int x, int y, int element)
1401 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
1402 DrawLevelFieldCrumbledSand(LEVELX(x), LEVELY(y));
1405 void DrawLevelElement(int x, int y, int element)
1407 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1408 DrawScreenElement(SCREENX(x), SCREENY(y), element);
1411 void DrawScreenField(int x, int y)
1413 int lx = LEVELX(x), ly = LEVELY(y);
1414 int element, content;
1416 if (!IN_LEV_FIELD(lx, ly))
1418 if (lx < -1 || lx > lev_fieldx || ly < -1 || ly > lev_fieldy)
1421 element = getBorderElement(lx, ly);
1423 DrawScreenElement(x, y, element);
1427 element = Feld[lx][ly];
1428 content = Store[lx][ly];
1430 if (IS_MOVING(lx, ly))
1432 int horiz_move = (MovDir[lx][ly] == MV_LEFT || MovDir[lx][ly] == MV_RIGHT);
1433 boolean cut_mode = NO_CUTTING;
1435 if (element == EL_QUICKSAND_EMPTYING ||
1436 element == EL_MAGIC_WALL_EMPTYING ||
1437 element == EL_BD_MAGIC_WALL_EMPTYING ||
1438 element == EL_AMOEBA_DROPPING)
1439 cut_mode = CUT_ABOVE;
1440 else if (element == EL_QUICKSAND_FILLING ||
1441 element == EL_MAGIC_WALL_FILLING ||
1442 element == EL_BD_MAGIC_WALL_FILLING)
1443 cut_mode = CUT_BELOW;
1445 if (cut_mode == CUT_ABOVE)
1446 DrawScreenElementShifted(x, y, 0, 0, element, NO_CUTTING);
1448 DrawScreenElement(x, y, EL_EMPTY);
1451 DrawScreenElementShifted(x, y, MovPos[lx][ly], 0, element, NO_CUTTING);
1452 else if (cut_mode == NO_CUTTING)
1453 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], element, cut_mode);
1455 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], content, cut_mode);
1457 if (content == EL_ACID)
1458 DrawLevelElementThruMask(lx, ly + 1, EL_ACID);
1460 else if (IS_BLOCKED(lx, ly))
1465 boolean cut_mode = NO_CUTTING;
1466 int element_old, content_old;
1468 Blocked2Moving(lx, ly, &oldx, &oldy);
1471 horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
1472 MovDir[oldx][oldy] == MV_RIGHT);
1474 element_old = Feld[oldx][oldy];
1475 content_old = Store[oldx][oldy];
1477 if (element_old == EL_QUICKSAND_EMPTYING ||
1478 element_old == EL_MAGIC_WALL_EMPTYING ||
1479 element_old == EL_BD_MAGIC_WALL_EMPTYING ||
1480 element_old == EL_AMOEBA_DROPPING)
1481 cut_mode = CUT_ABOVE;
1483 DrawScreenElement(x, y, EL_EMPTY);
1486 DrawScreenElementShifted(sx, sy, MovPos[oldx][oldy], 0, element_old,
1488 else if (cut_mode == NO_CUTTING)
1489 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], element_old,
1492 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], content_old,
1495 else if (IS_DRAWABLE(element))
1496 DrawScreenElement(x, y, element);
1498 DrawScreenElement(x, y, EL_EMPTY);
1501 void DrawLevelField(int x, int y)
1503 if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1504 DrawScreenField(SCREENX(x), SCREENY(y));
1505 else if (IS_MOVING(x, y))
1509 Moving2Blocked(x, y, &newx, &newy);
1510 if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
1511 DrawScreenField(SCREENX(newx), SCREENY(newy));
1513 else if (IS_BLOCKED(x, y))
1517 Blocked2Moving(x, y, &oldx, &oldy);
1518 if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
1519 DrawScreenField(SCREENX(oldx), SCREENY(oldy));
1523 void DrawMiniElement(int x, int y, int element)
1527 graphic = el2edimg(element);
1528 DrawMiniGraphic(x, y, graphic);
1531 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
1533 int x = sx + scroll_x, y = sy + scroll_y;
1535 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
1536 DrawMiniElement(sx, sy, EL_EMPTY);
1537 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
1538 DrawMiniElement(sx, sy, Feld[x][y]);
1540 DrawMiniGraphic(sx, sy, el2edimg(getBorderElement(x, y)));
1543 void DrawEnvelopeBackground(int envelope_nr, int startx, int starty,
1544 int x, int y, int xsize, int ysize, int font_nr)
1546 int font_width = getFontWidth(font_nr);
1547 int font_height = getFontHeight(font_nr);
1548 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1551 int dst_x = SX + startx + x * font_width;
1552 int dst_y = SY + starty + y * font_height;
1553 int width = graphic_info[graphic].width;
1554 int height = graphic_info[graphic].height;
1555 int inner_width = MAX(width - 2 * font_width, font_width);
1556 int inner_height = MAX(height - 2 * font_height, font_height);
1557 int inner_sx = (width >= 3 * font_width ? font_width : 0);
1558 int inner_sy = (height >= 3 * font_height ? font_height : 0);
1559 boolean draw_masked = graphic_info[graphic].draw_masked;
1561 getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
1563 if (src_bitmap == NULL || width < font_width || height < font_height)
1565 ClearRectangle(drawto, dst_x, dst_y, font_width, font_height);
1569 src_x += (x == 0 ? 0 : x == xsize - 1 ? width - font_width :
1570 inner_sx + (x - 1) * font_width % inner_width);
1571 src_y += (y == 0 ? 0 : y == ysize - 1 ? height - font_height :
1572 inner_sy + (y - 1) * font_height % inner_height);
1576 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1577 dst_x - src_x, dst_y - src_y);
1578 BlitBitmapMasked(src_bitmap, drawto, src_x, src_y, font_width, font_height,
1582 BlitBitmap(src_bitmap, drawto, src_x, src_y, font_width, font_height,
1586 void AnimateEnvelope(int envelope_nr, int anim_mode, int action)
1588 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1589 boolean draw_masked = graphic_info[graphic].draw_masked;
1590 int mask_mode = (draw_masked ? BLIT_MASKED : BLIT_ON_BACKGROUND);
1591 boolean ffwd_delay = (tape.playing && tape.fast_forward);
1592 unsigned long anim_delay = 0;
1593 int anim_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
1594 int font_nr = FONT_ENVELOPE_1 + envelope_nr;
1595 int font_width = getFontWidth(font_nr);
1596 int font_height = getFontHeight(font_nr);
1597 int max_xsize = level.envelope_xsize[envelope_nr];
1598 int max_ysize = level.envelope_ysize[envelope_nr];
1599 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize : 0);
1600 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize : 0);
1601 int xend = max_xsize;
1602 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize : 0);
1603 int xstep = (xstart < xend ? 1 : 0);
1604 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
1607 for (x=xstart, y=ystart; x <= xend && y <= yend; x += xstep, y += ystep)
1609 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
1610 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
1611 int sx = (SXSIZE - xsize * font_width) / 2;
1612 int sy = (SYSIZE - ysize * font_height) / 2;
1615 SetDrawtoField(DRAW_BUFFERED);
1617 BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
1619 SetDrawtoField(DRAW_BACKBUFFER);
1621 for (yy=0; yy < ysize; yy++) for (xx=0; xx < xsize; xx++)
1622 DrawEnvelopeBackground(envelope_nr, sx,sy, xx,yy, xsize, ysize, font_nr);
1624 DrawTextToTextArea(SX + sx + font_width, SY + sy + font_height,
1625 level.envelope_text[envelope_nr], font_nr, max_xsize,
1626 xsize - 2, ysize - 2, mask_mode);
1628 redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
1631 WaitUntilDelayReached(&anim_delay, anim_delay_value / 2);
1635 void ShowEnvelope(int envelope_nr)
1637 int element = EL_ENVELOPE_1 + envelope_nr;
1638 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1639 int sound_opening = element_info[element].sound[ACTION_OPENING];
1640 int sound_closing = element_info[element].sound[ACTION_CLOSING];
1641 boolean ffwd_delay = (tape.playing && tape.fast_forward);
1642 int wait_delay_value = (ffwd_delay ? 500 : 1000);
1643 int anim_mode = graphic_info[graphic].anim_mode;
1644 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
1645 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
1647 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
1649 PlaySoundStereo(sound_opening, SOUND_MIDDLE);
1651 if (anim_mode == ANIM_DEFAULT)
1652 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_OPENING);
1654 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_OPENING);
1657 Delay(wait_delay_value);
1659 WaitForEventToContinue();
1661 PlaySoundStereo(sound_closing, SOUND_MIDDLE);
1663 if (anim_mode != ANIM_NONE)
1664 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_CLOSING);
1666 if (anim_mode == ANIM_DEFAULT)
1667 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_CLOSING);
1669 game.envelope_active = FALSE;
1671 SetDrawtoField(DRAW_BUFFERED);
1673 redraw_mask |= REDRAW_FIELD;
1677 void getMicroGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
1679 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
1680 int mini_startx = src_bitmap->width * 3 / 4;
1681 int mini_starty = src_bitmap->height * 2 / 3;
1682 int src_x = mini_startx + graphic_info[graphic].src_x / 8;
1683 int src_y = mini_starty + graphic_info[graphic].src_y / 8;
1685 *bitmap = src_bitmap;
1690 void DrawMicroElement(int xpos, int ypos, int element)
1694 int graphic = el2preimg(element);
1696 getMicroGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
1697 BlitBitmap(src_bitmap, drawto, src_x, src_y, MICRO_TILEX, MICRO_TILEY,
1705 SetDrawBackgroundMask(REDRAW_NONE);
1708 for(x=BX1; x<=BX2; x++)
1709 for(y=BY1; y<=BY2; y++)
1710 DrawScreenField(x, y);
1712 redraw_mask |= REDRAW_FIELD;
1715 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
1719 for(x=0; x<size_x; x++)
1720 for(y=0; y<size_y; y++)
1721 DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
1723 redraw_mask |= REDRAW_FIELD;
1726 static void DrawMicroLevelExt(int xpos, int ypos, int from_x, int from_y)
1730 DrawBackground(xpos, ypos, MICROLEV_XSIZE, MICROLEV_YSIZE);
1732 if (lev_fieldx < STD_LEV_FIELDX)
1733 xpos += (STD_LEV_FIELDX - lev_fieldx) / 2 * MICRO_TILEX;
1734 if (lev_fieldy < STD_LEV_FIELDY)
1735 ypos += (STD_LEV_FIELDY - lev_fieldy) / 2 * MICRO_TILEY;
1737 xpos += MICRO_TILEX;
1738 ypos += MICRO_TILEY;
1740 for(x=-1; x<=STD_LEV_FIELDX; x++)
1742 for(y=-1; y<=STD_LEV_FIELDY; y++)
1744 int lx = from_x + x, ly = from_y + y;
1746 if (lx >= 0 && lx < lev_fieldx && ly >= 0 && ly < lev_fieldy)
1747 DrawMicroElement(xpos + x * MICRO_TILEX, ypos + y * MICRO_TILEY,
1748 level.field[lx][ly]);
1749 else if (lx >= -1 && lx < lev_fieldx+1 && ly >= -1 && ly < lev_fieldy+1
1750 && BorderElement != EL_EMPTY)
1751 DrawMicroElement(xpos + x * MICRO_TILEX, ypos + y * MICRO_TILEY,
1752 getBorderElement(lx, ly));
1756 redraw_mask |= REDRAW_MICROLEVEL;
1759 #define MICROLABEL_EMPTY 0
1760 #define MICROLABEL_LEVEL_NAME 1
1761 #define MICROLABEL_CREATED_BY 2
1762 #define MICROLABEL_LEVEL_AUTHOR 3
1763 #define MICROLABEL_IMPORTED_FROM 4
1764 #define MICROLABEL_LEVEL_IMPORT_INFO 5
1766 static void DrawMicroLevelLabelExt(int mode)
1768 char label_text[MAX_OUTPUT_LINESIZE + 1];
1769 int max_len_label_text;
1770 int font_nr = FONT_TEXT_2;
1772 if (mode == MICROLABEL_CREATED_BY || mode == MICROLABEL_IMPORTED_FROM)
1773 font_nr = FONT_TEXT_3;
1775 max_len_label_text = SXSIZE / getFontWidth(font_nr);
1777 DrawBackground(SX, MICROLABEL_YPOS, SXSIZE, getFontHeight(font_nr));
1779 strncpy(label_text, (mode == MICROLABEL_LEVEL_NAME ? level.name :
1780 mode == MICROLABEL_CREATED_BY ? "created by" :
1781 mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
1782 mode == MICROLABEL_IMPORTED_FROM ? "imported from" :
1783 mode == MICROLABEL_LEVEL_IMPORT_INFO ?
1784 leveldir_current->imported_from : ""),
1785 max_len_label_text);
1786 label_text[max_len_label_text] = '\0';
1788 if (strlen(label_text) > 0)
1790 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
1791 int lypos = MICROLABEL_YPOS;
1793 DrawText(lxpos, lypos, label_text, font_nr);
1796 redraw_mask |= REDRAW_MICROLEVEL;
1799 void DrawMicroLevel(int xpos, int ypos, boolean restart)
1801 static unsigned long scroll_delay = 0;
1802 static unsigned long label_delay = 0;
1803 static int from_x, from_y, scroll_direction;
1804 static int label_state, label_counter;
1805 int last_game_status = game_status; /* save current game status */
1807 /* force PREVIEW font on preview level */
1808 game_status = GAME_MODE_PSEUDO_PREVIEW;
1812 from_x = from_y = 0;
1813 scroll_direction = MV_RIGHT;
1817 DrawMicroLevelExt(xpos, ypos, from_x, from_y);
1818 DrawMicroLevelLabelExt(label_state);
1820 /* initialize delay counters */
1821 DelayReached(&scroll_delay, 0);
1822 DelayReached(&label_delay, 0);
1824 if (leveldir_current->name)
1826 int text_width = getTextWidth(leveldir_current->name, FONT_TEXT_1);
1827 int lxpos = SX + (SXSIZE - text_width) / 2;
1828 int lypos = SY + 352;
1830 DrawText(lxpos, lypos, leveldir_current->name, FONT_TEXT_1);
1833 game_status = last_game_status; /* restore current game status */
1838 /* scroll micro level, if needed */
1839 if ((lev_fieldx > STD_LEV_FIELDX || lev_fieldy > STD_LEV_FIELDY) &&
1840 DelayReached(&scroll_delay, MICROLEVEL_SCROLL_DELAY))
1842 switch (scroll_direction)
1848 scroll_direction = MV_UP;
1852 if (from_x < lev_fieldx - STD_LEV_FIELDX)
1855 scroll_direction = MV_DOWN;
1862 scroll_direction = MV_RIGHT;
1866 if (from_y < lev_fieldy - STD_LEV_FIELDY)
1869 scroll_direction = MV_LEFT;
1876 DrawMicroLevelExt(xpos, ypos, from_x, from_y);
1879 /* redraw micro level label, if needed */
1880 if (strcmp(level.name, NAMELESS_LEVEL_NAME) != 0 &&
1881 strcmp(level.author, ANONYMOUS_NAME) != 0 &&
1882 strcmp(level.author, leveldir_current->name) != 0 &&
1883 DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
1885 int max_label_counter = 23;
1887 if (leveldir_current->imported_from != NULL)
1888 max_label_counter += 14;
1890 label_counter = (label_counter + 1) % max_label_counter;
1891 label_state = (label_counter >= 0 && label_counter <= 7 ?
1892 MICROLABEL_LEVEL_NAME :
1893 label_counter >= 9 && label_counter <= 12 ?
1894 MICROLABEL_CREATED_BY :
1895 label_counter >= 14 && label_counter <= 21 ?
1896 MICROLABEL_LEVEL_AUTHOR :
1897 label_counter >= 23 && label_counter <= 26 ?
1898 MICROLABEL_IMPORTED_FROM :
1899 label_counter >= 28 && label_counter <= 35 ?
1900 MICROLABEL_LEVEL_IMPORT_INFO : MICROLABEL_EMPTY);
1901 DrawMicroLevelLabelExt(label_state);
1904 game_status = last_game_status; /* restore current game status */
1907 void WaitForEventToContinue()
1909 boolean still_wait = TRUE;
1911 /* simulate releasing mouse button over last gadget, if still pressed */
1913 HandleGadgets(-1, -1, 0);
1915 button_status = MB_RELEASED;
1927 case EVENT_BUTTONPRESS:
1928 case EVENT_KEYPRESS:
1932 case EVENT_KEYRELEASE:
1933 ClearPlayerAction();
1937 HandleOtherEvents(&event);
1941 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
1948 /* don't eat all CPU time */
1953 #define MAX_REQUEST_LINES 13
1954 #define MAX_REQUEST_LINE_LEN 7
1956 boolean Request(char *text, unsigned int req_state)
1958 int mx, my, ty, result = -1;
1959 unsigned int old_door_state;
1960 int last_game_status = game_status; /* save current game status */
1963 SetMouseCursor(CURSOR_DEFAULT);
1966 #if defined(PLATFORM_UNIX)
1967 /* pause network game while waiting for request to answer */
1968 if (options.network &&
1969 game_status == GAME_MODE_PLAYING &&
1970 req_state & REQUEST_WAIT_FOR)
1971 SendToServer_PausePlaying();
1974 old_door_state = GetDoorState();
1976 /* simulate releasing mouse button over last gadget, if still pressed */
1978 HandleGadgets(-1, -1, 0);
1982 CloseDoor(DOOR_CLOSE_1);
1984 /* save old door content */
1985 BlitBitmap(bitmap_db_door, bitmap_db_door,
1986 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
1987 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
1989 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
1991 /* clear door drawing field */
1992 DrawBackground(DX, DY, DXSIZE, DYSIZE);
1994 /* force DOOR font on preview level */
1995 game_status = GAME_MODE_PSEUDO_DOOR;
1997 /* write text for request */
1998 for(ty=0; ty < MAX_REQUEST_LINES; ty++)
2000 char text_line[MAX_REQUEST_LINE_LEN + 1];
2006 for(tl=0,tx=0; tx < MAX_REQUEST_LINE_LEN; tl++,tx++)
2009 if (!tc || tc == ' ')
2020 strncpy(text_line, text, tl);
2023 DrawText(DX + (DXSIZE - tl * getFontWidth(FONT_TEXT_2)) / 2,
2024 DY + 8 + ty * (getFontHeight(FONT_TEXT_2) + 2),
2025 text_line, FONT_TEXT_2);
2027 text += tl + (tc == ' ' ? 1 : 0);
2030 game_status = last_game_status; /* restore current game status */
2032 if (req_state & REQ_ASK)
2034 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
2035 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
2037 else if (req_state & REQ_CONFIRM)
2039 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
2041 else if (req_state & REQ_PLAYER)
2043 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
2044 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
2045 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
2046 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
2049 /* copy request gadgets to door backbuffer */
2050 BlitBitmap(drawto, bitmap_db_door,
2051 DX, DY, DXSIZE, DYSIZE,
2052 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2054 OpenDoor(DOOR_OPEN_1);
2060 if (!(req_state & REQUEST_WAIT_FOR))
2062 SetDrawBackgroundMask(REDRAW_FIELD);
2067 if (game_status != GAME_MODE_MAIN)
2070 button_status = MB_RELEASED;
2072 request_gadget_id = -1;
2074 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
2077 SetMouseCursor(CURSOR_DEFAULT);
2090 case EVENT_BUTTONPRESS:
2091 case EVENT_BUTTONRELEASE:
2092 case EVENT_MOTIONNOTIFY:
2094 if (event.type == EVENT_MOTIONNOTIFY)
2096 if (!PointerInWindow(window))
2097 continue; /* window and pointer are on different screens */
2102 motion_status = TRUE;
2103 mx = ((MotionEvent *) &event)->x;
2104 my = ((MotionEvent *) &event)->y;
2108 motion_status = FALSE;
2109 mx = ((ButtonEvent *) &event)->x;
2110 my = ((ButtonEvent *) &event)->y;
2111 if (event.type == EVENT_BUTTONPRESS)
2112 button_status = ((ButtonEvent *) &event)->button;
2114 button_status = MB_RELEASED;
2117 /* this sets 'request_gadget_id' */
2118 HandleGadgets(mx, my, button_status);
2120 switch(request_gadget_id)
2122 case TOOL_CTRL_ID_YES:
2125 case TOOL_CTRL_ID_NO:
2128 case TOOL_CTRL_ID_CONFIRM:
2129 result = TRUE | FALSE;
2132 case TOOL_CTRL_ID_PLAYER_1:
2135 case TOOL_CTRL_ID_PLAYER_2:
2138 case TOOL_CTRL_ID_PLAYER_3:
2141 case TOOL_CTRL_ID_PLAYER_4:
2152 case EVENT_KEYPRESS:
2153 switch(GetEventKey((KeyEvent *)&event, TRUE))
2166 if (req_state & REQ_PLAYER)
2170 case EVENT_KEYRELEASE:
2171 ClearPlayerAction();
2175 HandleOtherEvents(&event);
2179 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
2181 int joy = AnyJoystick();
2183 if (joy & JOY_BUTTON_1)
2185 else if (joy & JOY_BUTTON_2)
2191 /* don't eat all CPU time */
2195 if (game_status != GAME_MODE_MAIN)
2200 if (!(req_state & REQ_STAY_OPEN))
2202 CloseDoor(DOOR_CLOSE_1);
2204 if (!(req_state & REQ_STAY_CLOSED) && (old_door_state & DOOR_OPEN_1))
2206 BlitBitmap(bitmap_db_door, bitmap_db_door,
2207 DOOR_GFX_PAGEX2,DOOR_GFX_PAGEY1, DXSIZE,DYSIZE,
2208 DOOR_GFX_PAGEX1,DOOR_GFX_PAGEY1);
2209 OpenDoor(DOOR_OPEN_1);
2215 SetDrawBackgroundMask(REDRAW_FIELD);
2217 #if defined(PLATFORM_UNIX)
2218 /* continue network game after request */
2219 if (options.network &&
2220 game_status == GAME_MODE_PLAYING &&
2221 req_state & REQUEST_WAIT_FOR)
2222 SendToServer_ContinuePlaying();
2228 unsigned int OpenDoor(unsigned int door_state)
2230 unsigned int new_door_state;
2232 if (door_state & DOOR_COPY_BACK)
2234 BlitBitmap(bitmap_db_door, bitmap_db_door,
2235 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE + VYSIZE,
2236 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2237 door_state &= ~DOOR_COPY_BACK;
2240 new_door_state = MoveDoor(door_state);
2242 return(new_door_state);
2245 unsigned int CloseDoor(unsigned int door_state)
2247 unsigned int new_door_state;
2249 BlitBitmap(backbuffer, bitmap_db_door,
2250 DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2251 BlitBitmap(backbuffer, bitmap_db_door,
2252 VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
2254 new_door_state = MoveDoor(door_state);
2256 return(new_door_state);
2259 unsigned int GetDoorState()
2261 return MoveDoor(DOOR_GET_STATE);
2264 unsigned int SetDoorState(unsigned int door_state)
2266 return MoveDoor(door_state | DOOR_SET_STATE);
2269 unsigned int MoveDoor(unsigned int door_state)
2271 static int door1 = DOOR_OPEN_1;
2272 static int door2 = DOOR_CLOSE_2;
2273 unsigned long door_delay = 0;
2274 unsigned long door_delay_value;
2277 if (door_state == DOOR_GET_STATE)
2278 return(door1 | door2);
2280 if (door_state & DOOR_SET_STATE)
2282 if (door_state & DOOR_ACTION_1)
2283 door1 = door_state & DOOR_ACTION_1;
2284 if (door_state & DOOR_ACTION_2)
2285 door2 = door_state & DOOR_ACTION_2;
2287 return(door1 | door2);
2290 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
2291 door_state &= ~DOOR_OPEN_1;
2292 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
2293 door_state &= ~DOOR_CLOSE_1;
2294 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
2295 door_state &= ~DOOR_OPEN_2;
2296 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
2297 door_state &= ~DOOR_CLOSE_2;
2299 door_delay_value = (door_state & DOOR_ACTION_1 ? door_1.step_delay :
2302 if (setup.quick_doors)
2304 stepsize = 20; /* must be choosen to always draw last frame */
2305 door_delay_value = 0;
2307 StopSound(SND_DOOR_OPENING);
2308 StopSound(SND_DOOR_CLOSING);
2311 if (global.autoplay_leveldir)
2313 door_state |= DOOR_NO_DELAY;
2314 door_state &= ~DOOR_CLOSE_ALL;
2317 if (door_state & DOOR_ACTION)
2319 boolean door_1_done = !(door_state & DOOR_ACTION_1);
2320 boolean door_2_done = !(door_state & DOOR_ACTION_2);
2321 int start = ((door_state & DOOR_NO_DELAY) ? DXSIZE : 0);
2322 int end = (door_state & DOOR_ACTION_1 &&
2323 door_1.anim_mode == ANIM_VERTICAL ? DYSIZE : DXSIZE);
2326 if (!(door_state & DOOR_NO_DELAY))
2328 /* opening door sound has priority over simultaneously closing door */
2329 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
2330 PlaySoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
2331 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
2332 PlaySoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
2335 for(x = start; x <= end && !(door_1_done && door_2_done); x += stepsize)
2337 Bitmap *bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
2338 GC gc = bitmap->stored_clip_gc;
2340 if (door_state & DOOR_ACTION_1)
2342 int a = MIN(x * door_1.step_offset, end);
2343 int i = (door_state & DOOR_OPEN_1 ? end - a : a);
2347 BlitBitmap(bitmap_db_door, drawto,
2348 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + i / 2,
2349 DXSIZE,DYSIZE - i / 2, DX, DY);
2351 ClearRectangle(drawto, DX, DY + DYSIZE - i / 2, DXSIZE, i / 2);
2354 if (door_1.anim_mode == ANIM_HORIZONTAL && x <= DXSIZE)
2356 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
2357 int dst1_x = DX + DXSIZE - i, dst1_y = DY;
2358 int src2_x = DXSIZE - i, src2_y = DOOR_GFX_PAGEY1;
2359 int dst2_x = DX, dst2_y = DY;
2360 int width = i, height = DYSIZE;
2362 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2363 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2366 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2367 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2370 else if (door_1.anim_mode == ANIM_VERTICAL && x <= DYSIZE)
2372 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
2373 int dst1_x = DX, dst1_y = DY + DYSIZE - i;
2374 int src2_x = 0, src2_y = DOOR_GFX_PAGEY1 + DYSIZE - i;
2375 int dst2_x = DX, dst2_y = DY;
2376 int width = DXSIZE, height = i;
2378 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2379 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2382 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2383 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2386 else if (x <= DXSIZE) /* ANIM_DEFAULT */
2388 int j = (door_1.anim_mode == ANIM_DEFAULT ? (DXSIZE - i) / 3 : 0);
2390 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2391 BlitBitmapMasked(bitmap, drawto,
2392 DXSIZE, DOOR_GFX_PAGEY1, i, 77,
2393 DX + DXSIZE - i, DY + j);
2394 BlitBitmapMasked(bitmap, drawto,
2395 DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63,
2396 DX + DXSIZE - i, DY + 140 + j);
2397 SetClipOrigin(bitmap, gc, DX - DXSIZE + i,
2398 DY - (DOOR_GFX_PAGEY1 + j));
2399 BlitBitmapMasked(bitmap, drawto,
2400 DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j,
2402 BlitBitmapMasked(bitmap, drawto,
2403 DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63,
2406 BlitBitmapMasked(bitmap, drawto,
2407 DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
2409 BlitBitmapMasked(bitmap, drawto,
2410 DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
2412 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2413 BlitBitmapMasked(bitmap, drawto,
2414 DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
2415 DX + DXSIZE - i, DY + 77 + j);
2416 BlitBitmapMasked(bitmap, drawto,
2417 DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
2418 DX + DXSIZE - i, DY + 203 + j);
2421 redraw_mask |= REDRAW_DOOR_1;
2422 door_1_done = (a == end);
2425 if (door_state & DOOR_ACTION_2)
2427 int a = MIN(x * door_2.step_offset, VXSIZE);
2428 int i = (door_state & DOOR_OPEN_2 ? VXSIZE - a : a);
2432 BlitBitmap(bitmap_db_door, drawto,
2433 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + i / 2,
2434 VXSIZE, VYSIZE - i / 2, VX, VY);
2436 ClearRectangle(drawto, VX, VY + VYSIZE - i / 2, VXSIZE, i / 2);
2439 if (door_2.anim_mode == ANIM_HORIZONTAL && x <= VXSIZE)
2441 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
2442 int dst1_x = VX + VXSIZE - i, dst1_y = VY;
2443 int src2_x = VXSIZE - i, src2_y = DOOR_GFX_PAGEY2;
2444 int dst2_x = VX, dst2_y = VY;
2445 int width = i, height = VYSIZE;
2447 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2448 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2451 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2452 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2455 else if (door_2.anim_mode == ANIM_VERTICAL && x <= VYSIZE)
2457 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
2458 int dst1_x = VX, dst1_y = VY + VYSIZE - i;
2459 int src2_x = 0, src2_y = DOOR_GFX_PAGEY2 + VYSIZE - i;
2460 int dst2_x = VX, dst2_y = VY;
2461 int width = VXSIZE, height = i;
2463 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2464 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2467 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2468 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2471 else if (x <= VXSIZE) /* ANIM_DEFAULT */
2473 int j = (door_2.anim_mode == ANIM_DEFAULT ? (VXSIZE - i) / 3 : 0);
2475 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2476 BlitBitmapMasked(bitmap, drawto,
2477 VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2,
2478 VX + VXSIZE - i, VY + j);
2479 SetClipOrigin(bitmap, gc,
2480 VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
2481 BlitBitmapMasked(bitmap, drawto,
2482 VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j,
2485 BlitBitmapMasked(bitmap, drawto,
2486 VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2,
2487 i, VYSIZE / 2, VX, VY + VYSIZE / 2 - j);
2488 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2489 BlitBitmapMasked(bitmap, drawto,
2490 VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2,
2492 VX + VXSIZE - i, VY + VYSIZE / 2 + j);
2495 redraw_mask |= REDRAW_DOOR_2;
2496 door_2_done = (a == VXSIZE);
2501 if (game_status == GAME_MODE_MAIN)
2504 if (!(door_state & DOOR_NO_DELAY))
2505 WaitUntilDelayReached(&door_delay, door_delay_value);
2509 if (setup.quick_doors)
2511 StopSound(SND_DOOR_OPENING);
2512 StopSound(SND_DOOR_CLOSING);
2515 if (door_state & DOOR_ACTION_1)
2516 door1 = door_state & DOOR_ACTION_1;
2517 if (door_state & DOOR_ACTION_2)
2518 door2 = door_state & DOOR_ACTION_2;
2520 return (door1 | door2);
2523 void DrawSpecialEditorDoor()
2525 /* draw bigger toolbox window */
2526 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
2527 DOOR_GFX_PAGEX7, 0, EXSIZE + 8, 8,
2529 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
2530 EX - 4, VY - 4, EXSIZE + 8, EYSIZE - VYSIZE + 4,
2533 redraw_mask |= REDRAW_ALL;
2536 void UndrawSpecialEditorDoor()
2538 /* draw normal tape recorder window */
2539 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
2540 EX - 4, EY - 12, EXSIZE + 8, EYSIZE - VYSIZE + 12,
2543 redraw_mask |= REDRAW_ALL;
2547 /* ---------- new tool button stuff ---------------------------------------- */
2549 /* graphic position values for tool buttons */
2550 #define TOOL_BUTTON_YES_XPOS 2
2551 #define TOOL_BUTTON_YES_YPOS 250
2552 #define TOOL_BUTTON_YES_GFX_YPOS 0
2553 #define TOOL_BUTTON_YES_XSIZE 46
2554 #define TOOL_BUTTON_YES_YSIZE 28
2555 #define TOOL_BUTTON_NO_XPOS 52
2556 #define TOOL_BUTTON_NO_YPOS TOOL_BUTTON_YES_YPOS
2557 #define TOOL_BUTTON_NO_GFX_YPOS TOOL_BUTTON_YES_GFX_YPOS
2558 #define TOOL_BUTTON_NO_XSIZE TOOL_BUTTON_YES_XSIZE
2559 #define TOOL_BUTTON_NO_YSIZE TOOL_BUTTON_YES_YSIZE
2560 #define TOOL_BUTTON_CONFIRM_XPOS TOOL_BUTTON_YES_XPOS
2561 #define TOOL_BUTTON_CONFIRM_YPOS TOOL_BUTTON_YES_YPOS
2562 #define TOOL_BUTTON_CONFIRM_GFX_YPOS 30
2563 #define TOOL_BUTTON_CONFIRM_XSIZE 96
2564 #define TOOL_BUTTON_CONFIRM_YSIZE TOOL_BUTTON_YES_YSIZE
2565 #define TOOL_BUTTON_PLAYER_XSIZE 30
2566 #define TOOL_BUTTON_PLAYER_YSIZE 30
2567 #define TOOL_BUTTON_PLAYER_GFX_XPOS 5
2568 #define TOOL_BUTTON_PLAYER_GFX_YPOS 185
2569 #define TOOL_BUTTON_PLAYER_XPOS (5 + TOOL_BUTTON_PLAYER_XSIZE / 2)
2570 #define TOOL_BUTTON_PLAYER_YPOS (215 - TOOL_BUTTON_PLAYER_YSIZE / 2)
2571 #define TOOL_BUTTON_PLAYER1_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2572 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2573 #define TOOL_BUTTON_PLAYER2_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2574 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2575 #define TOOL_BUTTON_PLAYER3_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2576 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2577 #define TOOL_BUTTON_PLAYER4_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2578 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2579 #define TOOL_BUTTON_PLAYER1_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2580 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2581 #define TOOL_BUTTON_PLAYER2_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2582 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2583 #define TOOL_BUTTON_PLAYER3_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2584 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2585 #define TOOL_BUTTON_PLAYER4_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2586 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2595 } toolbutton_info[NUM_TOOL_BUTTONS] =
2598 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_GFX_YPOS,
2599 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_YPOS,
2600 TOOL_BUTTON_YES_XSIZE, TOOL_BUTTON_YES_YSIZE,
2605 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_GFX_YPOS,
2606 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_YPOS,
2607 TOOL_BUTTON_NO_XSIZE, TOOL_BUTTON_NO_YSIZE,
2612 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_GFX_YPOS,
2613 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_YPOS,
2614 TOOL_BUTTON_CONFIRM_XSIZE, TOOL_BUTTON_CONFIRM_YSIZE,
2615 TOOL_CTRL_ID_CONFIRM,
2619 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2620 TOOL_BUTTON_PLAYER1_XPOS, TOOL_BUTTON_PLAYER1_YPOS,
2621 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2622 TOOL_CTRL_ID_PLAYER_1,
2626 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2627 TOOL_BUTTON_PLAYER2_XPOS, TOOL_BUTTON_PLAYER2_YPOS,
2628 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2629 TOOL_CTRL_ID_PLAYER_2,
2633 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2634 TOOL_BUTTON_PLAYER3_XPOS, TOOL_BUTTON_PLAYER3_YPOS,
2635 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2636 TOOL_CTRL_ID_PLAYER_3,
2640 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2641 TOOL_BUTTON_PLAYER4_XPOS, TOOL_BUTTON_PLAYER4_YPOS,
2642 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2643 TOOL_CTRL_ID_PLAYER_4,
2648 void CreateToolButtons()
2652 for (i=0; i<NUM_TOOL_BUTTONS; i++)
2654 Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
2655 Bitmap *deco_bitmap = None;
2656 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
2657 struct GadgetInfo *gi;
2658 unsigned long event_mask;
2659 int gd_xoffset, gd_yoffset;
2660 int gd_x1, gd_x2, gd_y;
2663 event_mask = GD_EVENT_RELEASED;
2665 gd_xoffset = toolbutton_info[i].xpos;
2666 gd_yoffset = toolbutton_info[i].ypos;
2667 gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
2668 gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
2669 gd_y = DOOR_GFX_PAGEY1 + gd_yoffset;
2671 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
2673 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
2675 getMiniGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr),
2676 &deco_bitmap, &deco_x, &deco_y);
2677 deco_xpos = (toolbutton_info[i].width - MINI_TILEX) / 2;
2678 deco_ypos = (toolbutton_info[i].height - MINI_TILEY) / 2;
2681 gi = CreateGadget(GDI_CUSTOM_ID, id,
2682 GDI_INFO_TEXT, toolbutton_info[i].infotext,
2683 GDI_X, DX + toolbutton_info[i].x,
2684 GDI_Y, DY + toolbutton_info[i].y,
2685 GDI_WIDTH, toolbutton_info[i].width,
2686 GDI_HEIGHT, toolbutton_info[i].height,
2687 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
2688 GDI_STATE, GD_BUTTON_UNPRESSED,
2689 GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
2690 GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
2691 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
2692 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
2693 GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
2694 GDI_DECORATION_SHIFTING, 1, 1,
2695 GDI_EVENT_MASK, event_mask,
2696 GDI_CALLBACK_ACTION, HandleToolButtons,
2700 Error(ERR_EXIT, "cannot create gadget");
2702 tool_gadget[id] = gi;
2706 void FreeToolButtons()
2710 for (i=0; i<NUM_TOOL_BUTTONS; i++)
2711 FreeGadget(tool_gadget[i]);
2714 static void UnmapToolButtons()
2718 for (i=0; i<NUM_TOOL_BUTTONS; i++)
2719 UnmapGadget(tool_gadget[i]);
2722 static void HandleToolButtons(struct GadgetInfo *gi)
2724 request_gadget_id = gi->custom_id;
2727 int get_next_element(int element)
2731 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
2732 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
2733 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
2734 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
2735 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
2736 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
2737 case EL_AMOEBA_DROPPING: return EL_AMOEBA_WET;
2739 default: return element;
2743 int el_act_dir2img(int element, int action, int direction)
2745 element = GFX_ELEMENT(element);
2746 direction = MV_DIR_BIT(direction);
2748 return element_info[element].direction_graphic[action][direction];
2751 static int el_act_dir2crm(int element, int action, int direction)
2753 element = GFX_ELEMENT(element);
2754 direction = MV_DIR_BIT(direction);
2756 return element_info[element].direction_crumbled[action][direction];
2759 int el_act2img(int element, int action)
2761 element = GFX_ELEMENT(element);
2763 return element_info[element].graphic[action];
2766 int el_act2crm(int element, int action)
2768 element = GFX_ELEMENT(element);
2770 return element_info[element].crumbled[action];
2773 int el_dir2img(int element, int direction)
2775 element = GFX_ELEMENT(element);
2777 return el_act_dir2img(element, ACTION_DEFAULT, direction);
2780 int el2img(int element)
2782 element = GFX_ELEMENT(element);
2784 return element_info[element].graphic[ACTION_DEFAULT];
2787 int el2edimg(int element)
2789 element = GFX_ELEMENT(element);
2791 return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
2794 int el2preimg(int element)
2796 element = GFX_ELEMENT(element);
2798 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];