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], MovDir[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], MovDir[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 void DrawAllPlayers()
536 for(i=0; i<MAX_PLAYERS; i++)
537 if (stored_player[i].active)
538 DrawPlayer(&stored_player[i]);
541 void DrawPlayerField(int x, int y)
543 if (!IS_PLAYER(x, y))
546 DrawPlayer(PLAYERINFO(x, y));
549 void DrawPlayer(struct PlayerInfo *player)
552 int jx = player->jx, jy = player->jy;
553 int last_jx = player->last_jx, last_jy = player->last_jy;
554 int next_jx = jx + (jx - last_jx), next_jy = jy + (jy - last_jy);
555 int sx = SCREENX(jx), sy = SCREENY(jy);
556 int sxx = 0, syy = 0;
557 int element = Feld[jx][jy], last_element = Feld[last_jx][last_jy];
560 boolean player_is_moving = (last_jx != jx || last_jy != jy ? TRUE : FALSE);
561 int move_dir = player->MovDir;
562 int action = ACTION_DEFAULT;
564 int jx = player->jx, jy = player->jy;
565 int move_dir = player->MovDir;
566 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? +1 : 0);
567 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? +1 : 0);
568 int last_jx = (player->is_moving ? jx - dx : jx);
569 int last_jy = (player->is_moving ? jy - dy : jy);
570 int next_jx = jx + dx;
571 int next_jy = jy + dy;
572 int sx = SCREENX(jx), sy = SCREENY(jy);
573 int sxx = 0, syy = 0;
574 int element = Feld[jx][jy], last_element = Feld[last_jx][last_jy];
577 boolean player_is_moving = (player->MovPos ? TRUE : FALSE);
578 int action = ACTION_DEFAULT;
581 if (!player->active || !IN_SCR_FIELD(SCREENX(last_jx), SCREENY(last_jy)))
585 if (!IN_LEV_FIELD(jx,jy))
587 printf("DrawPlayerField(): x = %d, y = %d\n",jx,jy);
588 printf("DrawPlayerField(): sx = %d, sy = %d\n",sx,sy);
589 printf("DrawPlayerField(): This should never happen!\n");
594 if (element == EL_EXPLOSION)
597 action = (player->Pushing ? ACTION_PUSHING :
598 player->is_digging ? ACTION_DIGGING :
599 player->is_collecting ? ACTION_COLLECTING :
600 player->is_moving ? ACTION_MOVING :
601 player->snapped ? ACTION_SNAPPING : ACTION_DEFAULT);
604 printf("::: '%s'\n", element_action_info[action].suffix);
607 InitPlayerGfxAnimation(player, action, move_dir);
609 /* ----------------------------------------------------------------------- */
610 /* draw things in the field the player is leaving, if needed */
611 /* ----------------------------------------------------------------------- */
614 if (player->is_moving)
616 if (player_is_moving)
619 if (Back[last_jx][last_jy] && IS_DRAWABLE(last_element))
621 DrawLevelElement(last_jx, last_jy, Back[last_jx][last_jy]);
623 if (last_element == EL_DYNAMITE_ACTIVE ||
624 last_element == EL_SP_DISK_RED_ACTIVE)
625 DrawDynamite(last_jx, last_jy);
627 DrawLevelFieldThruMask(last_jx, last_jy);
629 else if (last_element == EL_DYNAMITE_ACTIVE ||
630 last_element == EL_SP_DISK_RED_ACTIVE)
631 DrawDynamite(last_jx, last_jy);
633 DrawLevelField(last_jx, last_jy);
635 if (player->Pushing && IN_SCR_FIELD(SCREENX(next_jx), SCREENY(next_jy)))
639 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
643 if (Feld[next_jx][next_jy] == EL_SOKOBAN_FIELD_FULL)
644 DrawLevelElement(next_jx, next_jy, EL_SOKOBAN_FIELD_EMPTY);
646 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
649 DrawLevelField(next_jx, next_jy);
655 if (!IN_SCR_FIELD(sx, sy))
658 if (setup.direct_draw)
659 SetDrawtoField(DRAW_BUFFERED);
661 /* ----------------------------------------------------------------------- */
662 /* draw things behind the player, if needed */
663 /* ----------------------------------------------------------------------- */
666 DrawLevelElement(jx, jy, Back[jx][jy]);
667 else if (IS_ACTIVE_BOMB(element))
668 DrawLevelElement(jx, jy, EL_EMPTY);
671 if (player_is_moving && GfxElement[jx][jy] != EL_UNDEFINED)
674 if (GFX_CRUMBLED(GfxElement[jx][jy]))
675 DrawLevelFieldCrumbledSandDigging(jx, jy, move_dir, player->StepFrame);
677 if (GfxElement[jx][jy] == EL_SAND)
678 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 /* ----------------------------------------------------------------------- */
701 if (player->use_murphy_graphic)
703 static int last_horizontal_dir = MV_LEFT;
706 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
707 last_horizontal_dir = move_dir;
709 direction = (player->snapped ? move_dir : last_horizontal_dir);
711 graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, direction);
714 graphic = el_act_dir2img(player->element_nr, player->GfxAction, move_dir);
716 frame = getGraphicAnimationFrame(graphic, player->Frame);
720 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
721 sxx = player->GfxPos;
723 syy = player->GfxPos;
726 if (!setup.soft_scrolling && ScreenMovPos)
729 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
731 if (SHIELD_ON(player))
733 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
734 IMG_SHIELD_NORMAL_ACTIVE);
735 int frame = getGraphicAnimationFrame(graphic, -1);
737 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
740 /* ----------------------------------------------------------------------- */
741 /* draw things the player is pushing, if needed */
742 /* ----------------------------------------------------------------------- */
745 printf("::: %d, %d [%d, %d] [%d]\n",
746 player->Pushing, player_is_moving, player->GfxAction,
747 player->is_moving, player_is_moving);
751 if (player->Pushing && player->is_moving)
753 if (player->Pushing && player_is_moving)
756 int px = SCREENX(next_jx), py = SCREENY(next_jy);
758 if (Back[next_jx][next_jy])
759 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
762 if ((sxx || syy) && element == EL_SOKOBAN_OBJECT)
763 DrawGraphicShiftedThruMask(px, py, sxx, syy, IMG_SOKOBAN_OBJECT, 0,
767 (element == EL_SOKOBAN_FIELD_EMPTY ||
768 Feld[next_jx][next_jy] == EL_SOKOBAN_FIELD_FULL))
769 DrawGraphicShiftedThruMask(px, py, sxx, syy, IMG_SOKOBAN_OBJECT, 0,
775 int element = MovingOrBlocked2Element(next_jx, next_jy);
778 int element = Feld[jx][jy];
780 int element = Feld[next_jx][next_jy];
785 int graphic = el2img(element);
789 if ((sxx || syy) && IS_PUSHABLE(element))
792 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
793 frame = getGraphicAnimationFrame(graphic, player->Frame);
797 printf("::: pushing %d: %d ...\n", sxx, frame);
800 DrawGraphicShifted(px, py, sxx, syy, graphic, frame,
801 NO_CUTTING, NO_MASKING);
806 /* ----------------------------------------------------------------------- */
807 /* draw things in front of player (active dynamite or dynabombs) */
808 /* ----------------------------------------------------------------------- */
810 if (IS_ACTIVE_BOMB(element))
812 graphic = el2img(element);
813 frame = getGraphicAnimationFrame(graphic, GfxFrame[jx][jy]);
815 if (game.emulation == EMU_SUPAPLEX)
816 DrawGraphic(sx, sy, IMG_SP_DISK_RED, frame);
818 DrawGraphicThruMask(sx, sy, graphic, frame);
821 if (player_is_moving && last_element == EL_EXPLOSION)
824 int graphic = el_act2img(GfxElement[last_jx][last_jy], ACTION_EXPLODING);
826 int stored = Store[last_jx][last_jy];
827 int graphic = (game.emulation != EMU_SUPAPLEX ? IMG_EXPLOSION :
828 stored == EL_SP_INFOTRON ? IMG_SP_EXPLOSION_INFOTRON :
831 int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
832 int phase = ExplodePhase[last_jx][last_jy] - 1;
833 int frame = getGraphicAnimationFrame(graphic, phase - delay);
836 DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy), graphic, frame);
839 /* ----------------------------------------------------------------------- */
840 /* draw elements the player is just walking/passing through/under */
841 /* ----------------------------------------------------------------------- */
843 /* handle the field the player is leaving ... */
844 if (player_is_moving && IS_ACCESSIBLE_INSIDE(last_element))
845 DrawLevelField(last_jx, last_jy);
846 else if (player_is_moving && IS_ACCESSIBLE_UNDER(last_element))
847 DrawLevelFieldThruMask(last_jx, last_jy);
849 /* ... and the field the player is entering */
850 if (IS_ACCESSIBLE_INSIDE(element))
851 DrawLevelField(jx, jy);
852 else if (IS_ACCESSIBLE_UNDER(element))
853 DrawLevelFieldThruMask(jx, jy);
855 if (setup.direct_draw)
857 int dest_x = SX + SCREENX(MIN(jx, last_jx)) * TILEX;
858 int dest_y = SY + SCREENY(MIN(jy, last_jy)) * TILEY;
859 int x_size = TILEX * (1 + ABS(jx - last_jx));
860 int y_size = TILEY * (1 + ABS(jy - last_jy));
862 BlitBitmap(drawto_field, window,
863 dest_x, dest_y, x_size, y_size, dest_x, dest_y);
864 SetDrawtoField(DRAW_DIRECT);
867 MarkTileDirty(sx,sy);
870 void getGraphicSource(int graphic, int frame, Bitmap **bitmap, int *x, int *y)
872 struct GraphicInfo *g = &graphic_info[graphic];
876 if (g->offset_y == 0) /* frames are ordered horizontally */
878 int max_width = g->anim_frames_per_line * g->width;
880 *x = (g->src_x + frame * g->offset_x) % max_width;
881 *y = g->src_y + (g->src_x + frame * g->offset_x) / max_width * g->height;
883 else if (g->offset_x == 0) /* frames are ordered vertically */
885 int max_height = g->anim_frames_per_line * g->height;
887 *x = g->src_x + (g->src_y + frame * g->offset_y) / max_height * g->width;
888 *y = (g->src_y + frame * g->offset_y) % max_height;
890 else /* frames are ordered diagonally */
892 *x = g->src_x + frame * g->offset_x;
893 *y = g->src_y + frame * g->offset_y;
897 void DrawGraphic(int x, int y, int graphic, int frame)
900 if (!IN_SCR_FIELD(x, y))
902 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
903 printf("DrawGraphic(): This should never happen!\n");
908 DrawGraphicExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic, frame);
912 void DrawGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
918 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
919 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
922 void DrawGraphicThruMask(int x, int y, int graphic, int frame)
925 if (!IN_SCR_FIELD(x, y))
927 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
928 printf("DrawGraphicThruMask(): This should never happen!\n");
933 DrawGraphicThruMaskExt(drawto_field, FX + x * TILEX, FY + y *TILEY, graphic,
938 void DrawGraphicThruMaskExt(DrawBuffer *d, int dest_x, int dest_y, int graphic,
946 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
947 drawing_gc = src_bitmap->stored_clip_gc;
949 GC drawing_gc = src_bitmap->stored_clip_gc;
950 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
951 int src_x = graphic_info[graphic].src_x;
952 int src_y = graphic_info[graphic].src_y;
953 int offset_x = graphic_info[graphic].offset_x;
954 int offset_y = graphic_info[graphic].offset_y;
956 src_x += frame * offset_x;
957 src_y += frame * offset_y;
961 SetClipOrigin(src_bitmap, drawing_gc, dest_x - src_x, dest_y - src_y);
962 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX, TILEY, dest_x, dest_y);
965 void DrawMiniGraphic(int x, int y, int graphic)
967 DrawMiniGraphicExt(drawto, SX + x * MINI_TILEX,SY + y * MINI_TILEY, graphic);
968 MarkTileDirty(x / 2, y / 2);
971 void getMiniGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
973 struct GraphicInfo *g = &graphic_info[graphic];
975 int mini_starty = g->bitmap->height * 2 / 3;
978 *x = mini_startx + g->src_x / 2;
979 *y = mini_starty + g->src_y / 2;
982 void DrawMiniGraphicExt(DrawBuffer *d, int x, int y, int graphic)
987 getMiniGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
988 BlitBitmap(src_bitmap, d, src_x, src_y, MINI_TILEX, MINI_TILEY, x, y);
991 void DrawGraphicShifted(int x,int y, int dx,int dy, int graphic, int frame,
992 int cut_mode, int mask_mode)
997 int width = TILEX, height = TILEY;
1003 DrawGraphic(x, y, graphic, frame);
1007 if (dx || dy) /* shifted graphic */
1009 if (x < BX1) /* object enters playfield from the left */
1016 else if (x > BX2) /* object enters playfield from the right */
1022 else if (x==BX1 && dx < 0) /* object leaves playfield to the left */
1028 else if (x==BX2 && dx > 0) /* object leaves playfield to the right */
1030 else if (dx) /* general horizontal movement */
1031 MarkTileDirty(x + SIGN(dx), y);
1033 if (y < BY1) /* object enters playfield from the top */
1035 if (cut_mode==CUT_BELOW) /* object completely above top border */
1043 else if (y > BY2) /* object enters playfield from the bottom */
1049 else if (y==BY1 && dy < 0) /* object leaves playfield to the top */
1055 else if (dy > 0 && cut_mode == CUT_ABOVE)
1057 if (y == BY2) /* object completely above bottom border */
1063 MarkTileDirty(x, y + 1);
1064 } /* object leaves playfield to the bottom */
1065 else if (dy > 0 && (y == BY2 || cut_mode == CUT_BELOW))
1067 else if (dy) /* general vertical movement */
1068 MarkTileDirty(x, y + SIGN(dy));
1072 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1074 src_bitmap = graphic_info[graphic].bitmap;
1075 src_x = graphic_info[graphic].src_x;
1076 src_y = graphic_info[graphic].src_y;
1077 offset_x = graphic_info[graphic].offset_x;
1078 offset_y = graphic_info[graphic].offset_y;
1080 src_x += frame * offset_x;
1081 src_y += frame * offset_y;
1084 drawing_gc = src_bitmap->stored_clip_gc;
1089 dest_x = FX + x * TILEX + dx;
1090 dest_y = FY + y * TILEY + dy;
1093 if (!IN_SCR_FIELD(x,y))
1095 printf("DrawGraphicShifted(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
1096 printf("DrawGraphicShifted(): This should never happen!\n");
1101 if (mask_mode == USE_MASKING)
1103 SetClipOrigin(src_bitmap, drawing_gc, dest_x - src_x, dest_y - src_y);
1104 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1108 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1114 void DrawGraphicShiftedThruMask(int x, int y, int dx, int dy, int graphic,
1115 int frame, int cut_mode)
1117 DrawGraphicShifted(x,y, dx,dy, graphic, frame, cut_mode, USE_MASKING);
1120 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
1121 int cut_mode, int mask_mode)
1123 int lx = LEVELX(x), ly = LEVELY(y);
1127 if (IN_LEV_FIELD(lx, ly))
1129 SetRandomAnimationValue(lx, ly);
1131 graphic = el_act_dir2img(element, GfxAction[lx][ly], MovDir[lx][ly]);
1132 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1134 else /* border element */
1136 graphic = el2img(element);
1137 frame = getGraphicAnimationFrame(graphic, -1);
1140 if (element == EL_EXPANDABLE_WALL)
1142 boolean left_stopped = FALSE, right_stopped = FALSE;
1144 if (!IN_LEV_FIELD(lx - 1, ly) || IS_WALL(Feld[lx - 1][ly]))
1145 left_stopped = TRUE;
1146 if (!IN_LEV_FIELD(lx + 1, ly) || IS_WALL(Feld[lx + 1][ly]))
1147 right_stopped = TRUE;
1149 if (left_stopped && right_stopped)
1151 else if (left_stopped)
1153 graphic = IMG_EXPANDABLE_WALL_GROWING_RIGHT;
1154 frame = graphic_info[graphic].anim_frames - 1;
1156 else if (right_stopped)
1158 graphic = IMG_EXPANDABLE_WALL_GROWING_LEFT;
1159 frame = graphic_info[graphic].anim_frames - 1;
1164 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, mask_mode);
1165 else if (mask_mode == USE_MASKING)
1166 DrawGraphicThruMask(x, y, graphic, frame);
1168 DrawGraphic(x, y, graphic, frame);
1171 void DrawLevelElementExt(int x, int y, int dx, int dy, int element,
1172 int cut_mode, int mask_mode)
1174 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1175 DrawScreenElementExt(SCREENX(x), SCREENY(y), dx, dy, element,
1176 cut_mode, mask_mode);
1179 void DrawScreenElementShifted(int x, int y, int dx, int dy, int element,
1182 DrawScreenElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1185 void DrawLevelElementShifted(int x, int y, int dx, int dy, int element,
1188 DrawLevelElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1191 void DrawLevelElementThruMask(int x, int y, int element)
1193 DrawLevelElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1196 void DrawLevelFieldThruMask(int x, int y)
1198 DrawLevelElementExt(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
1201 static void DrawLevelFieldCrumbledSandExt(int x, int y, int graphic, int frame)
1205 int sx = SCREENX(x), sy = SCREENY(y);
1207 int width, height, cx, cy, i;
1209 int crumbled_border_size = graphic_info[graphic].border_size;
1211 int snip = TILEX / 8; /* number of border pixels from "crumbled graphic" */
1213 static int xy[4][2] =
1222 if (x == 0 && y == 7)
1223 printf("::: %d, %d [%d]\n", GfxElement[x][y], Feld[x][y],
1224 crumbled_border_size);
1227 if (!IN_LEV_FIELD(x, y))
1230 element = (GfxElement[x][y] != EL_UNDEFINED && Feld[x][y] != EL_EXPLOSION ?
1231 GfxElement[x][y] : Feld[x][y]);
1233 /* crumble field itself */
1234 if (GFX_CRUMBLED(element) && !IS_MOVING(x, y))
1236 if (!IN_SCR_FIELD(sx, sy))
1239 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1243 int xx = x + xy[i][0];
1244 int yy = y + xy[i][1];
1246 element = (IN_LEV_FIELD(xx, yy) ? Feld[xx][yy] : BorderElement);
1248 /* check if neighbour field is of same type */
1249 if (GFX_CRUMBLED(element) && !IS_MOVING(xx, yy))
1253 if (Feld[x][y] == EL_CUSTOM_START + 123)
1254 printf("::: crumble [%d] THE CHAOS ENGINE (%d, %d): %d, %d\n",
1255 i, Feld[x][y], element,
1256 GFX_CRUMBLED(element), IS_MOVING(x, y));
1259 if (i == 1 || i == 2)
1261 width = crumbled_border_size;
1263 cx = (i == 2 ? TILEX - crumbled_border_size : 0);
1269 height = crumbled_border_size;
1271 cy = (i == 3 ? TILEY - crumbled_border_size : 0);
1274 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1275 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
1278 MarkTileDirty(sx, sy);
1280 else /* crumble neighbour fields */
1283 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1288 int xx = x + xy[i][0];
1289 int yy = y + xy[i][1];
1290 int sxx = sx + xy[i][0];
1291 int syy = sy + xy[i][1];
1293 if (!IN_LEV_FIELD(xx, yy) ||
1294 !IN_SCR_FIELD(sxx, syy) ||
1295 !GFX_CRUMBLED(Feld[xx][yy]) ||
1300 graphic = el_act2crm(Feld[xx][yy], ACTION_DEFAULT);
1301 crumbled_border_size = graphic_info[graphic].border_size;
1303 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1306 if (i == 1 || i == 2)
1308 width = crumbled_border_size;
1310 cx = (i == 1 ? TILEX - crumbled_border_size : 0);
1316 height = crumbled_border_size;
1318 cy = (i == 0 ? TILEY - crumbled_border_size : 0);
1321 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1322 width, height, FX + sxx * TILEX + cx, FY + syy * TILEY + cy);
1324 MarkTileDirty(sxx, syy);
1329 void DrawLevelFieldCrumbledSand(int x, int y)
1334 if (!IN_LEV_FIELD(x, y))
1337 graphic = el_act2crm(Feld[x][y], ACTION_DEFAULT);
1339 DrawLevelFieldCrumbledSandExt(x, y, graphic, 0);
1341 DrawLevelFieldCrumbledSandExt(x, y, IMG_SAND_CRUMBLED, 0);
1345 void DrawLevelFieldCrumbledSandDigging(int x, int y, int direction,
1349 int graphic1 = el_act_dir2img(GfxElement[x][y], ACTION_DIGGING, direction);
1350 int graphic2 = el_act_dir2crm(GfxElement[x][y], ACTION_DIGGING, direction);
1352 int graphic1 = el_act_dir2img(EL_SAND, ACTION_DIGGING, direction);
1353 int graphic2 = el_act_dir2img(EL_SAND_CRUMBLED, ACTION_DIGGING, direction);
1355 int frame1 = getGraphicAnimationFrame(graphic1, step_frame);
1356 int frame2 = getGraphicAnimationFrame(graphic2, step_frame);
1357 int sx = SCREENX(x), sy = SCREENY(y);
1359 DrawGraphic(sx, sy, graphic1, frame1);
1360 DrawLevelFieldCrumbledSandExt(x, y, graphic2, frame2);
1363 void DrawLevelFieldCrumbledSandNeighbours(int x, int y)
1365 int sx = SCREENX(x), sy = SCREENY(y);
1366 static int xy[4][2] =
1377 int xx = x + xy[i][0];
1378 int yy = y + xy[i][1];
1379 int sxx = sx + xy[i][0];
1380 int syy = sy + xy[i][1];
1382 if (!IN_LEV_FIELD(xx, yy) ||
1383 !IN_SCR_FIELD(sxx, syy) ||
1384 !GFX_CRUMBLED(Feld[xx][yy]) ||
1388 DrawLevelField(xx, yy);
1392 static int getBorderElement(int x, int y)
1396 { EL_STEELWALL_TOPLEFT, EL_INVISIBLE_STEELWALL_TOPLEFT },
1397 { EL_STEELWALL_TOPRIGHT, EL_INVISIBLE_STEELWALL_TOPRIGHT },
1398 { EL_STEELWALL_BOTTOMLEFT, EL_INVISIBLE_STEELWALL_BOTTOMLEFT },
1399 { EL_STEELWALL_BOTTOMRIGHT, EL_INVISIBLE_STEELWALL_BOTTOMRIGHT },
1400 { EL_STEELWALL_VERTICAL, EL_INVISIBLE_STEELWALL_VERTICAL },
1401 { EL_STEELWALL_HORIZONTAL, EL_INVISIBLE_STEELWALL_HORIZONTAL },
1402 { EL_STEELWALL, EL_INVISIBLE_STEELWALL }
1404 int steel_type = (BorderElement == EL_STEELWALL ? 0 : 1);
1405 int steel_position = (x == -1 && y == -1 ? 0 :
1406 x == lev_fieldx && y == -1 ? 1 :
1407 x == -1 && y == lev_fieldy ? 2 :
1408 x == lev_fieldx && y == lev_fieldy ? 3 :
1409 x == -1 || x == lev_fieldx ? 4 :
1410 y == -1 || y == lev_fieldy ? 5 : 6);
1412 return border[steel_position][steel_type];
1415 void DrawScreenElement(int x, int y, int element)
1417 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
1418 DrawLevelFieldCrumbledSand(LEVELX(x), LEVELY(y));
1421 void DrawLevelElement(int x, int y, int element)
1423 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1424 DrawScreenElement(SCREENX(x), SCREENY(y), element);
1427 void DrawScreenField(int x, int y)
1429 int lx = LEVELX(x), ly = LEVELY(y);
1430 int element, content;
1432 if (!IN_LEV_FIELD(lx, ly))
1434 if (lx < -1 || lx > lev_fieldx || ly < -1 || ly > lev_fieldy)
1437 element = getBorderElement(lx, ly);
1439 DrawScreenElement(x, y, element);
1443 element = Feld[lx][ly];
1444 content = Store[lx][ly];
1446 if (IS_MOVING(lx, ly))
1448 int horiz_move = (MovDir[lx][ly] == MV_LEFT || MovDir[lx][ly] == MV_RIGHT);
1449 boolean cut_mode = NO_CUTTING;
1451 if (element == EL_QUICKSAND_EMPTYING ||
1452 element == EL_MAGIC_WALL_EMPTYING ||
1453 element == EL_BD_MAGIC_WALL_EMPTYING ||
1454 element == EL_AMOEBA_DROPPING)
1455 cut_mode = CUT_ABOVE;
1456 else if (element == EL_QUICKSAND_FILLING ||
1457 element == EL_MAGIC_WALL_FILLING ||
1458 element == EL_BD_MAGIC_WALL_FILLING)
1459 cut_mode = CUT_BELOW;
1461 if (cut_mode == CUT_ABOVE)
1462 DrawScreenElementShifted(x, y, 0, 0, element, NO_CUTTING);
1464 DrawScreenElement(x, y, EL_EMPTY);
1467 DrawScreenElementShifted(x, y, MovPos[lx][ly], 0, element, NO_CUTTING);
1468 else if (cut_mode == NO_CUTTING)
1469 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], element, cut_mode);
1471 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], content, cut_mode);
1473 if (content == EL_ACID)
1474 DrawLevelElementThruMask(lx, ly + 1, EL_ACID);
1476 else if (IS_BLOCKED(lx, ly))
1481 boolean cut_mode = NO_CUTTING;
1482 int element_old, content_old;
1484 Blocked2Moving(lx, ly, &oldx, &oldy);
1487 horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
1488 MovDir[oldx][oldy] == MV_RIGHT);
1490 element_old = Feld[oldx][oldy];
1491 content_old = Store[oldx][oldy];
1493 if (element_old == EL_QUICKSAND_EMPTYING ||
1494 element_old == EL_MAGIC_WALL_EMPTYING ||
1495 element_old == EL_BD_MAGIC_WALL_EMPTYING ||
1496 element_old == EL_AMOEBA_DROPPING)
1497 cut_mode = CUT_ABOVE;
1499 DrawScreenElement(x, y, EL_EMPTY);
1502 DrawScreenElementShifted(sx, sy, MovPos[oldx][oldy], 0, element_old,
1504 else if (cut_mode == NO_CUTTING)
1505 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], element_old,
1508 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], content_old,
1511 else if (IS_DRAWABLE(element))
1512 DrawScreenElement(x, y, element);
1514 DrawScreenElement(x, y, EL_EMPTY);
1517 void DrawLevelField(int x, int y)
1519 if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1520 DrawScreenField(SCREENX(x), SCREENY(y));
1521 else if (IS_MOVING(x, y))
1525 Moving2Blocked(x, y, &newx, &newy);
1526 if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
1527 DrawScreenField(SCREENX(newx), SCREENY(newy));
1529 else if (IS_BLOCKED(x, y))
1533 Blocked2Moving(x, y, &oldx, &oldy);
1534 if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
1535 DrawScreenField(SCREENX(oldx), SCREENY(oldy));
1539 void DrawMiniElement(int x, int y, int element)
1543 graphic = el2edimg(element);
1544 DrawMiniGraphic(x, y, graphic);
1547 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
1549 int x = sx + scroll_x, y = sy + scroll_y;
1551 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
1552 DrawMiniElement(sx, sy, EL_EMPTY);
1553 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
1554 DrawMiniElement(sx, sy, Feld[x][y]);
1556 DrawMiniGraphic(sx, sy, el2edimg(getBorderElement(x, y)));
1559 void DrawEnvelopeBackground(int envelope_nr, int startx, int starty,
1560 int x, int y, int xsize, int ysize, int font_nr)
1562 int font_width = getFontWidth(font_nr);
1563 int font_height = getFontHeight(font_nr);
1564 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1567 int dst_x = SX + startx + x * font_width;
1568 int dst_y = SY + starty + y * font_height;
1569 int width = graphic_info[graphic].width;
1570 int height = graphic_info[graphic].height;
1571 int inner_width = MAX(width - 2 * font_width, font_width);
1572 int inner_height = MAX(height - 2 * font_height, font_height);
1573 int inner_sx = (width >= 3 * font_width ? font_width : 0);
1574 int inner_sy = (height >= 3 * font_height ? font_height : 0);
1575 boolean draw_masked = graphic_info[graphic].draw_masked;
1577 getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
1579 if (src_bitmap == NULL || width < font_width || height < font_height)
1581 ClearRectangle(drawto, dst_x, dst_y, font_width, font_height);
1585 src_x += (x == 0 ? 0 : x == xsize - 1 ? width - font_width :
1586 inner_sx + (x - 1) * font_width % inner_width);
1587 src_y += (y == 0 ? 0 : y == ysize - 1 ? height - font_height :
1588 inner_sy + (y - 1) * font_height % inner_height);
1592 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1593 dst_x - src_x, dst_y - src_y);
1594 BlitBitmapMasked(src_bitmap, drawto, src_x, src_y, font_width, font_height,
1598 BlitBitmap(src_bitmap, drawto, src_x, src_y, font_width, font_height,
1602 void AnimateEnvelope(int envelope_nr, int anim_mode, int action)
1604 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1605 boolean draw_masked = graphic_info[graphic].draw_masked;
1606 int mask_mode = (draw_masked ? BLIT_MASKED : BLIT_ON_BACKGROUND);
1607 boolean ffwd_delay = (tape.playing && tape.fast_forward);
1608 unsigned long anim_delay = 0;
1609 int anim_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
1610 int font_nr = FONT_ENVELOPE_1 + envelope_nr;
1611 int font_width = getFontWidth(font_nr);
1612 int font_height = getFontHeight(font_nr);
1613 int max_xsize = level.envelope_xsize[envelope_nr];
1614 int max_ysize = level.envelope_ysize[envelope_nr];
1615 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize : 0);
1616 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize : 0);
1617 int xend = max_xsize;
1618 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize : 0);
1619 int xstep = (xstart < xend ? 1 : 0);
1620 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
1623 for (x=xstart, y=ystart; x <= xend && y <= yend; x += xstep, y += ystep)
1625 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
1626 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
1627 int sx = (SXSIZE - xsize * font_width) / 2;
1628 int sy = (SYSIZE - ysize * font_height) / 2;
1631 SetDrawtoField(DRAW_BUFFERED);
1633 BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
1635 SetDrawtoField(DRAW_BACKBUFFER);
1637 for (yy=0; yy < ysize; yy++) for (xx=0; xx < xsize; xx++)
1638 DrawEnvelopeBackground(envelope_nr, sx,sy, xx,yy, xsize, ysize, font_nr);
1640 DrawTextToTextArea(SX + sx + font_width, SY + sy + font_height,
1641 level.envelope_text[envelope_nr], font_nr, max_xsize,
1642 xsize - 2, ysize - 2, mask_mode);
1644 redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
1647 WaitUntilDelayReached(&anim_delay, anim_delay_value / 2);
1651 void ShowEnvelope(int envelope_nr)
1653 int element = EL_ENVELOPE_1 + envelope_nr;
1654 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1655 int sound_opening = element_info[element].sound[ACTION_OPENING];
1656 int sound_closing = element_info[element].sound[ACTION_CLOSING];
1657 boolean ffwd_delay = (tape.playing && tape.fast_forward);
1658 int wait_delay_value = (ffwd_delay ? 500 : 1000);
1659 int anim_mode = graphic_info[graphic].anim_mode;
1660 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
1661 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
1663 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
1665 PlaySoundStereo(sound_opening, SOUND_MIDDLE);
1667 if (anim_mode == ANIM_DEFAULT)
1668 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_OPENING);
1670 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_OPENING);
1673 Delay(wait_delay_value);
1675 WaitForEventToContinue();
1677 PlaySoundStereo(sound_closing, SOUND_MIDDLE);
1679 if (anim_mode != ANIM_NONE)
1680 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_CLOSING);
1682 if (anim_mode == ANIM_DEFAULT)
1683 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_CLOSING);
1685 game.envelope_active = FALSE;
1687 SetDrawtoField(DRAW_BUFFERED);
1689 redraw_mask |= REDRAW_FIELD;
1693 void getMicroGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
1695 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
1696 int mini_startx = src_bitmap->width * 3 / 4;
1697 int mini_starty = src_bitmap->height * 2 / 3;
1698 int src_x = mini_startx + graphic_info[graphic].src_x / 8;
1699 int src_y = mini_starty + graphic_info[graphic].src_y / 8;
1701 *bitmap = src_bitmap;
1706 void DrawMicroElement(int xpos, int ypos, int element)
1710 int graphic = el2preimg(element);
1712 getMicroGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
1713 BlitBitmap(src_bitmap, drawto, src_x, src_y, MICRO_TILEX, MICRO_TILEY,
1721 SetDrawBackgroundMask(REDRAW_NONE);
1724 for(x=BX1; x<=BX2; x++)
1725 for(y=BY1; y<=BY2; y++)
1726 DrawScreenField(x, y);
1728 redraw_mask |= REDRAW_FIELD;
1731 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
1735 for(x=0; x<size_x; x++)
1736 for(y=0; y<size_y; y++)
1737 DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
1739 redraw_mask |= REDRAW_FIELD;
1742 static void DrawMicroLevelExt(int xpos, int ypos, int from_x, int from_y)
1746 DrawBackground(xpos, ypos, MICROLEV_XSIZE, MICROLEV_YSIZE);
1748 if (lev_fieldx < STD_LEV_FIELDX)
1749 xpos += (STD_LEV_FIELDX - lev_fieldx) / 2 * MICRO_TILEX;
1750 if (lev_fieldy < STD_LEV_FIELDY)
1751 ypos += (STD_LEV_FIELDY - lev_fieldy) / 2 * MICRO_TILEY;
1753 xpos += MICRO_TILEX;
1754 ypos += MICRO_TILEY;
1756 for(x=-1; x<=STD_LEV_FIELDX; x++)
1758 for(y=-1; y<=STD_LEV_FIELDY; y++)
1760 int lx = from_x + x, ly = from_y + y;
1762 if (lx >= 0 && lx < lev_fieldx && ly >= 0 && ly < lev_fieldy)
1763 DrawMicroElement(xpos + x * MICRO_TILEX, ypos + y * MICRO_TILEY,
1764 level.field[lx][ly]);
1765 else if (lx >= -1 && lx < lev_fieldx+1 && ly >= -1 && ly < lev_fieldy+1
1766 && BorderElement != EL_EMPTY)
1767 DrawMicroElement(xpos + x * MICRO_TILEX, ypos + y * MICRO_TILEY,
1768 getBorderElement(lx, ly));
1772 redraw_mask |= REDRAW_MICROLEVEL;
1775 #define MICROLABEL_EMPTY 0
1776 #define MICROLABEL_LEVEL_NAME 1
1777 #define MICROLABEL_CREATED_BY 2
1778 #define MICROLABEL_LEVEL_AUTHOR 3
1779 #define MICROLABEL_IMPORTED_FROM 4
1780 #define MICROLABEL_LEVEL_IMPORT_INFO 5
1782 static void DrawMicroLevelLabelExt(int mode)
1784 char label_text[MAX_OUTPUT_LINESIZE + 1];
1785 int max_len_label_text;
1786 int font_nr = FONT_TEXT_2;
1788 if (mode == MICROLABEL_CREATED_BY || mode == MICROLABEL_IMPORTED_FROM)
1789 font_nr = FONT_TEXT_3;
1791 max_len_label_text = SXSIZE / getFontWidth(font_nr);
1793 DrawBackground(SX, MICROLABEL_YPOS, SXSIZE, getFontHeight(font_nr));
1795 strncpy(label_text, (mode == MICROLABEL_LEVEL_NAME ? level.name :
1796 mode == MICROLABEL_CREATED_BY ? "created by" :
1797 mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
1798 mode == MICROLABEL_IMPORTED_FROM ? "imported from" :
1799 mode == MICROLABEL_LEVEL_IMPORT_INFO ?
1800 leveldir_current->imported_from : ""),
1801 max_len_label_text);
1802 label_text[max_len_label_text] = '\0';
1804 if (strlen(label_text) > 0)
1806 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
1807 int lypos = MICROLABEL_YPOS;
1809 DrawText(lxpos, lypos, label_text, font_nr);
1812 redraw_mask |= REDRAW_MICROLEVEL;
1815 void DrawMicroLevel(int xpos, int ypos, boolean restart)
1817 static unsigned long scroll_delay = 0;
1818 static unsigned long label_delay = 0;
1819 static int from_x, from_y, scroll_direction;
1820 static int label_state, label_counter;
1821 int last_game_status = game_status; /* save current game status */
1823 /* force PREVIEW font on preview level */
1824 game_status = GAME_MODE_PSEUDO_PREVIEW;
1828 from_x = from_y = 0;
1829 scroll_direction = MV_RIGHT;
1833 DrawMicroLevelExt(xpos, ypos, from_x, from_y);
1834 DrawMicroLevelLabelExt(label_state);
1836 /* initialize delay counters */
1837 DelayReached(&scroll_delay, 0);
1838 DelayReached(&label_delay, 0);
1840 if (leveldir_current->name)
1842 int text_width = getTextWidth(leveldir_current->name, FONT_TEXT_1);
1843 int lxpos = SX + (SXSIZE - text_width) / 2;
1844 int lypos = SY + 352;
1846 DrawText(lxpos, lypos, leveldir_current->name, FONT_TEXT_1);
1849 game_status = last_game_status; /* restore current game status */
1854 /* scroll micro level, if needed */
1855 if ((lev_fieldx > STD_LEV_FIELDX || lev_fieldy > STD_LEV_FIELDY) &&
1856 DelayReached(&scroll_delay, MICROLEVEL_SCROLL_DELAY))
1858 switch (scroll_direction)
1864 scroll_direction = MV_UP;
1868 if (from_x < lev_fieldx - STD_LEV_FIELDX)
1871 scroll_direction = MV_DOWN;
1878 scroll_direction = MV_RIGHT;
1882 if (from_y < lev_fieldy - STD_LEV_FIELDY)
1885 scroll_direction = MV_LEFT;
1892 DrawMicroLevelExt(xpos, ypos, from_x, from_y);
1895 /* redraw micro level label, if needed */
1896 if (strcmp(level.name, NAMELESS_LEVEL_NAME) != 0 &&
1897 strcmp(level.author, ANONYMOUS_NAME) != 0 &&
1898 strcmp(level.author, leveldir_current->name) != 0 &&
1899 DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
1901 int max_label_counter = 23;
1903 if (leveldir_current->imported_from != NULL)
1904 max_label_counter += 14;
1906 label_counter = (label_counter + 1) % max_label_counter;
1907 label_state = (label_counter >= 0 && label_counter <= 7 ?
1908 MICROLABEL_LEVEL_NAME :
1909 label_counter >= 9 && label_counter <= 12 ?
1910 MICROLABEL_CREATED_BY :
1911 label_counter >= 14 && label_counter <= 21 ?
1912 MICROLABEL_LEVEL_AUTHOR :
1913 label_counter >= 23 && label_counter <= 26 ?
1914 MICROLABEL_IMPORTED_FROM :
1915 label_counter >= 28 && label_counter <= 35 ?
1916 MICROLABEL_LEVEL_IMPORT_INFO : MICROLABEL_EMPTY);
1917 DrawMicroLevelLabelExt(label_state);
1920 game_status = last_game_status; /* restore current game status */
1923 void WaitForEventToContinue()
1925 boolean still_wait = TRUE;
1927 /* simulate releasing mouse button over last gadget, if still pressed */
1929 HandleGadgets(-1, -1, 0);
1931 button_status = MB_RELEASED;
1943 case EVENT_BUTTONPRESS:
1944 case EVENT_KEYPRESS:
1948 case EVENT_KEYRELEASE:
1949 ClearPlayerAction();
1953 HandleOtherEvents(&event);
1957 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
1964 /* don't eat all CPU time */
1969 #define MAX_REQUEST_LINES 13
1970 #define MAX_REQUEST_LINE_LEN 7
1972 boolean Request(char *text, unsigned int req_state)
1974 int mx, my, ty, result = -1;
1975 unsigned int old_door_state;
1976 int last_game_status = game_status; /* save current game status */
1979 SetMouseCursor(CURSOR_DEFAULT);
1982 #if defined(PLATFORM_UNIX)
1983 /* pause network game while waiting for request to answer */
1984 if (options.network &&
1985 game_status == GAME_MODE_PLAYING &&
1986 req_state & REQUEST_WAIT_FOR)
1987 SendToServer_PausePlaying();
1990 old_door_state = GetDoorState();
1992 /* simulate releasing mouse button over last gadget, if still pressed */
1994 HandleGadgets(-1, -1, 0);
1998 CloseDoor(DOOR_CLOSE_1);
2000 /* save old door content */
2001 BlitBitmap(bitmap_db_door, bitmap_db_door,
2002 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
2003 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
2005 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
2007 /* clear door drawing field */
2008 DrawBackground(DX, DY, DXSIZE, DYSIZE);
2010 /* force DOOR font on preview level */
2011 game_status = GAME_MODE_PSEUDO_DOOR;
2013 /* write text for request */
2014 for(ty=0; ty < MAX_REQUEST_LINES; ty++)
2016 char text_line[MAX_REQUEST_LINE_LEN + 1];
2022 for(tl=0,tx=0; tx < MAX_REQUEST_LINE_LEN; tl++,tx++)
2025 if (!tc || tc == ' ')
2036 strncpy(text_line, text, tl);
2039 DrawText(DX + (DXSIZE - tl * getFontWidth(FONT_TEXT_2)) / 2,
2040 DY + 8 + ty * (getFontHeight(FONT_TEXT_2) + 2),
2041 text_line, FONT_TEXT_2);
2043 text += tl + (tc == ' ' ? 1 : 0);
2046 game_status = last_game_status; /* restore current game status */
2048 if (req_state & REQ_ASK)
2050 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
2051 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
2053 else if (req_state & REQ_CONFIRM)
2055 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
2057 else if (req_state & REQ_PLAYER)
2059 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
2060 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
2061 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
2062 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
2065 /* copy request gadgets to door backbuffer */
2066 BlitBitmap(drawto, bitmap_db_door,
2067 DX, DY, DXSIZE, DYSIZE,
2068 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2070 OpenDoor(DOOR_OPEN_1);
2076 if (!(req_state & REQUEST_WAIT_FOR))
2078 SetDrawBackgroundMask(REDRAW_FIELD);
2083 if (game_status != GAME_MODE_MAIN)
2086 button_status = MB_RELEASED;
2088 request_gadget_id = -1;
2090 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
2093 SetMouseCursor(CURSOR_DEFAULT);
2106 case EVENT_BUTTONPRESS:
2107 case EVENT_BUTTONRELEASE:
2108 case EVENT_MOTIONNOTIFY:
2110 if (event.type == EVENT_MOTIONNOTIFY)
2112 if (!PointerInWindow(window))
2113 continue; /* window and pointer are on different screens */
2118 motion_status = TRUE;
2119 mx = ((MotionEvent *) &event)->x;
2120 my = ((MotionEvent *) &event)->y;
2124 motion_status = FALSE;
2125 mx = ((ButtonEvent *) &event)->x;
2126 my = ((ButtonEvent *) &event)->y;
2127 if (event.type == EVENT_BUTTONPRESS)
2128 button_status = ((ButtonEvent *) &event)->button;
2130 button_status = MB_RELEASED;
2133 /* this sets 'request_gadget_id' */
2134 HandleGadgets(mx, my, button_status);
2136 switch(request_gadget_id)
2138 case TOOL_CTRL_ID_YES:
2141 case TOOL_CTRL_ID_NO:
2144 case TOOL_CTRL_ID_CONFIRM:
2145 result = TRUE | FALSE;
2148 case TOOL_CTRL_ID_PLAYER_1:
2151 case TOOL_CTRL_ID_PLAYER_2:
2154 case TOOL_CTRL_ID_PLAYER_3:
2157 case TOOL_CTRL_ID_PLAYER_4:
2168 case EVENT_KEYPRESS:
2169 switch(GetEventKey((KeyEvent *)&event, TRUE))
2182 if (req_state & REQ_PLAYER)
2186 case EVENT_KEYRELEASE:
2187 ClearPlayerAction();
2191 HandleOtherEvents(&event);
2195 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
2197 int joy = AnyJoystick();
2199 if (joy & JOY_BUTTON_1)
2201 else if (joy & JOY_BUTTON_2)
2207 /* don't eat all CPU time */
2211 if (game_status != GAME_MODE_MAIN)
2216 if (!(req_state & REQ_STAY_OPEN))
2218 CloseDoor(DOOR_CLOSE_1);
2220 if (!(req_state & REQ_STAY_CLOSED) && (old_door_state & DOOR_OPEN_1))
2222 BlitBitmap(bitmap_db_door, bitmap_db_door,
2223 DOOR_GFX_PAGEX2,DOOR_GFX_PAGEY1, DXSIZE,DYSIZE,
2224 DOOR_GFX_PAGEX1,DOOR_GFX_PAGEY1);
2225 OpenDoor(DOOR_OPEN_1);
2231 SetDrawBackgroundMask(REDRAW_FIELD);
2233 #if defined(PLATFORM_UNIX)
2234 /* continue network game after request */
2235 if (options.network &&
2236 game_status == GAME_MODE_PLAYING &&
2237 req_state & REQUEST_WAIT_FOR)
2238 SendToServer_ContinuePlaying();
2244 unsigned int OpenDoor(unsigned int door_state)
2246 unsigned int new_door_state;
2248 if (door_state & DOOR_COPY_BACK)
2250 BlitBitmap(bitmap_db_door, bitmap_db_door,
2251 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE + VYSIZE,
2252 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2253 door_state &= ~DOOR_COPY_BACK;
2256 new_door_state = MoveDoor(door_state);
2258 return(new_door_state);
2261 unsigned int CloseDoor(unsigned int door_state)
2263 unsigned int new_door_state;
2265 BlitBitmap(backbuffer, bitmap_db_door,
2266 DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2267 BlitBitmap(backbuffer, bitmap_db_door,
2268 VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
2270 new_door_state = MoveDoor(door_state);
2272 return(new_door_state);
2275 unsigned int GetDoorState()
2277 return MoveDoor(DOOR_GET_STATE);
2280 unsigned int SetDoorState(unsigned int door_state)
2282 return MoveDoor(door_state | DOOR_SET_STATE);
2285 unsigned int MoveDoor(unsigned int door_state)
2287 static int door1 = DOOR_OPEN_1;
2288 static int door2 = DOOR_CLOSE_2;
2289 unsigned long door_delay = 0;
2290 unsigned long door_delay_value;
2293 if (door_state == DOOR_GET_STATE)
2294 return(door1 | door2);
2296 if (door_state & DOOR_SET_STATE)
2298 if (door_state & DOOR_ACTION_1)
2299 door1 = door_state & DOOR_ACTION_1;
2300 if (door_state & DOOR_ACTION_2)
2301 door2 = door_state & DOOR_ACTION_2;
2303 return(door1 | door2);
2306 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
2307 door_state &= ~DOOR_OPEN_1;
2308 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
2309 door_state &= ~DOOR_CLOSE_1;
2310 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
2311 door_state &= ~DOOR_OPEN_2;
2312 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
2313 door_state &= ~DOOR_CLOSE_2;
2315 door_delay_value = (door_state & DOOR_ACTION_1 ? door_1.step_delay :
2318 if (setup.quick_doors)
2320 stepsize = 20; /* must be choosen to always draw last frame */
2321 door_delay_value = 0;
2323 StopSound(SND_DOOR_OPENING);
2324 StopSound(SND_DOOR_CLOSING);
2327 if (global.autoplay_leveldir)
2329 door_state |= DOOR_NO_DELAY;
2330 door_state &= ~DOOR_CLOSE_ALL;
2333 if (door_state & DOOR_ACTION)
2335 boolean door_1_done = !(door_state & DOOR_ACTION_1);
2336 boolean door_2_done = !(door_state & DOOR_ACTION_2);
2337 int start = ((door_state & DOOR_NO_DELAY) ? DXSIZE : 0);
2338 int end = (door_state & DOOR_ACTION_1 &&
2339 door_1.anim_mode == ANIM_VERTICAL ? DYSIZE : DXSIZE);
2342 if (!(door_state & DOOR_NO_DELAY))
2344 /* opening door sound has priority over simultaneously closing door */
2345 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
2346 PlaySoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
2347 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
2348 PlaySoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
2351 for(x = start; x <= end && !(door_1_done && door_2_done); x += stepsize)
2353 Bitmap *bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
2354 GC gc = bitmap->stored_clip_gc;
2356 if (door_state & DOOR_ACTION_1)
2358 int a = MIN(x * door_1.step_offset, end);
2359 int i = (door_state & DOOR_OPEN_1 ? end - a : a);
2363 BlitBitmap(bitmap_db_door, drawto,
2364 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + i / 2,
2365 DXSIZE,DYSIZE - i / 2, DX, DY);
2367 ClearRectangle(drawto, DX, DY + DYSIZE - i / 2, DXSIZE, i / 2);
2370 if (door_1.anim_mode == ANIM_HORIZONTAL && x <= DXSIZE)
2372 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
2373 int dst1_x = DX + DXSIZE - i, dst1_y = DY;
2374 int src2_x = DXSIZE - i, src2_y = DOOR_GFX_PAGEY1;
2375 int dst2_x = DX, dst2_y = DY;
2376 int width = i, height = DYSIZE;
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 (door_1.anim_mode == ANIM_VERTICAL && x <= DYSIZE)
2388 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
2389 int dst1_x = DX, dst1_y = DY + DYSIZE - i;
2390 int src2_x = 0, src2_y = DOOR_GFX_PAGEY1 + DYSIZE - i;
2391 int dst2_x = DX, dst2_y = DY;
2392 int width = DXSIZE, height = i;
2394 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2395 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2398 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2399 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2402 else if (x <= DXSIZE) /* ANIM_DEFAULT */
2404 int j = (door_1.anim_mode == ANIM_DEFAULT ? (DXSIZE - i) / 3 : 0);
2406 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2407 BlitBitmapMasked(bitmap, drawto,
2408 DXSIZE, DOOR_GFX_PAGEY1, i, 77,
2409 DX + DXSIZE - i, DY + j);
2410 BlitBitmapMasked(bitmap, drawto,
2411 DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63,
2412 DX + DXSIZE - i, DY + 140 + j);
2413 SetClipOrigin(bitmap, gc, DX - DXSIZE + i,
2414 DY - (DOOR_GFX_PAGEY1 + j));
2415 BlitBitmapMasked(bitmap, drawto,
2416 DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j,
2418 BlitBitmapMasked(bitmap, drawto,
2419 DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63,
2422 BlitBitmapMasked(bitmap, drawto,
2423 DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
2425 BlitBitmapMasked(bitmap, drawto,
2426 DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
2428 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2429 BlitBitmapMasked(bitmap, drawto,
2430 DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
2431 DX + DXSIZE - i, DY + 77 + j);
2432 BlitBitmapMasked(bitmap, drawto,
2433 DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
2434 DX + DXSIZE - i, DY + 203 + j);
2437 redraw_mask |= REDRAW_DOOR_1;
2438 door_1_done = (a == end);
2441 if (door_state & DOOR_ACTION_2)
2443 int a = MIN(x * door_2.step_offset, VXSIZE);
2444 int i = (door_state & DOOR_OPEN_2 ? VXSIZE - a : a);
2448 BlitBitmap(bitmap_db_door, drawto,
2449 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + i / 2,
2450 VXSIZE, VYSIZE - i / 2, VX, VY);
2452 ClearRectangle(drawto, VX, VY + VYSIZE - i / 2, VXSIZE, i / 2);
2455 if (door_2.anim_mode == ANIM_HORIZONTAL && x <= VXSIZE)
2457 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
2458 int dst1_x = VX + VXSIZE - i, dst1_y = VY;
2459 int src2_x = VXSIZE - i, src2_y = DOOR_GFX_PAGEY2;
2460 int dst2_x = VX, dst2_y = VY;
2461 int width = i, height = VYSIZE;
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 (door_2.anim_mode == ANIM_VERTICAL && x <= VYSIZE)
2473 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
2474 int dst1_x = VX, dst1_y = VY + VYSIZE - i;
2475 int src2_x = 0, src2_y = DOOR_GFX_PAGEY2 + VYSIZE - i;
2476 int dst2_x = VX, dst2_y = VY;
2477 int width = VXSIZE, height = i;
2479 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2480 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2483 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2484 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2487 else if (x <= VXSIZE) /* ANIM_DEFAULT */
2489 int j = (door_2.anim_mode == ANIM_DEFAULT ? (VXSIZE - i) / 3 : 0);
2491 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2492 BlitBitmapMasked(bitmap, drawto,
2493 VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2,
2494 VX + VXSIZE - i, VY + j);
2495 SetClipOrigin(bitmap, gc,
2496 VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
2497 BlitBitmapMasked(bitmap, drawto,
2498 VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j,
2501 BlitBitmapMasked(bitmap, drawto,
2502 VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2,
2503 i, VYSIZE / 2, VX, VY + VYSIZE / 2 - j);
2504 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2505 BlitBitmapMasked(bitmap, drawto,
2506 VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2,
2508 VX + VXSIZE - i, VY + VYSIZE / 2 + j);
2511 redraw_mask |= REDRAW_DOOR_2;
2512 door_2_done = (a == VXSIZE);
2517 if (game_status == GAME_MODE_MAIN)
2520 if (!(door_state & DOOR_NO_DELAY))
2521 WaitUntilDelayReached(&door_delay, door_delay_value);
2525 if (setup.quick_doors)
2527 StopSound(SND_DOOR_OPENING);
2528 StopSound(SND_DOOR_CLOSING);
2531 if (door_state & DOOR_ACTION_1)
2532 door1 = door_state & DOOR_ACTION_1;
2533 if (door_state & DOOR_ACTION_2)
2534 door2 = door_state & DOOR_ACTION_2;
2536 return (door1 | door2);
2539 void DrawSpecialEditorDoor()
2541 /* draw bigger toolbox window */
2542 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
2543 DOOR_GFX_PAGEX7, 0, EXSIZE + 8, 8,
2545 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
2546 EX - 4, VY - 4, EXSIZE + 8, EYSIZE - VYSIZE + 4,
2549 redraw_mask |= REDRAW_ALL;
2552 void UndrawSpecialEditorDoor()
2554 /* draw normal tape recorder window */
2555 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
2556 EX - 4, EY - 12, EXSIZE + 8, EYSIZE - VYSIZE + 12,
2559 redraw_mask |= REDRAW_ALL;
2563 /* ---------- new tool button stuff ---------------------------------------- */
2565 /* graphic position values for tool buttons */
2566 #define TOOL_BUTTON_YES_XPOS 2
2567 #define TOOL_BUTTON_YES_YPOS 250
2568 #define TOOL_BUTTON_YES_GFX_YPOS 0
2569 #define TOOL_BUTTON_YES_XSIZE 46
2570 #define TOOL_BUTTON_YES_YSIZE 28
2571 #define TOOL_BUTTON_NO_XPOS 52
2572 #define TOOL_BUTTON_NO_YPOS TOOL_BUTTON_YES_YPOS
2573 #define TOOL_BUTTON_NO_GFX_YPOS TOOL_BUTTON_YES_GFX_YPOS
2574 #define TOOL_BUTTON_NO_XSIZE TOOL_BUTTON_YES_XSIZE
2575 #define TOOL_BUTTON_NO_YSIZE TOOL_BUTTON_YES_YSIZE
2576 #define TOOL_BUTTON_CONFIRM_XPOS TOOL_BUTTON_YES_XPOS
2577 #define TOOL_BUTTON_CONFIRM_YPOS TOOL_BUTTON_YES_YPOS
2578 #define TOOL_BUTTON_CONFIRM_GFX_YPOS 30
2579 #define TOOL_BUTTON_CONFIRM_XSIZE 96
2580 #define TOOL_BUTTON_CONFIRM_YSIZE TOOL_BUTTON_YES_YSIZE
2581 #define TOOL_BUTTON_PLAYER_XSIZE 30
2582 #define TOOL_BUTTON_PLAYER_YSIZE 30
2583 #define TOOL_BUTTON_PLAYER_GFX_XPOS 5
2584 #define TOOL_BUTTON_PLAYER_GFX_YPOS 185
2585 #define TOOL_BUTTON_PLAYER_XPOS (5 + TOOL_BUTTON_PLAYER_XSIZE / 2)
2586 #define TOOL_BUTTON_PLAYER_YPOS (215 - TOOL_BUTTON_PLAYER_YSIZE / 2)
2587 #define TOOL_BUTTON_PLAYER1_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2588 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2589 #define TOOL_BUTTON_PLAYER2_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2590 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2591 #define TOOL_BUTTON_PLAYER3_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2592 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2593 #define TOOL_BUTTON_PLAYER4_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2594 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2595 #define TOOL_BUTTON_PLAYER1_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2596 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2597 #define TOOL_BUTTON_PLAYER2_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2598 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2599 #define TOOL_BUTTON_PLAYER3_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2600 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2601 #define TOOL_BUTTON_PLAYER4_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2602 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2611 } toolbutton_info[NUM_TOOL_BUTTONS] =
2614 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_GFX_YPOS,
2615 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_YPOS,
2616 TOOL_BUTTON_YES_XSIZE, TOOL_BUTTON_YES_YSIZE,
2621 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_GFX_YPOS,
2622 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_YPOS,
2623 TOOL_BUTTON_NO_XSIZE, TOOL_BUTTON_NO_YSIZE,
2628 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_GFX_YPOS,
2629 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_YPOS,
2630 TOOL_BUTTON_CONFIRM_XSIZE, TOOL_BUTTON_CONFIRM_YSIZE,
2631 TOOL_CTRL_ID_CONFIRM,
2635 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2636 TOOL_BUTTON_PLAYER1_XPOS, TOOL_BUTTON_PLAYER1_YPOS,
2637 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2638 TOOL_CTRL_ID_PLAYER_1,
2642 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2643 TOOL_BUTTON_PLAYER2_XPOS, TOOL_BUTTON_PLAYER2_YPOS,
2644 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2645 TOOL_CTRL_ID_PLAYER_2,
2649 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2650 TOOL_BUTTON_PLAYER3_XPOS, TOOL_BUTTON_PLAYER3_YPOS,
2651 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2652 TOOL_CTRL_ID_PLAYER_3,
2656 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2657 TOOL_BUTTON_PLAYER4_XPOS, TOOL_BUTTON_PLAYER4_YPOS,
2658 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2659 TOOL_CTRL_ID_PLAYER_4,
2664 void CreateToolButtons()
2668 for (i=0; i<NUM_TOOL_BUTTONS; i++)
2670 Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
2671 Bitmap *deco_bitmap = None;
2672 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
2673 struct GadgetInfo *gi;
2674 unsigned long event_mask;
2675 int gd_xoffset, gd_yoffset;
2676 int gd_x1, gd_x2, gd_y;
2679 event_mask = GD_EVENT_RELEASED;
2681 gd_xoffset = toolbutton_info[i].xpos;
2682 gd_yoffset = toolbutton_info[i].ypos;
2683 gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
2684 gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
2685 gd_y = DOOR_GFX_PAGEY1 + gd_yoffset;
2687 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
2689 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
2691 getMiniGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr),
2692 &deco_bitmap, &deco_x, &deco_y);
2693 deco_xpos = (toolbutton_info[i].width - MINI_TILEX) / 2;
2694 deco_ypos = (toolbutton_info[i].height - MINI_TILEY) / 2;
2697 gi = CreateGadget(GDI_CUSTOM_ID, id,
2698 GDI_INFO_TEXT, toolbutton_info[i].infotext,
2699 GDI_X, DX + toolbutton_info[i].x,
2700 GDI_Y, DY + toolbutton_info[i].y,
2701 GDI_WIDTH, toolbutton_info[i].width,
2702 GDI_HEIGHT, toolbutton_info[i].height,
2703 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
2704 GDI_STATE, GD_BUTTON_UNPRESSED,
2705 GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
2706 GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
2707 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
2708 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
2709 GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
2710 GDI_DECORATION_SHIFTING, 1, 1,
2711 GDI_EVENT_MASK, event_mask,
2712 GDI_CALLBACK_ACTION, HandleToolButtons,
2716 Error(ERR_EXIT, "cannot create gadget");
2718 tool_gadget[id] = gi;
2722 void FreeToolButtons()
2726 for (i=0; i<NUM_TOOL_BUTTONS; i++)
2727 FreeGadget(tool_gadget[i]);
2730 static void UnmapToolButtons()
2734 for (i=0; i<NUM_TOOL_BUTTONS; i++)
2735 UnmapGadget(tool_gadget[i]);
2738 static void HandleToolButtons(struct GadgetInfo *gi)
2740 request_gadget_id = gi->custom_id;
2743 int get_next_element(int element)
2747 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
2748 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
2749 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
2750 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
2751 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
2752 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
2753 case EL_AMOEBA_DROPPING: return EL_AMOEBA_WET;
2755 default: return element;
2759 int el_act_dir2img(int element, int action, int direction)
2761 element = GFX_ELEMENT(element);
2762 direction = MV_DIR_BIT(direction);
2764 return element_info[element].direction_graphic[action][direction];
2767 static int el_act_dir2crm(int element, int action, int direction)
2769 element = GFX_ELEMENT(element);
2770 direction = MV_DIR_BIT(direction);
2772 return element_info[element].direction_crumbled[action][direction];
2775 int el_act2img(int element, int action)
2777 element = GFX_ELEMENT(element);
2779 return element_info[element].graphic[action];
2782 int el_act2crm(int element, int action)
2784 element = GFX_ELEMENT(element);
2786 return element_info[element].crumbled[action];
2789 int el_dir2img(int element, int direction)
2791 element = GFX_ELEMENT(element);
2793 return el_act_dir2img(element, ACTION_DEFAULT, direction);
2796 int el2img(int element)
2798 element = GFX_ELEMENT(element);
2800 return element_info[element].graphic[ACTION_DEFAULT];
2803 int el2edimg(int element)
2805 element = GFX_ELEMENT(element);
2807 return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
2810 int el2preimg(int element)
2812 element = GFX_ELEMENT(element);
2814 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];