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_GAME_ENVELOPE_1_BACKGROUND + 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 ShowEnvelope(int envelope_nr)
1604 int element = EL_ENVELOPE_1 + envelope_nr;
1605 int graphic = IMG_GAME_ENVELOPE_1_BACKGROUND + envelope_nr;
1606 int sound_opening = element_info[element].sound[ACTION_OPENING];
1607 int sound_closing = element_info[element].sound[ACTION_CLOSING];
1608 boolean draw_masked = graphic_info[graphic].draw_masked;
1609 int anim_mode = graphic_info[graphic].anim_mode;
1610 int mask_mode = (draw_masked ? BLIT_MASKED : BLIT_ON_BACKGROUND);
1611 int font_nr = FONT_TEXT_1;
1612 int font_width = getFontWidth(font_nr);
1613 int font_height = getFontHeight(font_nr);
1614 boolean ffwd_delay = (tape.playing && tape.fast_forward);
1615 unsigned long anim_delay = 0;
1616 int anim_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
1617 int wait_delay_value = (ffwd_delay ? 500 : 1000);
1618 int start_pos_vertically = 0;
1621 game.envelope_active = TRUE;
1623 if (anim_mode != ANIM_NONE)
1624 PlaySoundStereo(sound_opening, SOUND_MIDDLE);
1626 if (anim_mode == ANIM_DEFAULT)
1628 /* open envelope window horizontally */
1629 for (i = 0; i <= level.envelope_xsize[envelope_nr]; i++)
1633 int startx = (SXSIZE - xsize * font_width) / 2;
1634 int starty = (SYSIZE - ysize * font_height) / 2;
1636 SetDrawtoField(DRAW_BUFFERED);
1638 BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
1640 SetDrawtoField(DRAW_BACKBUFFER);
1642 for (y=0; y < ysize; y++) for (x=0; x < xsize; x++)
1643 DrawEnvelopeBackground(envelope_nr, startx, starty, x, y, xsize, ysize,
1646 redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
1649 WaitUntilDelayReached(&anim_delay, anim_delay_value / 2);
1653 if (anim_mode == ANIM_NONE)
1654 start_pos_vertically = level.envelope_ysize[envelope_nr];
1656 /* open envelope window vertically */
1657 for (i = start_pos_vertically; i <= level.envelope_ysize[envelope_nr]; i++)
1659 int xsize = level.envelope_xsize[envelope_nr] + 2;
1661 int startx = (SXSIZE - xsize * font_width) / 2;
1662 int starty = (SYSIZE - ysize * font_height) / 2;
1664 SetDrawtoField(DRAW_BUFFERED);
1666 BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
1668 SetDrawtoField(DRAW_BACKBUFFER);
1670 for (y=0; y < ysize; y++) for (x=0; x < xsize; x++)
1671 DrawEnvelopeBackground(envelope_nr, startx, starty, x, y, xsize, ysize,
1674 DrawTextToTextArea(SX + startx + font_width, SY + starty + font_height,
1675 level.envelope_text[envelope_nr], FONT_TEXT_1,
1676 level.envelope_xsize[envelope_nr], i, mask_mode);
1678 redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
1681 WaitUntilDelayReached(&anim_delay, anim_delay_value);
1685 Delay(wait_delay_value);
1687 WaitForEventToContinue();
1689 if (anim_mode != ANIM_NONE)
1690 PlaySoundStereo(sound_closing, SOUND_MIDDLE);
1692 if (anim_mode != ANIM_NONE)
1694 /* close envelope window vertically */
1695 for (i = level.envelope_ysize[envelope_nr]; i >= 0; i--)
1697 int xsize = level.envelope_xsize[envelope_nr] + 2;
1699 int startx = (SXSIZE - xsize * font_width) / 2;
1700 int starty = (SYSIZE - ysize * font_height) / 2;
1702 SetDrawtoField(DRAW_BUFFERED);
1704 BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
1706 SetDrawtoField(DRAW_BACKBUFFER);
1708 for (y=0; y < ysize; y++) for (x=0; x < xsize; x++)
1709 DrawEnvelopeBackground(envelope_nr, startx, starty, x, y, xsize, ysize,
1712 DrawTextToTextArea(SX + startx + font_width, SY + starty + font_height,
1713 level.envelope_text[envelope_nr], FONT_TEXT_1,
1714 level.envelope_xsize[envelope_nr], i, mask_mode);
1716 redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
1719 WaitUntilDelayReached(&anim_delay, anim_delay_value);
1723 if (anim_mode == ANIM_DEFAULT)
1725 /* close envelope window horizontally */
1726 for (i = level.envelope_xsize[envelope_nr]; i >= 0; i--)
1730 int startx = (SXSIZE - xsize * font_width) / 2;
1731 int starty = (SYSIZE - ysize * font_height) / 2;
1733 SetDrawtoField(DRAW_BUFFERED);
1735 BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
1737 SetDrawtoField(DRAW_BACKBUFFER);
1739 for (y=0; y < ysize; y++) for (x=0; x < xsize; x++)
1740 DrawEnvelopeBackground(envelope_nr, startx, starty, x, y, xsize, ysize,
1743 redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
1746 WaitUntilDelayReached(&anim_delay, anim_delay_value / 2);
1750 game.envelope_active = FALSE;
1752 SetDrawtoField(DRAW_BUFFERED);
1754 redraw_mask |= REDRAW_FIELD;
1758 void getMicroGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
1760 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
1761 int mini_startx = src_bitmap->width * 3 / 4;
1762 int mini_starty = src_bitmap->height * 2 / 3;
1763 int src_x = mini_startx + graphic_info[graphic].src_x / 8;
1764 int src_y = mini_starty + graphic_info[graphic].src_y / 8;
1766 *bitmap = src_bitmap;
1771 void DrawMicroElement(int xpos, int ypos, int element)
1775 int graphic = el2preimg(element);
1777 getMicroGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
1778 BlitBitmap(src_bitmap, drawto, src_x, src_y, MICRO_TILEX, MICRO_TILEY,
1786 SetDrawBackgroundMask(REDRAW_NONE);
1789 for(x=BX1; x<=BX2; x++)
1790 for(y=BY1; y<=BY2; y++)
1791 DrawScreenField(x, y);
1793 redraw_mask |= REDRAW_FIELD;
1796 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
1800 for(x=0; x<size_x; x++)
1801 for(y=0; y<size_y; y++)
1802 DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
1804 redraw_mask |= REDRAW_FIELD;
1807 static void DrawMicroLevelExt(int xpos, int ypos, int from_x, int from_y)
1811 DrawBackground(xpos, ypos, MICROLEV_XSIZE, MICROLEV_YSIZE);
1813 if (lev_fieldx < STD_LEV_FIELDX)
1814 xpos += (STD_LEV_FIELDX - lev_fieldx) / 2 * MICRO_TILEX;
1815 if (lev_fieldy < STD_LEV_FIELDY)
1816 ypos += (STD_LEV_FIELDY - lev_fieldy) / 2 * MICRO_TILEY;
1818 xpos += MICRO_TILEX;
1819 ypos += MICRO_TILEY;
1821 for(x=-1; x<=STD_LEV_FIELDX; x++)
1823 for(y=-1; y<=STD_LEV_FIELDY; y++)
1825 int lx = from_x + x, ly = from_y + y;
1827 if (lx >= 0 && lx < lev_fieldx && ly >= 0 && ly < lev_fieldy)
1828 DrawMicroElement(xpos + x * MICRO_TILEX, ypos + y * MICRO_TILEY,
1829 level.field[lx][ly]);
1830 else if (lx >= -1 && lx < lev_fieldx+1 && ly >= -1 && ly < lev_fieldy+1
1831 && BorderElement != EL_EMPTY)
1832 DrawMicroElement(xpos + x * MICRO_TILEX, ypos + y * MICRO_TILEY,
1833 getBorderElement(lx, ly));
1837 redraw_mask |= REDRAW_MICROLEVEL;
1840 #define MICROLABEL_EMPTY 0
1841 #define MICROLABEL_LEVEL_NAME 1
1842 #define MICROLABEL_CREATED_BY 2
1843 #define MICROLABEL_LEVEL_AUTHOR 3
1844 #define MICROLABEL_IMPORTED_FROM 4
1845 #define MICROLABEL_LEVEL_IMPORT_INFO 5
1847 static void DrawMicroLevelLabelExt(int mode)
1849 char label_text[MAX_OUTPUT_LINESIZE + 1];
1850 int max_len_label_text;
1851 int font_nr = FONT_TEXT_2;
1853 if (mode == MICROLABEL_CREATED_BY || mode == MICROLABEL_IMPORTED_FROM)
1854 font_nr = FONT_TEXT_3;
1856 max_len_label_text = SXSIZE / getFontWidth(font_nr);
1858 DrawBackground(SX, MICROLABEL_YPOS, SXSIZE, getFontHeight(font_nr));
1860 strncpy(label_text, (mode == MICROLABEL_LEVEL_NAME ? level.name :
1861 mode == MICROLABEL_CREATED_BY ? "created by" :
1862 mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
1863 mode == MICROLABEL_IMPORTED_FROM ? "imported from" :
1864 mode == MICROLABEL_LEVEL_IMPORT_INFO ?
1865 leveldir_current->imported_from : ""),
1866 max_len_label_text);
1867 label_text[max_len_label_text] = '\0';
1869 if (strlen(label_text) > 0)
1871 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
1872 int lypos = MICROLABEL_YPOS;
1874 DrawText(lxpos, lypos, label_text, font_nr);
1877 redraw_mask |= REDRAW_MICROLEVEL;
1880 void DrawMicroLevel(int xpos, int ypos, boolean restart)
1882 static unsigned long scroll_delay = 0;
1883 static unsigned long label_delay = 0;
1884 static int from_x, from_y, scroll_direction;
1885 static int label_state, label_counter;
1886 int last_game_status = game_status; /* save current game status */
1888 /* force PREVIEW font on preview level */
1889 game_status = GAME_MODE_PSEUDO_PREVIEW;
1893 from_x = from_y = 0;
1894 scroll_direction = MV_RIGHT;
1898 DrawMicroLevelExt(xpos, ypos, from_x, from_y);
1899 DrawMicroLevelLabelExt(label_state);
1901 /* initialize delay counters */
1902 DelayReached(&scroll_delay, 0);
1903 DelayReached(&label_delay, 0);
1905 if (leveldir_current->name)
1907 int text_width = getTextWidth(leveldir_current->name, FONT_TEXT_1);
1908 int lxpos = SX + (SXSIZE - text_width) / 2;
1909 int lypos = SY + 352;
1911 DrawText(lxpos, lypos, leveldir_current->name, FONT_TEXT_1);
1914 game_status = last_game_status; /* restore current game status */
1919 /* scroll micro level, if needed */
1920 if ((lev_fieldx > STD_LEV_FIELDX || lev_fieldy > STD_LEV_FIELDY) &&
1921 DelayReached(&scroll_delay, MICROLEVEL_SCROLL_DELAY))
1923 switch (scroll_direction)
1929 scroll_direction = MV_UP;
1933 if (from_x < lev_fieldx - STD_LEV_FIELDX)
1936 scroll_direction = MV_DOWN;
1943 scroll_direction = MV_RIGHT;
1947 if (from_y < lev_fieldy - STD_LEV_FIELDY)
1950 scroll_direction = MV_LEFT;
1957 DrawMicroLevelExt(xpos, ypos, from_x, from_y);
1960 /* redraw micro level label, if needed */
1961 if (strcmp(level.name, NAMELESS_LEVEL_NAME) != 0 &&
1962 strcmp(level.author, ANONYMOUS_NAME) != 0 &&
1963 strcmp(level.author, leveldir_current->name) != 0 &&
1964 DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
1966 int max_label_counter = 23;
1968 if (leveldir_current->imported_from != NULL)
1969 max_label_counter += 14;
1971 label_counter = (label_counter + 1) % max_label_counter;
1972 label_state = (label_counter >= 0 && label_counter <= 7 ?
1973 MICROLABEL_LEVEL_NAME :
1974 label_counter >= 9 && label_counter <= 12 ?
1975 MICROLABEL_CREATED_BY :
1976 label_counter >= 14 && label_counter <= 21 ?
1977 MICROLABEL_LEVEL_AUTHOR :
1978 label_counter >= 23 && label_counter <= 26 ?
1979 MICROLABEL_IMPORTED_FROM :
1980 label_counter >= 28 && label_counter <= 35 ?
1981 MICROLABEL_LEVEL_IMPORT_INFO : MICROLABEL_EMPTY);
1982 DrawMicroLevelLabelExt(label_state);
1985 game_status = last_game_status; /* restore current game status */
1988 void WaitForEventToContinue()
1990 boolean still_wait = TRUE;
1992 /* simulate releasing mouse button over last gadget, if still pressed */
1994 HandleGadgets(-1, -1, 0);
1996 button_status = MB_RELEASED;
2008 case EVENT_BUTTONPRESS:
2009 case EVENT_KEYPRESS:
2013 case EVENT_KEYRELEASE:
2014 ClearPlayerAction();
2018 HandleOtherEvents(&event);
2022 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
2029 /* don't eat all CPU time */
2034 #define MAX_REQUEST_LINES 13
2035 #define MAX_REQUEST_LINE_LEN 7
2037 boolean Request(char *text, unsigned int req_state)
2039 int mx, my, ty, result = -1;
2040 unsigned int old_door_state;
2041 int last_game_status = game_status; /* save current game status */
2044 SetMouseCursor(CURSOR_DEFAULT);
2047 #if defined(PLATFORM_UNIX)
2048 /* pause network game while waiting for request to answer */
2049 if (options.network &&
2050 game_status == GAME_MODE_PLAYING &&
2051 req_state & REQUEST_WAIT_FOR)
2052 SendToServer_PausePlaying();
2055 old_door_state = GetDoorState();
2057 /* simulate releasing mouse button over last gadget, if still pressed */
2059 HandleGadgets(-1, -1, 0);
2063 CloseDoor(DOOR_CLOSE_1);
2065 /* save old door content */
2066 BlitBitmap(bitmap_db_door, bitmap_db_door,
2067 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
2068 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
2070 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
2072 /* clear door drawing field */
2073 DrawBackground(DX, DY, DXSIZE, DYSIZE);
2075 /* force DOOR font on preview level */
2076 game_status = GAME_MODE_PSEUDO_DOOR;
2078 /* write text for request */
2079 for(ty=0; ty < MAX_REQUEST_LINES; ty++)
2081 char text_line[MAX_REQUEST_LINE_LEN + 1];
2087 for(tl=0,tx=0; tx < MAX_REQUEST_LINE_LEN; tl++,tx++)
2090 if (!tc || tc == ' ')
2101 strncpy(text_line, text, tl);
2104 DrawText(DX + (DXSIZE - tl * getFontWidth(FONT_TEXT_2)) / 2,
2105 DY + 8 + ty * (getFontHeight(FONT_TEXT_2) + 2),
2106 text_line, FONT_TEXT_2);
2108 text += tl + (tc == ' ' ? 1 : 0);
2111 game_status = last_game_status; /* restore current game status */
2113 if (req_state & REQ_ASK)
2115 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
2116 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
2118 else if (req_state & REQ_CONFIRM)
2120 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
2122 else if (req_state & REQ_PLAYER)
2124 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
2125 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
2126 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
2127 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
2130 /* copy request gadgets to door backbuffer */
2131 BlitBitmap(drawto, bitmap_db_door,
2132 DX, DY, DXSIZE, DYSIZE,
2133 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2135 OpenDoor(DOOR_OPEN_1);
2141 if (!(req_state & REQUEST_WAIT_FOR))
2143 SetDrawBackgroundMask(REDRAW_FIELD);
2148 if (game_status != GAME_MODE_MAIN)
2151 button_status = MB_RELEASED;
2153 request_gadget_id = -1;
2155 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
2158 SetMouseCursor(CURSOR_DEFAULT);
2171 case EVENT_BUTTONPRESS:
2172 case EVENT_BUTTONRELEASE:
2173 case EVENT_MOTIONNOTIFY:
2175 if (event.type == EVENT_MOTIONNOTIFY)
2177 if (!PointerInWindow(window))
2178 continue; /* window and pointer are on different screens */
2183 motion_status = TRUE;
2184 mx = ((MotionEvent *) &event)->x;
2185 my = ((MotionEvent *) &event)->y;
2189 motion_status = FALSE;
2190 mx = ((ButtonEvent *) &event)->x;
2191 my = ((ButtonEvent *) &event)->y;
2192 if (event.type == EVENT_BUTTONPRESS)
2193 button_status = ((ButtonEvent *) &event)->button;
2195 button_status = MB_RELEASED;
2198 /* this sets 'request_gadget_id' */
2199 HandleGadgets(mx, my, button_status);
2201 switch(request_gadget_id)
2203 case TOOL_CTRL_ID_YES:
2206 case TOOL_CTRL_ID_NO:
2209 case TOOL_CTRL_ID_CONFIRM:
2210 result = TRUE | FALSE;
2213 case TOOL_CTRL_ID_PLAYER_1:
2216 case TOOL_CTRL_ID_PLAYER_2:
2219 case TOOL_CTRL_ID_PLAYER_3:
2222 case TOOL_CTRL_ID_PLAYER_4:
2233 case EVENT_KEYPRESS:
2234 switch(GetEventKey((KeyEvent *)&event, TRUE))
2247 if (req_state & REQ_PLAYER)
2251 case EVENT_KEYRELEASE:
2252 ClearPlayerAction();
2256 HandleOtherEvents(&event);
2260 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
2262 int joy = AnyJoystick();
2264 if (joy & JOY_BUTTON_1)
2266 else if (joy & JOY_BUTTON_2)
2272 /* don't eat all CPU time */
2276 if (game_status != GAME_MODE_MAIN)
2281 if (!(req_state & REQ_STAY_OPEN))
2283 CloseDoor(DOOR_CLOSE_1);
2285 if (!(req_state & REQ_STAY_CLOSED) && (old_door_state & DOOR_OPEN_1))
2287 BlitBitmap(bitmap_db_door, bitmap_db_door,
2288 DOOR_GFX_PAGEX2,DOOR_GFX_PAGEY1, DXSIZE,DYSIZE,
2289 DOOR_GFX_PAGEX1,DOOR_GFX_PAGEY1);
2290 OpenDoor(DOOR_OPEN_1);
2296 SetDrawBackgroundMask(REDRAW_FIELD);
2298 #if defined(PLATFORM_UNIX)
2299 /* continue network game after request */
2300 if (options.network &&
2301 game_status == GAME_MODE_PLAYING &&
2302 req_state & REQUEST_WAIT_FOR)
2303 SendToServer_ContinuePlaying();
2309 unsigned int OpenDoor(unsigned int door_state)
2311 unsigned int new_door_state;
2313 if (door_state & DOOR_COPY_BACK)
2315 BlitBitmap(bitmap_db_door, bitmap_db_door,
2316 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE + VYSIZE,
2317 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2318 door_state &= ~DOOR_COPY_BACK;
2321 new_door_state = MoveDoor(door_state);
2323 return(new_door_state);
2326 unsigned int CloseDoor(unsigned int door_state)
2328 unsigned int new_door_state;
2330 BlitBitmap(backbuffer, bitmap_db_door,
2331 DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2332 BlitBitmap(backbuffer, bitmap_db_door,
2333 VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
2335 new_door_state = MoveDoor(door_state);
2337 return(new_door_state);
2340 unsigned int GetDoorState()
2342 return MoveDoor(DOOR_GET_STATE);
2345 unsigned int SetDoorState(unsigned int door_state)
2347 return MoveDoor(door_state | DOOR_SET_STATE);
2350 unsigned int MoveDoor(unsigned int door_state)
2352 static int door1 = DOOR_OPEN_1;
2353 static int door2 = DOOR_CLOSE_2;
2354 unsigned long door_delay = 0;
2355 unsigned long door_delay_value = door_1.step_delay;
2358 if (door_state == DOOR_GET_STATE)
2359 return(door1 | door2);
2361 if (door_state & DOOR_SET_STATE)
2363 if (door_state & DOOR_ACTION_1)
2364 door1 = door_state & DOOR_ACTION_1;
2365 if (door_state & DOOR_ACTION_2)
2366 door2 = door_state & DOOR_ACTION_2;
2368 return(door1 | door2);
2371 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
2372 door_state &= ~DOOR_OPEN_1;
2373 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
2374 door_state &= ~DOOR_CLOSE_1;
2375 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
2376 door_state &= ~DOOR_OPEN_2;
2377 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
2378 door_state &= ~DOOR_CLOSE_2;
2380 if (setup.quick_doors)
2382 stepsize = 20; /* must be choosen to always draw last frame */
2383 door_delay_value = 0;
2385 StopSound(SND_DOOR_OPENING);
2386 StopSound(SND_DOOR_CLOSING);
2389 if (global.autoplay_leveldir)
2391 door_state |= DOOR_NO_DELAY;
2392 door_state &= ~DOOR_CLOSE_ALL;
2395 if (door_state & DOOR_ACTION)
2397 boolean door_1_done = !(door_state & DOOR_ACTION_1);
2398 boolean door_2_done = !(door_state & DOOR_ACTION_2);
2399 int start = ((door_state & DOOR_NO_DELAY) ? DXSIZE : 0);
2400 int end = (door_state & DOOR_ACTION_1 &&
2401 door_1.anim_mode == ANIM_VERTICAL ? DYSIZE : DXSIZE);
2404 if (!(door_state & DOOR_NO_DELAY))
2406 /* opening door sound has priority over simultaneously closing door */
2407 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
2408 PlaySoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
2409 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
2410 PlaySoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
2413 for(x = start; x <= end && !(door_1_done && door_2_done); x += stepsize)
2415 Bitmap *bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
2416 GC gc = bitmap->stored_clip_gc;
2418 if (door_state & DOOR_ACTION_1)
2420 int a = MIN(x * door_1.step_offset, end);
2421 int i = (door_state & DOOR_OPEN_1 ? end - a : a);
2425 BlitBitmap(bitmap_db_door, drawto,
2426 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + i / 2,
2427 DXSIZE,DYSIZE - i / 2, DX, DY);
2429 ClearRectangle(drawto, DX, DY + DYSIZE - i / 2, DXSIZE, i / 2);
2432 if (door_1.anim_mode == ANIM_HORIZONTAL && x <= DXSIZE)
2434 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
2435 int dst1_x = DX + DXSIZE - i, dst1_y = DY;
2436 int src2_x = DXSIZE - i, src2_y = DOOR_GFX_PAGEY1;
2437 int dst2_x = DX, dst2_y = DY;
2438 int width = i, height = DYSIZE;
2440 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2441 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2444 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2445 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2448 else if (door_1.anim_mode == ANIM_VERTICAL && x <= DYSIZE)
2450 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
2451 int dst1_x = DX, dst1_y = DY + DYSIZE - i;
2452 int src2_x = 0, src2_y = DOOR_GFX_PAGEY1 + DYSIZE - i;
2453 int dst2_x = DX, dst2_y = DY;
2454 int width = DXSIZE, height = i;
2456 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2457 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2460 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2461 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2464 else if (x <= DXSIZE) /* ANIM_DEFAULT */
2466 int j = (door_1.anim_mode == ANIM_DEFAULT ? (DXSIZE - i) / 3 : 0);
2468 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2469 BlitBitmapMasked(bitmap, drawto,
2470 DXSIZE, DOOR_GFX_PAGEY1, i, 77,
2471 DX + DXSIZE - i, DY + j);
2472 BlitBitmapMasked(bitmap, drawto,
2473 DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63,
2474 DX + DXSIZE - i, DY + 140 + j);
2475 SetClipOrigin(bitmap, gc, DX - DXSIZE + i,
2476 DY - (DOOR_GFX_PAGEY1 + j));
2477 BlitBitmapMasked(bitmap, drawto,
2478 DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j,
2480 BlitBitmapMasked(bitmap, drawto,
2481 DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63,
2484 BlitBitmapMasked(bitmap, drawto,
2485 DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
2487 BlitBitmapMasked(bitmap, drawto,
2488 DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
2490 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2491 BlitBitmapMasked(bitmap, drawto,
2492 DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
2493 DX + DXSIZE - i, DY + 77 + j);
2494 BlitBitmapMasked(bitmap, drawto,
2495 DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
2496 DX + DXSIZE - i, DY + 203 + j);
2499 redraw_mask |= REDRAW_DOOR_1;
2500 door_1_done = (a == end);
2503 if (door_state & DOOR_ACTION_2)
2505 int a = MIN(x * door_2.step_offset, VXSIZE);
2506 int i = (door_state & DOOR_OPEN_2 ? VXSIZE - a : a);
2510 BlitBitmap(bitmap_db_door, drawto,
2511 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + i / 2,
2512 VXSIZE, VYSIZE - i / 2, VX, VY);
2514 ClearRectangle(drawto, VX, VY + VYSIZE - i / 2, VXSIZE, i / 2);
2517 if (door_2.anim_mode == ANIM_HORIZONTAL && x <= VXSIZE)
2519 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
2520 int dst1_x = VX + VXSIZE - i, dst1_y = VY;
2521 int src2_x = VXSIZE - i, src2_y = DOOR_GFX_PAGEY2;
2522 int dst2_x = VX, dst2_y = VY;
2523 int width = i, height = VYSIZE;
2525 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2526 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2529 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2530 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2533 else if (door_2.anim_mode == ANIM_VERTICAL && x <= VYSIZE)
2535 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
2536 int dst1_x = VX, dst1_y = VY + VYSIZE - i;
2537 int src2_x = 0, src2_y = DOOR_GFX_PAGEY2 + VYSIZE - i;
2538 int dst2_x = VX, dst2_y = VY;
2539 int width = VXSIZE, height = i;
2541 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2542 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2545 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2546 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2549 else if (x <= VXSIZE) /* ANIM_DEFAULT */
2551 int j = (door_2.anim_mode == ANIM_DEFAULT ? (VXSIZE - i) / 3 : 0);
2553 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2554 BlitBitmapMasked(bitmap, drawto,
2555 VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2,
2556 VX + VXSIZE - i, VY + j);
2557 SetClipOrigin(bitmap, gc,
2558 VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
2559 BlitBitmapMasked(bitmap, drawto,
2560 VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j,
2563 BlitBitmapMasked(bitmap, drawto,
2564 VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2,
2565 i, VYSIZE / 2, VX, VY + VYSIZE / 2 - j);
2566 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2567 BlitBitmapMasked(bitmap, drawto,
2568 VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2,
2570 VX + VXSIZE - i, VY + VYSIZE / 2 + j);
2573 redraw_mask |= REDRAW_DOOR_2;
2574 door_2_done = (a == VXSIZE);
2579 if (game_status == GAME_MODE_MAIN)
2582 if (!(door_state & DOOR_NO_DELAY))
2583 WaitUntilDelayReached(&door_delay, door_delay_value);
2587 if (setup.quick_doors)
2589 StopSound(SND_DOOR_OPENING);
2590 StopSound(SND_DOOR_CLOSING);
2593 if (door_state & DOOR_ACTION_1)
2594 door1 = door_state & DOOR_ACTION_1;
2595 if (door_state & DOOR_ACTION_2)
2596 door2 = door_state & DOOR_ACTION_2;
2598 return (door1 | door2);
2601 void DrawSpecialEditorDoor()
2603 /* draw bigger toolbox window */
2604 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
2605 DOOR_GFX_PAGEX7, 0, EXSIZE + 8, 8,
2607 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
2608 EX - 4, VY - 4, EXSIZE + 8, EYSIZE - VYSIZE + 4,
2611 redraw_mask |= REDRAW_ALL;
2614 void UndrawSpecialEditorDoor()
2616 /* draw normal tape recorder window */
2617 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
2618 EX - 4, EY - 12, EXSIZE + 8, EYSIZE - VYSIZE + 12,
2621 redraw_mask |= REDRAW_ALL;
2625 /* ---------- new tool button stuff ---------------------------------------- */
2627 /* graphic position values for tool buttons */
2628 #define TOOL_BUTTON_YES_XPOS 2
2629 #define TOOL_BUTTON_YES_YPOS 250
2630 #define TOOL_BUTTON_YES_GFX_YPOS 0
2631 #define TOOL_BUTTON_YES_XSIZE 46
2632 #define TOOL_BUTTON_YES_YSIZE 28
2633 #define TOOL_BUTTON_NO_XPOS 52
2634 #define TOOL_BUTTON_NO_YPOS TOOL_BUTTON_YES_YPOS
2635 #define TOOL_BUTTON_NO_GFX_YPOS TOOL_BUTTON_YES_GFX_YPOS
2636 #define TOOL_BUTTON_NO_XSIZE TOOL_BUTTON_YES_XSIZE
2637 #define TOOL_BUTTON_NO_YSIZE TOOL_BUTTON_YES_YSIZE
2638 #define TOOL_BUTTON_CONFIRM_XPOS TOOL_BUTTON_YES_XPOS
2639 #define TOOL_BUTTON_CONFIRM_YPOS TOOL_BUTTON_YES_YPOS
2640 #define TOOL_BUTTON_CONFIRM_GFX_YPOS 30
2641 #define TOOL_BUTTON_CONFIRM_XSIZE 96
2642 #define TOOL_BUTTON_CONFIRM_YSIZE TOOL_BUTTON_YES_YSIZE
2643 #define TOOL_BUTTON_PLAYER_XSIZE 30
2644 #define TOOL_BUTTON_PLAYER_YSIZE 30
2645 #define TOOL_BUTTON_PLAYER_GFX_XPOS 5
2646 #define TOOL_BUTTON_PLAYER_GFX_YPOS 185
2647 #define TOOL_BUTTON_PLAYER_XPOS (5 + TOOL_BUTTON_PLAYER_XSIZE / 2)
2648 #define TOOL_BUTTON_PLAYER_YPOS (215 - TOOL_BUTTON_PLAYER_YSIZE / 2)
2649 #define TOOL_BUTTON_PLAYER1_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2650 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2651 #define TOOL_BUTTON_PLAYER2_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2652 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2653 #define TOOL_BUTTON_PLAYER3_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2654 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2655 #define TOOL_BUTTON_PLAYER4_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2656 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2657 #define TOOL_BUTTON_PLAYER1_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2658 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2659 #define TOOL_BUTTON_PLAYER2_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2660 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2661 #define TOOL_BUTTON_PLAYER3_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2662 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2663 #define TOOL_BUTTON_PLAYER4_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2664 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2673 } toolbutton_info[NUM_TOOL_BUTTONS] =
2676 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_GFX_YPOS,
2677 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_YPOS,
2678 TOOL_BUTTON_YES_XSIZE, TOOL_BUTTON_YES_YSIZE,
2683 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_GFX_YPOS,
2684 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_YPOS,
2685 TOOL_BUTTON_NO_XSIZE, TOOL_BUTTON_NO_YSIZE,
2690 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_GFX_YPOS,
2691 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_YPOS,
2692 TOOL_BUTTON_CONFIRM_XSIZE, TOOL_BUTTON_CONFIRM_YSIZE,
2693 TOOL_CTRL_ID_CONFIRM,
2697 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2698 TOOL_BUTTON_PLAYER1_XPOS, TOOL_BUTTON_PLAYER1_YPOS,
2699 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2700 TOOL_CTRL_ID_PLAYER_1,
2704 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2705 TOOL_BUTTON_PLAYER2_XPOS, TOOL_BUTTON_PLAYER2_YPOS,
2706 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2707 TOOL_CTRL_ID_PLAYER_2,
2711 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2712 TOOL_BUTTON_PLAYER3_XPOS, TOOL_BUTTON_PLAYER3_YPOS,
2713 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2714 TOOL_CTRL_ID_PLAYER_3,
2718 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2719 TOOL_BUTTON_PLAYER4_XPOS, TOOL_BUTTON_PLAYER4_YPOS,
2720 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2721 TOOL_CTRL_ID_PLAYER_4,
2726 void CreateToolButtons()
2730 for (i=0; i<NUM_TOOL_BUTTONS; i++)
2732 Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
2733 Bitmap *deco_bitmap = None;
2734 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
2735 struct GadgetInfo *gi;
2736 unsigned long event_mask;
2737 int gd_xoffset, gd_yoffset;
2738 int gd_x1, gd_x2, gd_y;
2741 event_mask = GD_EVENT_RELEASED;
2743 gd_xoffset = toolbutton_info[i].xpos;
2744 gd_yoffset = toolbutton_info[i].ypos;
2745 gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
2746 gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
2747 gd_y = DOOR_GFX_PAGEY1 + gd_yoffset;
2749 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
2751 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
2753 getMiniGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr),
2754 &deco_bitmap, &deco_x, &deco_y);
2755 deco_xpos = (toolbutton_info[i].width - MINI_TILEX) / 2;
2756 deco_ypos = (toolbutton_info[i].height - MINI_TILEY) / 2;
2759 gi = CreateGadget(GDI_CUSTOM_ID, id,
2760 GDI_INFO_TEXT, toolbutton_info[i].infotext,
2761 GDI_X, DX + toolbutton_info[i].x,
2762 GDI_Y, DY + toolbutton_info[i].y,
2763 GDI_WIDTH, toolbutton_info[i].width,
2764 GDI_HEIGHT, toolbutton_info[i].height,
2765 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
2766 GDI_STATE, GD_BUTTON_UNPRESSED,
2767 GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
2768 GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
2769 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
2770 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
2771 GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
2772 GDI_DECORATION_SHIFTING, 1, 1,
2773 GDI_EVENT_MASK, event_mask,
2774 GDI_CALLBACK_ACTION, HandleToolButtons,
2778 Error(ERR_EXIT, "cannot create gadget");
2780 tool_gadget[id] = gi;
2784 void FreeToolButtons()
2788 for (i=0; i<NUM_TOOL_BUTTONS; i++)
2789 FreeGadget(tool_gadget[i]);
2792 static void UnmapToolButtons()
2796 for (i=0; i<NUM_TOOL_BUTTONS; i++)
2797 UnmapGadget(tool_gadget[i]);
2800 static void HandleToolButtons(struct GadgetInfo *gi)
2802 request_gadget_id = gi->custom_id;
2805 int get_next_element(int element)
2809 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
2810 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
2811 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
2812 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
2813 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
2814 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
2815 case EL_AMOEBA_DROPPING: return EL_AMOEBA_WET;
2817 default: return element;
2821 int el_act_dir2img(int element, int action, int direction)
2823 element = GFX_ELEMENT(element);
2824 direction = MV_DIR_BIT(direction);
2826 return element_info[element].direction_graphic[action][direction];
2829 static int el_act_dir2crm(int element, int action, int direction)
2831 element = GFX_ELEMENT(element);
2832 direction = MV_DIR_BIT(direction);
2834 return element_info[element].direction_crumbled[action][direction];
2837 int el_act2img(int element, int action)
2839 element = GFX_ELEMENT(element);
2841 return element_info[element].graphic[action];
2844 int el_act2crm(int element, int action)
2846 element = GFX_ELEMENT(element);
2848 return element_info[element].crumbled[action];
2851 int el_dir2img(int element, int direction)
2853 element = GFX_ELEMENT(element);
2855 return el_act_dir2img(element, ACTION_DEFAULT, direction);
2858 int el2img(int element)
2860 element = GFX_ELEMENT(element);
2862 return element_info[element].graphic[ACTION_DEFAULT];
2865 int el2edimg(int element)
2867 element = GFX_ELEMENT(element);
2869 return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
2872 int el2preimg(int element)
2874 element = GFX_ELEMENT(element);
2876 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];