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)
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 (CAN_BE_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 (CAN_BE_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 (CAN_BE_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);
692 if (player->is_collecting && GfxElement[jx][jy] == EL_ENVELOPE)
698 GfxElement[jx][jy] = EL_UNDEFINED;
700 DrawLevelField(jx, jy);
704 /* ----------------------------------------------------------------------- */
705 /* draw player himself */
706 /* ----------------------------------------------------------------------- */
708 if (player->use_murphy_graphic)
710 static int last_horizontal_dir = MV_LEFT;
713 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
714 last_horizontal_dir = move_dir;
716 direction = (player->snapped ? move_dir : last_horizontal_dir);
718 graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, direction);
721 graphic = el_act_dir2img(player->element_nr, player->GfxAction, move_dir);
723 frame = getGraphicAnimationFrame(graphic, player->Frame);
727 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
728 sxx = player->GfxPos;
730 syy = player->GfxPos;
733 if (!setup.soft_scrolling && ScreenMovPos)
736 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
738 if (SHIELD_ON(player))
740 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
741 IMG_SHIELD_NORMAL_ACTIVE);
742 int frame = getGraphicAnimationFrame(graphic, -1);
744 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
747 /* ----------------------------------------------------------------------- */
748 /* draw things the player is pushing, if needed */
749 /* ----------------------------------------------------------------------- */
752 printf("::: %d, %d [%d, %d] [%d]\n",
753 player->Pushing, player_is_moving, player->GfxAction,
754 player->is_moving, player_is_moving);
758 if (player->Pushing && player->is_moving)
760 if (player->Pushing && player_is_moving)
763 int px = SCREENX(next_jx), py = SCREENY(next_jy);
765 if (Back[next_jx][next_jy])
766 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
769 if ((sxx || syy) && element == EL_SOKOBAN_OBJECT)
770 DrawGraphicShiftedThruMask(px, py, sxx, syy, IMG_SOKOBAN_OBJECT, 0,
774 (element == EL_SOKOBAN_FIELD_EMPTY ||
775 Feld[next_jx][next_jy] == EL_SOKOBAN_FIELD_FULL))
776 DrawGraphicShiftedThruMask(px, py, sxx, syy, IMG_SOKOBAN_OBJECT, 0,
782 int element = MovingOrBlocked2Element(next_jx, next_jy);
785 int element = Feld[jx][jy];
787 int element = Feld[next_jx][next_jy];
792 int graphic = el2img(element);
796 if ((sxx || syy) && IS_PUSHABLE(element))
799 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
800 frame = getGraphicAnimationFrame(graphic, player->Frame);
804 printf("::: pushing %d: %d ...\n", sxx, frame);
807 DrawGraphicShifted(px, py, sxx, syy, graphic, frame,
808 NO_CUTTING, NO_MASKING);
813 /* ----------------------------------------------------------------------- */
814 /* draw things in front of player (active dynamite or dynabombs) */
815 /* ----------------------------------------------------------------------- */
817 if (IS_ACTIVE_BOMB(element))
819 graphic = el2img(element);
820 frame = getGraphicAnimationFrame(graphic, GfxFrame[jx][jy]);
822 if (game.emulation == EMU_SUPAPLEX)
823 DrawGraphic(sx, sy, IMG_SP_DISK_RED, frame);
825 DrawGraphicThruMask(sx, sy, graphic, frame);
828 if (player_is_moving && last_element == EL_EXPLOSION)
831 int graphic = el_act2img(GfxElement[last_jx][last_jy], ACTION_EXPLODING);
833 int stored = Store[last_jx][last_jy];
834 int graphic = (game.emulation != EMU_SUPAPLEX ? IMG_EXPLOSION :
835 stored == EL_SP_INFOTRON ? IMG_SP_EXPLOSION_INFOTRON :
838 int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
839 int phase = ExplodePhase[last_jx][last_jy] - 1;
840 int frame = getGraphicAnimationFrame(graphic, phase - delay);
843 DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy), graphic, frame);
846 /* ----------------------------------------------------------------------- */
847 /* draw elements the player is just walking/passing through/under */
848 /* ----------------------------------------------------------------------- */
850 /* handle the field the player is leaving ... */
851 if (player_is_moving && IS_ACCESSIBLE_INSIDE(last_element))
852 DrawLevelField(last_jx, last_jy);
853 else if (player_is_moving && IS_ACCESSIBLE_UNDER(last_element))
854 DrawLevelFieldThruMask(last_jx, last_jy);
856 /* ... and the field the player is entering */
857 if (IS_ACCESSIBLE_INSIDE(element))
858 DrawLevelField(jx, jy);
859 else if (IS_ACCESSIBLE_UNDER(element))
860 DrawLevelFieldThruMask(jx, jy);
862 if (setup.direct_draw)
864 int dest_x = SX + SCREENX(MIN(jx, last_jx)) * TILEX;
865 int dest_y = SY + SCREENY(MIN(jy, last_jy)) * TILEY;
866 int x_size = TILEX * (1 + ABS(jx - last_jx));
867 int y_size = TILEY * (1 + ABS(jy - last_jy));
869 BlitBitmap(drawto_field, window,
870 dest_x, dest_y, x_size, y_size, dest_x, dest_y);
871 SetDrawtoField(DRAW_DIRECT);
874 MarkTileDirty(sx,sy);
877 void getGraphicSource(int graphic, int frame, Bitmap **bitmap, int *x, int *y)
879 struct GraphicInfo *g = &graphic_info[graphic];
883 if (g->offset_y == 0) /* frames are ordered horizontally */
885 int max_width = g->anim_frames_per_line * g->width;
887 *x = (g->src_x + frame * g->offset_x) % max_width;
888 *y = g->src_y + (g->src_x + frame * g->offset_x) / max_width * g->height;
890 else if (g->offset_x == 0) /* frames are ordered vertically */
892 int max_height = g->anim_frames_per_line * g->height;
894 *x = g->src_x + (g->src_y + frame * g->offset_y) / max_height * g->width;
895 *y = (g->src_y + frame * g->offset_y) % max_height;
897 else /* frames are ordered diagonally */
899 *x = g->src_x + frame * g->offset_x;
900 *y = g->src_y + frame * g->offset_y;
904 void DrawGraphic(int x, int y, int graphic, int frame)
907 if (!IN_SCR_FIELD(x, y))
909 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
910 printf("DrawGraphic(): This should never happen!\n");
915 DrawGraphicExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic, frame);
919 void DrawGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
925 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
926 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
929 void DrawGraphicThruMask(int x, int y, int graphic, int frame)
932 if (!IN_SCR_FIELD(x, y))
934 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
935 printf("DrawGraphicThruMask(): This should never happen!\n");
940 DrawGraphicThruMaskExt(drawto_field, FX + x * TILEX, FY + y *TILEY, graphic,
945 void DrawGraphicThruMaskExt(DrawBuffer *d, int dest_x, int dest_y, int graphic,
953 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
954 drawing_gc = src_bitmap->stored_clip_gc;
956 GC drawing_gc = src_bitmap->stored_clip_gc;
957 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
958 int src_x = graphic_info[graphic].src_x;
959 int src_y = graphic_info[graphic].src_y;
960 int offset_x = graphic_info[graphic].offset_x;
961 int offset_y = graphic_info[graphic].offset_y;
963 src_x += frame * offset_x;
964 src_y += frame * offset_y;
968 SetClipOrigin(src_bitmap, drawing_gc, dest_x - src_x, dest_y - src_y);
969 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX, TILEY, dest_x, dest_y);
972 void DrawMiniGraphic(int x, int y, int graphic)
974 DrawMiniGraphicExt(drawto, SX + x * MINI_TILEX,SY + y * MINI_TILEY, graphic);
975 MarkTileDirty(x / 2, y / 2);
978 void getMiniGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
980 struct GraphicInfo *g = &graphic_info[graphic];
982 int mini_starty = g->bitmap->height * 2 / 3;
985 *x = mini_startx + g->src_x / 2;
986 *y = mini_starty + g->src_y / 2;
989 void DrawMiniGraphicExt(DrawBuffer *d, int x, int y, int graphic)
994 getMiniGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
995 BlitBitmap(src_bitmap, d, src_x, src_y, MINI_TILEX, MINI_TILEY, x, y);
998 void DrawGraphicShifted(int x,int y, int dx,int dy, int graphic, int frame,
999 int cut_mode, int mask_mode)
1004 int width = TILEX, height = TILEY;
1010 DrawGraphic(x, y, graphic, frame);
1014 if (dx || dy) /* shifted graphic */
1016 if (x < BX1) /* object enters playfield from the left */
1023 else if (x > BX2) /* object enters playfield from the right */
1029 else if (x==BX1 && dx < 0) /* object leaves playfield to the left */
1035 else if (x==BX2 && dx > 0) /* object leaves playfield to the right */
1037 else if (dx) /* general horizontal movement */
1038 MarkTileDirty(x + SIGN(dx), y);
1040 if (y < BY1) /* object enters playfield from the top */
1042 if (cut_mode==CUT_BELOW) /* object completely above top border */
1050 else if (y > BY2) /* object enters playfield from the bottom */
1056 else if (y==BY1 && dy < 0) /* object leaves playfield to the top */
1062 else if (dy > 0 && cut_mode == CUT_ABOVE)
1064 if (y == BY2) /* object completely above bottom border */
1070 MarkTileDirty(x, y + 1);
1071 } /* object leaves playfield to the bottom */
1072 else if (dy > 0 && (y == BY2 || cut_mode == CUT_BELOW))
1074 else if (dy) /* general vertical movement */
1075 MarkTileDirty(x, y + SIGN(dy));
1079 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1081 src_bitmap = graphic_info[graphic].bitmap;
1082 src_x = graphic_info[graphic].src_x;
1083 src_y = graphic_info[graphic].src_y;
1084 offset_x = graphic_info[graphic].offset_x;
1085 offset_y = graphic_info[graphic].offset_y;
1087 src_x += frame * offset_x;
1088 src_y += frame * offset_y;
1091 drawing_gc = src_bitmap->stored_clip_gc;
1096 dest_x = FX + x * TILEX + dx;
1097 dest_y = FY + y * TILEY + dy;
1100 if (!IN_SCR_FIELD(x,y))
1102 printf("DrawGraphicShifted(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
1103 printf("DrawGraphicShifted(): This should never happen!\n");
1108 if (mask_mode == USE_MASKING)
1110 SetClipOrigin(src_bitmap, drawing_gc, dest_x - src_x, dest_y - src_y);
1111 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1115 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1121 void DrawGraphicShiftedThruMask(int x, int y, int dx, int dy, int graphic,
1122 int frame, int cut_mode)
1124 DrawGraphicShifted(x,y, dx,dy, graphic, frame, cut_mode, USE_MASKING);
1127 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
1128 int cut_mode, int mask_mode)
1130 int lx = LEVELX(x), ly = LEVELY(y);
1134 if (IN_LEV_FIELD(lx, ly))
1136 SetRandomAnimationValue(lx, ly);
1138 graphic = el_act_dir2img(element, GfxAction[lx][ly], MovDir[lx][ly]);
1139 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1141 else /* border element */
1143 graphic = el2img(element);
1144 frame = getGraphicAnimationFrame(graphic, -1);
1147 if (element == EL_EXPANDABLE_WALL)
1149 boolean left_stopped = FALSE, right_stopped = FALSE;
1151 if (!IN_LEV_FIELD(lx - 1, ly) || IS_WALL(Feld[lx - 1][ly]))
1152 left_stopped = TRUE;
1153 if (!IN_LEV_FIELD(lx + 1, ly) || IS_WALL(Feld[lx + 1][ly]))
1154 right_stopped = TRUE;
1156 if (left_stopped && right_stopped)
1158 else if (left_stopped)
1160 graphic = IMG_EXPANDABLE_WALL_GROWING_RIGHT;
1161 frame = graphic_info[graphic].anim_frames - 1;
1163 else if (right_stopped)
1165 graphic = IMG_EXPANDABLE_WALL_GROWING_LEFT;
1166 frame = graphic_info[graphic].anim_frames - 1;
1171 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, mask_mode);
1172 else if (mask_mode == USE_MASKING)
1173 DrawGraphicThruMask(x, y, graphic, frame);
1175 DrawGraphic(x, y, graphic, frame);
1178 void DrawLevelElementExt(int x, int y, int dx, int dy, int element,
1179 int cut_mode, int mask_mode)
1181 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1182 DrawScreenElementExt(SCREENX(x), SCREENY(y), dx, dy, element,
1183 cut_mode, mask_mode);
1186 void DrawScreenElementShifted(int x, int y, int dx, int dy, int element,
1189 DrawScreenElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1192 void DrawLevelElementShifted(int x, int y, int dx, int dy, int element,
1195 DrawLevelElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1198 void DrawLevelElementThruMask(int x, int y, int element)
1200 DrawLevelElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1203 void DrawLevelFieldThruMask(int x, int y)
1205 DrawLevelElementExt(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
1208 static void DrawLevelFieldCrumbledSandExt(int x, int y, int graphic, int frame)
1212 int sx = SCREENX(x), sy = SCREENY(y);
1214 int width, height, cx, cy, i;
1216 int crumbled_border_size = graphic_info[graphic].border_size;
1218 int snip = TILEX / 8; /* number of border pixels from "crumbled graphic" */
1220 static int xy[4][2] =
1229 if (x == 0 && y == 7)
1230 printf("::: %d, %d [%d]\n", GfxElement[x][y], Feld[x][y],
1231 crumbled_border_size);
1234 if (!IN_LEV_FIELD(x, y))
1237 element = (GfxElement[x][y] != EL_UNDEFINED && Feld[x][y] != EL_EXPLOSION ?
1238 GfxElement[x][y] : Feld[x][y]);
1240 /* crumble field itself */
1241 if (CAN_BE_CRUMBLED(element) && !IS_MOVING(x, y))
1243 if (!IN_SCR_FIELD(sx, sy))
1246 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1250 int xx = x + xy[i][0];
1251 int yy = y + xy[i][1];
1253 element = (IN_LEV_FIELD(xx, yy) ? Feld[xx][yy] : BorderElement);
1255 /* check if neighbour field is of same type */
1256 if (CAN_BE_CRUMBLED(element) && !IS_MOVING(xx, yy))
1260 if (Feld[x][y] == EL_CUSTOM_START + 123)
1261 printf("::: crumble [%d] THE CHAOS ENGINE (%d, %d): %d, %d\n",
1262 i, Feld[x][y], element,
1263 CAN_BE_CRUMBLED(element), IS_MOVING(x, y));
1266 if (i == 1 || i == 2)
1268 width = crumbled_border_size;
1270 cx = (i == 2 ? TILEX - crumbled_border_size : 0);
1276 height = crumbled_border_size;
1278 cy = (i == 3 ? TILEY - crumbled_border_size : 0);
1281 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1282 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
1285 MarkTileDirty(sx, sy);
1287 else /* crumble neighbour fields */
1290 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1295 int xx = x + xy[i][0];
1296 int yy = y + xy[i][1];
1297 int sxx = sx + xy[i][0];
1298 int syy = sy + xy[i][1];
1300 if (!IN_LEV_FIELD(xx, yy) ||
1301 !IN_SCR_FIELD(sxx, syy) ||
1302 !CAN_BE_CRUMBLED(Feld[xx][yy]) ||
1307 graphic = el_act2crm(Feld[xx][yy], ACTION_DEFAULT);
1308 crumbled_border_size = graphic_info[graphic].border_size;
1310 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1313 if (i == 1 || i == 2)
1315 width = crumbled_border_size;
1317 cx = (i == 1 ? TILEX - crumbled_border_size : 0);
1323 height = crumbled_border_size;
1325 cy = (i == 0 ? TILEY - crumbled_border_size : 0);
1328 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1329 width, height, FX + sxx * TILEX + cx, FY + syy * TILEY + cy);
1331 MarkTileDirty(sxx, syy);
1336 void DrawLevelFieldCrumbledSand(int x, int y)
1341 if (!IN_LEV_FIELD(x, y))
1344 graphic = el_act2crm(Feld[x][y], ACTION_DEFAULT);
1346 DrawLevelFieldCrumbledSandExt(x, y, graphic, 0);
1348 DrawLevelFieldCrumbledSandExt(x, y, IMG_SAND_CRUMBLED, 0);
1352 void DrawLevelFieldCrumbledSandDigging(int x, int y, int direction,
1356 int graphic1 = el_act_dir2img(GfxElement[x][y], ACTION_DIGGING, direction);
1357 int graphic2 = el_act_dir2crm(GfxElement[x][y], ACTION_DIGGING, direction);
1359 int graphic1 = el_act_dir2img(EL_SAND, ACTION_DIGGING, direction);
1360 int graphic2 = el_act_dir2img(EL_SAND_CRUMBLED, ACTION_DIGGING, direction);
1362 int frame1 = getGraphicAnimationFrame(graphic1, step_frame);
1363 int frame2 = getGraphicAnimationFrame(graphic2, step_frame);
1364 int sx = SCREENX(x), sy = SCREENY(y);
1366 DrawGraphic(sx, sy, graphic1, frame1);
1367 DrawLevelFieldCrumbledSandExt(x, y, graphic2, frame2);
1370 void DrawLevelFieldCrumbledSandNeighbours(int x, int y)
1372 int sx = SCREENX(x), sy = SCREENY(y);
1373 static int xy[4][2] =
1384 int xx = x + xy[i][0];
1385 int yy = y + xy[i][1];
1386 int sxx = sx + xy[i][0];
1387 int syy = sy + xy[i][1];
1389 if (!IN_LEV_FIELD(xx, yy) ||
1390 !IN_SCR_FIELD(sxx, syy) ||
1391 !CAN_BE_CRUMBLED(Feld[xx][yy]) ||
1395 DrawLevelField(xx, yy);
1399 static int getBorderElement(int x, int y)
1403 { EL_STEELWALL_TOPLEFT, EL_INVISIBLE_STEELWALL_TOPLEFT },
1404 { EL_STEELWALL_TOPRIGHT, EL_INVISIBLE_STEELWALL_TOPRIGHT },
1405 { EL_STEELWALL_BOTTOMLEFT, EL_INVISIBLE_STEELWALL_BOTTOMLEFT },
1406 { EL_STEELWALL_BOTTOMRIGHT, EL_INVISIBLE_STEELWALL_BOTTOMRIGHT },
1407 { EL_STEELWALL_VERTICAL, EL_INVISIBLE_STEELWALL_VERTICAL },
1408 { EL_STEELWALL_HORIZONTAL, EL_INVISIBLE_STEELWALL_HORIZONTAL },
1409 { EL_STEELWALL, EL_INVISIBLE_STEELWALL }
1411 int steel_type = (BorderElement == EL_STEELWALL ? 0 : 1);
1412 int steel_position = (x == -1 && y == -1 ? 0 :
1413 x == lev_fieldx && y == -1 ? 1 :
1414 x == -1 && y == lev_fieldy ? 2 :
1415 x == lev_fieldx && y == lev_fieldy ? 3 :
1416 x == -1 || x == lev_fieldx ? 4 :
1417 y == -1 || y == lev_fieldy ? 5 : 6);
1419 return border[steel_position][steel_type];
1422 void DrawScreenElement(int x, int y, int element)
1424 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
1425 DrawLevelFieldCrumbledSand(LEVELX(x), LEVELY(y));
1428 void DrawLevelElement(int x, int y, int element)
1430 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1431 DrawScreenElement(SCREENX(x), SCREENY(y), element);
1434 void DrawScreenField(int x, int y)
1436 int lx = LEVELX(x), ly = LEVELY(y);
1437 int element, content;
1439 if (!IN_LEV_FIELD(lx, ly))
1441 if (lx < -1 || lx > lev_fieldx || ly < -1 || ly > lev_fieldy)
1444 element = getBorderElement(lx, ly);
1446 DrawScreenElement(x, y, element);
1450 element = Feld[lx][ly];
1451 content = Store[lx][ly];
1453 if (IS_MOVING(lx, ly))
1455 int horiz_move = (MovDir[lx][ly] == MV_LEFT || MovDir[lx][ly] == MV_RIGHT);
1456 boolean cut_mode = NO_CUTTING;
1458 if (element == EL_QUICKSAND_EMPTYING ||
1459 element == EL_MAGIC_WALL_EMPTYING ||
1460 element == EL_BD_MAGIC_WALL_EMPTYING ||
1461 element == EL_AMOEBA_DROPPING)
1462 cut_mode = CUT_ABOVE;
1463 else if (element == EL_QUICKSAND_FILLING ||
1464 element == EL_MAGIC_WALL_FILLING ||
1465 element == EL_BD_MAGIC_WALL_FILLING)
1466 cut_mode = CUT_BELOW;
1468 if (cut_mode == CUT_ABOVE)
1469 DrawScreenElementShifted(x, y, 0, 0, element, NO_CUTTING);
1471 DrawScreenElement(x, y, EL_EMPTY);
1474 DrawScreenElementShifted(x, y, MovPos[lx][ly], 0, element, NO_CUTTING);
1475 else if (cut_mode == NO_CUTTING)
1476 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], element, cut_mode);
1478 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], content, cut_mode);
1480 if (content == EL_ACID)
1481 DrawLevelElementThruMask(lx, ly + 1, EL_ACID);
1483 else if (IS_BLOCKED(lx, ly))
1488 boolean cut_mode = NO_CUTTING;
1489 int element_old, content_old;
1491 Blocked2Moving(lx, ly, &oldx, &oldy);
1494 horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
1495 MovDir[oldx][oldy] == MV_RIGHT);
1497 element_old = Feld[oldx][oldy];
1498 content_old = Store[oldx][oldy];
1500 if (element_old == EL_QUICKSAND_EMPTYING ||
1501 element_old == EL_MAGIC_WALL_EMPTYING ||
1502 element_old == EL_BD_MAGIC_WALL_EMPTYING ||
1503 element_old == EL_AMOEBA_DROPPING)
1504 cut_mode = CUT_ABOVE;
1506 DrawScreenElement(x, y, EL_EMPTY);
1509 DrawScreenElementShifted(sx, sy, MovPos[oldx][oldy], 0, element_old,
1511 else if (cut_mode == NO_CUTTING)
1512 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], element_old,
1515 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], content_old,
1518 else if (IS_DRAWABLE(element))
1519 DrawScreenElement(x, y, element);
1521 DrawScreenElement(x, y, EL_EMPTY);
1524 void DrawLevelField(int x, int y)
1526 if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1527 DrawScreenField(SCREENX(x), SCREENY(y));
1528 else if (IS_MOVING(x, y))
1532 Moving2Blocked(x, y, &newx, &newy);
1533 if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
1534 DrawScreenField(SCREENX(newx), SCREENY(newy));
1536 else if (IS_BLOCKED(x, y))
1540 Blocked2Moving(x, y, &oldx, &oldy);
1541 if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
1542 DrawScreenField(SCREENX(oldx), SCREENY(oldy));
1546 void DrawMiniElement(int x, int y, int element)
1550 graphic = el2edimg(element);
1551 DrawMiniGraphic(x, y, graphic);
1554 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
1556 int x = sx + scroll_x, y = sy + scroll_y;
1558 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
1559 DrawMiniElement(sx, sy, EL_EMPTY);
1560 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
1561 DrawMiniElement(sx, sy, Feld[x][y]);
1563 DrawMiniGraphic(sx, sy, el2edimg(getBorderElement(x, y)));
1567 void DrawEnvelopeBackground(int startx, int starty, int x, int y,
1568 int xsize, int ysize, int font_nr)
1570 int font_width = getFontWidth(font_nr);
1571 int font_height = getFontHeight(font_nr);
1572 int graphic = IMG_GAME_ENVELOPE_BACKGROUND;
1575 int dst_x = SX + startx + x * font_width;
1576 int dst_y = SY + starty + y * font_height;
1577 int width = graphic_info[graphic].width;
1578 int height = graphic_info[graphic].height;
1579 int inner_width = MAX(width - 2 * font_width, font_width);
1580 int inner_height = MAX(height - 2 * font_height, font_height);
1581 int inner_sx = (width >= 3 * font_width ? font_width : 0);
1582 int inner_sy = (height >= 3 * font_height ? font_height : 0);
1583 boolean draw_masked = graphic_info[graphic].draw_masked;
1585 getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
1587 if (src_bitmap == NULL || width < font_width || height < font_height)
1589 ClearRectangle(drawto, dst_x, dst_y, font_width, font_height);
1593 src_x += (x == 0 ? 0 : x == xsize - 1 ? width - font_width :
1594 inner_sx + (x - 1) * font_width % inner_width);
1595 src_y += (y == 0 ? 0 : y == ysize - 1 ? height - font_height :
1596 inner_sy + (y - 1) * font_height % inner_height);
1600 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1601 dst_x - src_x, dst_y - src_y);
1602 BlitBitmapMasked(src_bitmap, drawto, src_x, src_y, font_width, font_height,
1606 BlitBitmap(src_bitmap, drawto, src_x, src_y, font_width, font_height,
1612 void DrawEnvelopeBackground(int dst_x, int dst_y, int ex, int ey, int font_nr)
1614 int font_width = getFontWidth(font_nr);
1615 int font_height = getFontHeight(font_nr);
1616 int graphic = IMG_GAME_ENVELOPE_BACKGROUND;
1619 int width = graphic_info[graphic].width;
1620 int height = graphic_info[graphic].height;
1621 boolean draw_masked = graphic_info[graphic].draw_masked;
1623 getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
1625 if (src_bitmap == NULL)
1627 ClearRectangle(drawto, dst_x, dst_y, font_width, font_height);
1631 src_x += (ex == -1 ? 0 : ex == +1 ? width - font_width : font_width);
1632 src_y += (ey == -1 ? 0 : ey == +1 ? height - font_height : font_height);
1636 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1637 dst_x - src_x, dst_y - src_y);
1638 BlitBitmapMasked(src_bitmap, drawto, src_x, src_y, font_width, font_height,
1642 BlitBitmap(src_bitmap, drawto, src_x, src_y, font_width, font_height,
1647 void ShowEnvelope(int envelope_nr)
1649 int graphic = IMG_GAME_ENVELOPE_BACKGROUND;
1650 boolean draw_masked = graphic_info[graphic].draw_masked;
1651 int mask_mode = (draw_masked ? BLIT_MASKED : BLIT_ON_BACKGROUND);
1652 int font_nr = FONT_TEXT_1;
1653 int font_width = getFontWidth(font_nr);
1654 int font_height = getFontHeight(font_nr);
1655 boolean ffwd_delay = (tape.playing && tape.fast_forward);
1656 int anim_delay = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
1657 int wait_delay = (ffwd_delay ? 500 : 1000);
1658 int start_pos_vertically = 0;
1661 if (game.envelope.anim_mode > 1)
1663 /* open envelope window horizontally */
1664 for (i = 0; i <= level.envelope_xsize[envelope_nr]; i++)
1668 int startx = (SXSIZE - xsize * font_width) / 2;
1669 int starty = (SYSIZE - ysize * font_height) / 2;
1671 SetDrawtoField(DRAW_BUFFERED);
1673 BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
1675 SetDrawtoField(DRAW_BACKBUFFER);
1678 for (y=0; y < ysize; y++) for (x=0; x < xsize; x++)
1679 DrawEnvelopeBackground(startx, starty, x, y, xsize, ysize, font_nr);
1681 for (y=0; y < ysize; y++) for (x=0; x < xsize; x++)
1683 int sx = SX + startx + x * font_width;
1684 int sy = SY + starty + y * font_height;
1685 int ex = (x == 0 ? -1 : x == xsize - 1 ? +1 : 0);
1686 int ey = (y == 0 ? -1 : y == ysize - 1 ? +1 : 0);
1688 DrawEnvelopeBackground(sx, sy, ex, ey, font_nr);
1692 redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
1695 Delay(anim_delay / 2);
1699 if (game.envelope.anim_mode < 1)
1700 start_pos_vertically = level.envelope_ysize[envelope_nr];
1702 /* open envelope window vertically */
1703 for (i = start_pos_vertically; i <= level.envelope_ysize[envelope_nr]; i++)
1705 int xsize = level.envelope_xsize[envelope_nr] + 2;
1707 int startx = (SXSIZE - xsize * font_width) / 2;
1708 int starty = (SYSIZE - ysize * font_height) / 2;
1710 SetDrawtoField(DRAW_BUFFERED);
1712 BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
1714 SetDrawtoField(DRAW_BACKBUFFER);
1717 for (y=0; y < ysize; y++) for (x=0; x < xsize; x++)
1718 DrawEnvelopeBackground(startx, starty, x, y, xsize, ysize, font_nr);
1720 for (y=0; y < ysize; y++) for (x=0; x < xsize; x++)
1722 int sx = SX + startx + x * font_width;
1723 int sy = SY + starty + y * font_height;
1724 int ex = (x == 0 ? -1 : x == xsize - 1 ? +1 : 0);
1725 int ey = (y == 0 ? -1 : y == ysize - 1 ? +1 : 0);
1727 DrawEnvelopeBackground(sx, sy, ex, ey, font_nr);
1731 DrawTextToTextArea(SX + startx + font_width, SY + starty + font_height,
1732 level.envelope_text[envelope_nr], FONT_TEXT_1,
1733 level.envelope_xsize[envelope_nr], i, mask_mode);
1735 redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
1744 WaitForEventToContinue();
1746 if (game.envelope.anim_mode > 0)
1748 /* close envelope window vertically */
1749 for (i = level.envelope_ysize[envelope_nr]; i >= 0; i--)
1751 int xsize = level.envelope_xsize[envelope_nr] + 2;
1753 int startx = (SXSIZE - xsize * font_width) / 2;
1754 int starty = (SYSIZE - ysize * font_height) / 2;
1756 SetDrawtoField(DRAW_BUFFERED);
1758 BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
1760 SetDrawtoField(DRAW_BACKBUFFER);
1763 for (y=0; y < ysize; y++) for (x=0; x < xsize; x++)
1764 DrawEnvelopeBackground(startx, starty, x, y, xsize, ysize, font_nr);
1766 for (y=0; y < ysize; y++) for (x=0; x < xsize; x++)
1768 int sx = SX + startx + x * font_width;
1769 int sy = SY + starty + y * font_height;
1770 int ex = (x == 0 ? -1 : x == xsize - 1 ? +1 : 0);
1771 int ey = (y == 0 ? -1 : y == ysize - 1 ? +1 : 0);
1773 DrawEnvelopeBackground(sx, sy, ex, ey, font_nr);
1777 DrawTextToTextArea(SX + startx + font_width, SY + starty + font_height,
1778 level.envelope_text[envelope_nr], FONT_TEXT_1,
1779 level.envelope_xsize[envelope_nr], i, mask_mode);
1781 redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
1788 if (game.envelope.anim_mode > 1)
1790 /* close envelope window horizontally */
1791 for (i = level.envelope_xsize[envelope_nr]; i >= 0; i--)
1795 int startx = (SXSIZE - xsize * font_width) / 2;
1796 int starty = (SYSIZE - ysize * font_height) / 2;
1798 SetDrawtoField(DRAW_BUFFERED);
1800 BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
1802 SetDrawtoField(DRAW_BACKBUFFER);
1805 for (y=0; y < ysize; y++) for (x=0; x < xsize; x++)
1806 DrawEnvelopeBackground(startx, starty, x, y, xsize, ysize, font_nr);
1808 for (y=0; y < ysize; y++) for (x=0; x < xsize; x++)
1810 int sx = SX + startx + x * font_width;
1811 int sy = SY + starty + y * font_height;
1812 int ex = (x == 0 ? -1 : x == xsize - 1 ? +1 : 0);
1813 int ey = (y == 0 ? -1 : y == ysize - 1 ? +1 : 0);
1815 DrawEnvelopeBackground(sx, sy, ex, ey, font_nr);
1819 redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
1822 Delay(anim_delay / 2);
1826 SetDrawtoField(DRAW_BUFFERED);
1828 redraw_mask |= REDRAW_FIELD;
1832 void getMicroGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
1834 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
1835 int mini_startx = src_bitmap->width * 3 / 4;
1836 int mini_starty = src_bitmap->height * 2 / 3;
1837 int src_x = mini_startx + graphic_info[graphic].src_x / 8;
1838 int src_y = mini_starty + graphic_info[graphic].src_y / 8;
1840 *bitmap = src_bitmap;
1845 void DrawMicroElement(int xpos, int ypos, int element)
1849 int graphic = el2preimg(element);
1851 getMicroGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
1852 BlitBitmap(src_bitmap, drawto, src_x, src_y, MICRO_TILEX, MICRO_TILEY,
1860 SetDrawBackgroundMask(REDRAW_NONE);
1863 for(x=BX1; x<=BX2; x++)
1864 for(y=BY1; y<=BY2; y++)
1865 DrawScreenField(x, y);
1867 redraw_mask |= REDRAW_FIELD;
1870 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
1874 for(x=0; x<size_x; x++)
1875 for(y=0; y<size_y; y++)
1876 DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
1878 redraw_mask |= REDRAW_FIELD;
1881 static void DrawMicroLevelExt(int xpos, int ypos, int from_x, int from_y)
1885 DrawBackground(xpos, ypos, MICROLEV_XSIZE, MICROLEV_YSIZE);
1887 if (lev_fieldx < STD_LEV_FIELDX)
1888 xpos += (STD_LEV_FIELDX - lev_fieldx) / 2 * MICRO_TILEX;
1889 if (lev_fieldy < STD_LEV_FIELDY)
1890 ypos += (STD_LEV_FIELDY - lev_fieldy) / 2 * MICRO_TILEY;
1892 xpos += MICRO_TILEX;
1893 ypos += MICRO_TILEY;
1895 for(x=-1; x<=STD_LEV_FIELDX; x++)
1897 for(y=-1; y<=STD_LEV_FIELDY; y++)
1899 int lx = from_x + x, ly = from_y + y;
1901 if (lx >= 0 && lx < lev_fieldx && ly >= 0 && ly < lev_fieldy)
1902 DrawMicroElement(xpos + x * MICRO_TILEX, ypos + y * MICRO_TILEY,
1903 level.field[lx][ly]);
1904 else if (lx >= -1 && lx < lev_fieldx+1 && ly >= -1 && ly < lev_fieldy+1
1905 && BorderElement != EL_EMPTY)
1906 DrawMicroElement(xpos + x * MICRO_TILEX, ypos + y * MICRO_TILEY,
1907 getBorderElement(lx, ly));
1911 redraw_mask |= REDRAW_MICROLEVEL;
1914 #define MICROLABEL_EMPTY 0
1915 #define MICROLABEL_LEVEL_NAME 1
1916 #define MICROLABEL_CREATED_BY 2
1917 #define MICROLABEL_LEVEL_AUTHOR 3
1918 #define MICROLABEL_IMPORTED_FROM 4
1919 #define MICROLABEL_LEVEL_IMPORT_INFO 5
1921 static void DrawMicroLevelLabelExt(int mode)
1923 char label_text[MAX_OUTPUT_LINESIZE + 1];
1924 int max_len_label_text;
1925 int font_nr = FONT_TEXT_2;
1927 if (mode == MICROLABEL_CREATED_BY || mode == MICROLABEL_IMPORTED_FROM)
1928 font_nr = FONT_TEXT_3;
1930 max_len_label_text = SXSIZE / getFontWidth(font_nr);
1932 DrawBackground(SX, MICROLABEL_YPOS, SXSIZE, getFontHeight(font_nr));
1934 strncpy(label_text, (mode == MICROLABEL_LEVEL_NAME ? level.name :
1935 mode == MICROLABEL_CREATED_BY ? "created by" :
1936 mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
1937 mode == MICROLABEL_IMPORTED_FROM ? "imported from" :
1938 mode == MICROLABEL_LEVEL_IMPORT_INFO ?
1939 leveldir_current->imported_from : ""),
1940 max_len_label_text);
1941 label_text[max_len_label_text] = '\0';
1943 if (strlen(label_text) > 0)
1945 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
1946 int lypos = MICROLABEL_YPOS;
1948 DrawText(lxpos, lypos, label_text, font_nr);
1951 redraw_mask |= REDRAW_MICROLEVEL;
1954 void DrawMicroLevel(int xpos, int ypos, boolean restart)
1956 static unsigned long scroll_delay = 0;
1957 static unsigned long label_delay = 0;
1958 static int from_x, from_y, scroll_direction;
1959 static int label_state, label_counter;
1960 int last_game_status = game_status; /* save current game status */
1962 /* force PREVIEW font on preview level */
1963 game_status = GAME_MODE_PSEUDO_PREVIEW;
1967 from_x = from_y = 0;
1968 scroll_direction = MV_RIGHT;
1972 DrawMicroLevelExt(xpos, ypos, from_x, from_y);
1973 DrawMicroLevelLabelExt(label_state);
1975 /* initialize delay counters */
1976 DelayReached(&scroll_delay, 0);
1977 DelayReached(&label_delay, 0);
1979 if (leveldir_current->name)
1981 int text_width = getTextWidth(leveldir_current->name, FONT_TEXT_1);
1982 int lxpos = SX + (SXSIZE - text_width) / 2;
1983 int lypos = SY + 352;
1985 DrawText(lxpos, lypos, leveldir_current->name, FONT_TEXT_1);
1988 game_status = last_game_status; /* restore current game status */
1993 /* scroll micro level, if needed */
1994 if ((lev_fieldx > STD_LEV_FIELDX || lev_fieldy > STD_LEV_FIELDY) &&
1995 DelayReached(&scroll_delay, MICROLEVEL_SCROLL_DELAY))
1997 switch (scroll_direction)
2003 scroll_direction = MV_UP;
2007 if (from_x < lev_fieldx - STD_LEV_FIELDX)
2010 scroll_direction = MV_DOWN;
2017 scroll_direction = MV_RIGHT;
2021 if (from_y < lev_fieldy - STD_LEV_FIELDY)
2024 scroll_direction = MV_LEFT;
2031 DrawMicroLevelExt(xpos, ypos, from_x, from_y);
2034 /* redraw micro level label, if needed */
2035 if (strcmp(level.name, NAMELESS_LEVEL_NAME) != 0 &&
2036 strcmp(level.author, ANONYMOUS_NAME) != 0 &&
2037 strcmp(level.author, leveldir_current->name) != 0 &&
2038 DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
2040 int max_label_counter = 23;
2042 if (leveldir_current->imported_from != NULL)
2043 max_label_counter += 14;
2045 label_counter = (label_counter + 1) % max_label_counter;
2046 label_state = (label_counter >= 0 && label_counter <= 7 ?
2047 MICROLABEL_LEVEL_NAME :
2048 label_counter >= 9 && label_counter <= 12 ?
2049 MICROLABEL_CREATED_BY :
2050 label_counter >= 14 && label_counter <= 21 ?
2051 MICROLABEL_LEVEL_AUTHOR :
2052 label_counter >= 23 && label_counter <= 26 ?
2053 MICROLABEL_IMPORTED_FROM :
2054 label_counter >= 28 && label_counter <= 35 ?
2055 MICROLABEL_LEVEL_IMPORT_INFO : MICROLABEL_EMPTY);
2056 DrawMicroLevelLabelExt(label_state);
2059 game_status = last_game_status; /* restore current game status */
2062 void WaitForEventToContinue()
2064 boolean still_wait = TRUE;
2066 /* simulate releasing mouse button over last gadget, if still pressed */
2068 HandleGadgets(-1, -1, 0);
2070 button_status = MB_RELEASED;
2082 case EVENT_BUTTONPRESS:
2083 case EVENT_KEYPRESS:
2087 case EVENT_KEYRELEASE:
2088 ClearPlayerAction();
2092 HandleOtherEvents(&event);
2096 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
2103 /* don't eat all CPU time */
2108 #define MAX_REQUEST_LINES 13
2109 #define MAX_REQUEST_LINE_LEN 7
2111 boolean Request(char *text, unsigned int req_state)
2113 int mx, my, ty, result = -1;
2114 unsigned int old_door_state;
2115 int last_game_status = game_status; /* save current game status */
2118 SetMouseCursor(CURSOR_DEFAULT);
2121 #if defined(PLATFORM_UNIX)
2122 /* pause network game while waiting for request to answer */
2123 if (options.network &&
2124 game_status == GAME_MODE_PLAYING &&
2125 req_state & REQUEST_WAIT_FOR)
2126 SendToServer_PausePlaying();
2129 old_door_state = GetDoorState();
2131 /* simulate releasing mouse button over last gadget, if still pressed */
2133 HandleGadgets(-1, -1, 0);
2137 CloseDoor(DOOR_CLOSE_1);
2139 /* save old door content */
2140 BlitBitmap(bitmap_db_door, bitmap_db_door,
2141 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
2142 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
2144 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
2146 /* clear door drawing field */
2147 DrawBackground(DX, DY, DXSIZE, DYSIZE);
2149 /* force DOOR font on preview level */
2150 game_status = GAME_MODE_PSEUDO_DOOR;
2152 /* write text for request */
2153 for(ty=0; ty < MAX_REQUEST_LINES; ty++)
2155 char text_line[MAX_REQUEST_LINE_LEN + 1];
2161 for(tl=0,tx=0; tx < MAX_REQUEST_LINE_LEN; tl++,tx++)
2164 if (!tc || tc == ' ')
2175 strncpy(text_line, text, tl);
2178 DrawText(DX + (DXSIZE - tl * getFontWidth(FONT_TEXT_2)) / 2,
2179 DY + 8 + ty * (getFontHeight(FONT_TEXT_2) + 2),
2180 text_line, FONT_TEXT_2);
2182 text += tl + (tc == ' ' ? 1 : 0);
2185 game_status = last_game_status; /* restore current game status */
2187 if (req_state & REQ_ASK)
2189 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
2190 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
2192 else if (req_state & REQ_CONFIRM)
2194 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
2196 else if (req_state & REQ_PLAYER)
2198 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
2199 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
2200 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
2201 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
2204 /* copy request gadgets to door backbuffer */
2205 BlitBitmap(drawto, bitmap_db_door,
2206 DX, DY, DXSIZE, DYSIZE,
2207 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2209 OpenDoor(DOOR_OPEN_1);
2215 if (!(req_state & REQUEST_WAIT_FOR))
2217 SetDrawBackgroundMask(REDRAW_FIELD);
2222 if (game_status != GAME_MODE_MAIN)
2225 button_status = MB_RELEASED;
2227 request_gadget_id = -1;
2229 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
2232 SetMouseCursor(CURSOR_DEFAULT);
2245 case EVENT_BUTTONPRESS:
2246 case EVENT_BUTTONRELEASE:
2247 case EVENT_MOTIONNOTIFY:
2249 if (event.type == EVENT_MOTIONNOTIFY)
2251 if (!PointerInWindow(window))
2252 continue; /* window and pointer are on different screens */
2257 motion_status = TRUE;
2258 mx = ((MotionEvent *) &event)->x;
2259 my = ((MotionEvent *) &event)->y;
2263 motion_status = FALSE;
2264 mx = ((ButtonEvent *) &event)->x;
2265 my = ((ButtonEvent *) &event)->y;
2266 if (event.type == EVENT_BUTTONPRESS)
2267 button_status = ((ButtonEvent *) &event)->button;
2269 button_status = MB_RELEASED;
2272 /* this sets 'request_gadget_id' */
2273 HandleGadgets(mx, my, button_status);
2275 switch(request_gadget_id)
2277 case TOOL_CTRL_ID_YES:
2280 case TOOL_CTRL_ID_NO:
2283 case TOOL_CTRL_ID_CONFIRM:
2284 result = TRUE | FALSE;
2287 case TOOL_CTRL_ID_PLAYER_1:
2290 case TOOL_CTRL_ID_PLAYER_2:
2293 case TOOL_CTRL_ID_PLAYER_3:
2296 case TOOL_CTRL_ID_PLAYER_4:
2307 case EVENT_KEYPRESS:
2308 switch(GetEventKey((KeyEvent *)&event, TRUE))
2321 if (req_state & REQ_PLAYER)
2325 case EVENT_KEYRELEASE:
2326 ClearPlayerAction();
2330 HandleOtherEvents(&event);
2334 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
2336 int joy = AnyJoystick();
2338 if (joy & JOY_BUTTON_1)
2340 else if (joy & JOY_BUTTON_2)
2346 /* don't eat all CPU time */
2350 if (game_status != GAME_MODE_MAIN)
2355 if (!(req_state & REQ_STAY_OPEN))
2357 CloseDoor(DOOR_CLOSE_1);
2359 if (!(req_state & REQ_STAY_CLOSED) && (old_door_state & DOOR_OPEN_1))
2361 BlitBitmap(bitmap_db_door, bitmap_db_door,
2362 DOOR_GFX_PAGEX2,DOOR_GFX_PAGEY1, DXSIZE,DYSIZE,
2363 DOOR_GFX_PAGEX1,DOOR_GFX_PAGEY1);
2364 OpenDoor(DOOR_OPEN_1);
2370 SetDrawBackgroundMask(REDRAW_FIELD);
2372 #if defined(PLATFORM_UNIX)
2373 /* continue network game after request */
2374 if (options.network &&
2375 game_status == GAME_MODE_PLAYING &&
2376 req_state & REQUEST_WAIT_FOR)
2377 SendToServer_ContinuePlaying();
2383 unsigned int OpenDoor(unsigned int door_state)
2385 unsigned int new_door_state;
2387 if (door_state & DOOR_COPY_BACK)
2389 BlitBitmap(bitmap_db_door, bitmap_db_door,
2390 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE + VYSIZE,
2391 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2392 door_state &= ~DOOR_COPY_BACK;
2395 new_door_state = MoveDoor(door_state);
2397 return(new_door_state);
2400 unsigned int CloseDoor(unsigned int door_state)
2402 unsigned int new_door_state;
2404 BlitBitmap(backbuffer, bitmap_db_door,
2405 DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2406 BlitBitmap(backbuffer, bitmap_db_door,
2407 VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
2409 new_door_state = MoveDoor(door_state);
2411 return(new_door_state);
2414 unsigned int GetDoorState()
2416 return MoveDoor(DOOR_GET_STATE);
2419 unsigned int SetDoorState(unsigned int door_state)
2421 return MoveDoor(door_state | DOOR_SET_STATE);
2424 unsigned int MoveDoor(unsigned int door_state)
2426 static int door1 = DOOR_OPEN_1;
2427 static int door2 = DOOR_CLOSE_2;
2428 static unsigned long door_delay = 0;
2429 int x, start, stepsize = door.step_offset;
2430 unsigned long door_delay_value = door.step_delay;
2432 if (door_state == DOOR_GET_STATE)
2433 return(door1 | door2);
2435 if (door_state & DOOR_SET_STATE)
2437 if (door_state & DOOR_ACTION_1)
2438 door1 = door_state & DOOR_ACTION_1;
2439 if (door_state & DOOR_ACTION_2)
2440 door2 = door_state & DOOR_ACTION_2;
2442 return(door1 | door2);
2445 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
2446 door_state &= ~DOOR_OPEN_1;
2447 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
2448 door_state &= ~DOOR_CLOSE_1;
2449 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
2450 door_state &= ~DOOR_OPEN_2;
2451 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
2452 door_state &= ~DOOR_CLOSE_2;
2454 if (setup.quick_doors)
2457 door_delay_value = 0;
2459 StopSound(SND_DOOR_OPENING);
2460 StopSound(SND_DOOR_CLOSING);
2463 if (global.autoplay_leveldir)
2465 door_state |= DOOR_NO_DELAY;
2466 door_state &= ~DOOR_CLOSE_ALL;
2469 if (door_state & DOOR_ACTION)
2471 if (!(door_state & DOOR_NO_DELAY))
2473 /* opening door sound has priority over simultaneously closing door */
2474 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
2475 PlaySoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
2476 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
2477 PlaySoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
2480 start = ((door_state & DOOR_NO_DELAY) ? DXSIZE : 0);
2482 for(x=start; x<=DXSIZE; x+=stepsize)
2484 Bitmap *bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
2485 GC gc = bitmap->stored_clip_gc;
2487 if (!(door_state & DOOR_NO_DELAY))
2488 WaitUntilDelayReached(&door_delay, door_delay_value);
2490 if (door_state & DOOR_ACTION_1)
2492 int i = (door_state & DOOR_OPEN_1 ? DXSIZE-x : x);
2493 int j = (door.anim_mode == 0 ? (DXSIZE - i) / 3 : 0);
2495 BlitBitmap(bitmap_db_door, drawto,
2496 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + i/2,
2497 DXSIZE,DYSIZE - i/2, DX, DY);
2499 ClearRectangle(drawto, DX, DY + DYSIZE - i/2, DXSIZE,i/2);
2501 if (door.anim_mode == 0)
2503 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2504 BlitBitmapMasked(bitmap, drawto,
2505 DXSIZE, DOOR_GFX_PAGEY1, i, 77,
2506 DX + DXSIZE - i, DY + j);
2507 BlitBitmapMasked(bitmap, drawto,
2508 DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63,
2509 DX + DXSIZE - i, DY + 140 + j);
2510 SetClipOrigin(bitmap, gc, DX - DXSIZE + i,
2511 DY - (DOOR_GFX_PAGEY1 + j));
2512 BlitBitmapMasked(bitmap, drawto,
2513 DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j,
2515 BlitBitmapMasked(bitmap, drawto,
2516 DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63,
2519 BlitBitmapMasked(bitmap, drawto,
2520 DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
2522 BlitBitmapMasked(bitmap, drawto,
2523 DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
2525 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2526 BlitBitmapMasked(bitmap, drawto,
2527 DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
2528 DX + DXSIZE - i, DY + 77 + j);
2529 BlitBitmapMasked(bitmap, drawto,
2530 DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
2531 DX + DXSIZE - i, DY + 203 + j);
2535 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2536 BlitBitmapMasked(bitmap, drawto,
2537 DXSIZE, DOOR_GFX_PAGEY1, i, DYSIZE,
2538 DX + DXSIZE - i, DY);
2540 SetClipOrigin(bitmap, gc, DX - DXSIZE + i, DY - DOOR_GFX_PAGEY1);
2541 BlitBitmapMasked(bitmap, drawto,
2542 DXSIZE - i, DOOR_GFX_PAGEY1, i, DYSIZE,
2546 redraw_mask |= REDRAW_DOOR_1;
2549 if (door_state & DOOR_ACTION_2)
2551 int i = (door_state & DOOR_OPEN_2 ? VXSIZE - x : x);
2552 int j = (VXSIZE - i) / 3;
2554 BlitBitmap(bitmap_db_door, drawto,
2555 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + i/2,
2556 VXSIZE, VYSIZE - i/2, VX, VY);
2558 ClearRectangle(drawto, VX, VY + VYSIZE-i/2, VXSIZE, i/2);
2560 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2561 BlitBitmapMasked(bitmap, drawto,
2562 VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2,
2563 VX + VXSIZE-i, VY+j);
2564 SetClipOrigin(bitmap, gc,
2565 VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
2566 BlitBitmapMasked(bitmap, drawto,
2567 VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j,
2570 BlitBitmapMasked(bitmap, drawto,
2571 VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2,
2572 i, VYSIZE / 2, VX, VY + VYSIZE / 2 - j);
2573 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2574 BlitBitmapMasked(bitmap, drawto,
2575 VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2,
2577 VX + VXSIZE - i, VY + VYSIZE / 2 + j);
2579 redraw_mask |= REDRAW_DOOR_2;
2584 if (game_status == GAME_MODE_MAIN)
2589 if (setup.quick_doors)
2591 StopSound(SND_DOOR_OPENING);
2592 StopSound(SND_DOOR_CLOSING);
2595 if (door_state & DOOR_ACTION_1)
2596 door1 = door_state & DOOR_ACTION_1;
2597 if (door_state & DOOR_ACTION_2)
2598 door2 = door_state & DOOR_ACTION_2;
2600 return (door1 | door2);
2603 void DrawSpecialEditorDoor()
2605 /* draw bigger toolbox window */
2606 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
2607 DOOR_GFX_PAGEX7, 0, EXSIZE + 8, 8,
2609 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
2610 EX - 4, VY - 4, EXSIZE + 8, EYSIZE - VYSIZE + 4,
2613 redraw_mask |= REDRAW_ALL;
2616 void UndrawSpecialEditorDoor()
2618 /* draw normal tape recorder window */
2619 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
2620 EX - 4, EY - 12, EXSIZE + 8, EYSIZE - VYSIZE + 12,
2623 redraw_mask |= REDRAW_ALL;
2627 /* ---------- new tool button stuff ---------------------------------------- */
2629 /* graphic position values for tool buttons */
2630 #define TOOL_BUTTON_YES_XPOS 2
2631 #define TOOL_BUTTON_YES_YPOS 250
2632 #define TOOL_BUTTON_YES_GFX_YPOS 0
2633 #define TOOL_BUTTON_YES_XSIZE 46
2634 #define TOOL_BUTTON_YES_YSIZE 28
2635 #define TOOL_BUTTON_NO_XPOS 52
2636 #define TOOL_BUTTON_NO_YPOS TOOL_BUTTON_YES_YPOS
2637 #define TOOL_BUTTON_NO_GFX_YPOS TOOL_BUTTON_YES_GFX_YPOS
2638 #define TOOL_BUTTON_NO_XSIZE TOOL_BUTTON_YES_XSIZE
2639 #define TOOL_BUTTON_NO_YSIZE TOOL_BUTTON_YES_YSIZE
2640 #define TOOL_BUTTON_CONFIRM_XPOS TOOL_BUTTON_YES_XPOS
2641 #define TOOL_BUTTON_CONFIRM_YPOS TOOL_BUTTON_YES_YPOS
2642 #define TOOL_BUTTON_CONFIRM_GFX_YPOS 30
2643 #define TOOL_BUTTON_CONFIRM_XSIZE 96
2644 #define TOOL_BUTTON_CONFIRM_YSIZE TOOL_BUTTON_YES_YSIZE
2645 #define TOOL_BUTTON_PLAYER_XSIZE 30
2646 #define TOOL_BUTTON_PLAYER_YSIZE 30
2647 #define TOOL_BUTTON_PLAYER_GFX_XPOS 5
2648 #define TOOL_BUTTON_PLAYER_GFX_YPOS 185
2649 #define TOOL_BUTTON_PLAYER_XPOS (5 + TOOL_BUTTON_PLAYER_XSIZE / 2)
2650 #define TOOL_BUTTON_PLAYER_YPOS (215 - TOOL_BUTTON_PLAYER_YSIZE / 2)
2651 #define TOOL_BUTTON_PLAYER1_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2652 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2653 #define TOOL_BUTTON_PLAYER2_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2654 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2655 #define TOOL_BUTTON_PLAYER3_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2656 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2657 #define TOOL_BUTTON_PLAYER4_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2658 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2659 #define TOOL_BUTTON_PLAYER1_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2660 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2661 #define TOOL_BUTTON_PLAYER2_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2662 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2663 #define TOOL_BUTTON_PLAYER3_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2664 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2665 #define TOOL_BUTTON_PLAYER4_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2666 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2675 } toolbutton_info[NUM_TOOL_BUTTONS] =
2678 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_GFX_YPOS,
2679 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_YPOS,
2680 TOOL_BUTTON_YES_XSIZE, TOOL_BUTTON_YES_YSIZE,
2685 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_GFX_YPOS,
2686 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_YPOS,
2687 TOOL_BUTTON_NO_XSIZE, TOOL_BUTTON_NO_YSIZE,
2692 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_GFX_YPOS,
2693 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_YPOS,
2694 TOOL_BUTTON_CONFIRM_XSIZE, TOOL_BUTTON_CONFIRM_YSIZE,
2695 TOOL_CTRL_ID_CONFIRM,
2699 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2700 TOOL_BUTTON_PLAYER1_XPOS, TOOL_BUTTON_PLAYER1_YPOS,
2701 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2702 TOOL_CTRL_ID_PLAYER_1,
2706 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2707 TOOL_BUTTON_PLAYER2_XPOS, TOOL_BUTTON_PLAYER2_YPOS,
2708 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2709 TOOL_CTRL_ID_PLAYER_2,
2713 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2714 TOOL_BUTTON_PLAYER3_XPOS, TOOL_BUTTON_PLAYER3_YPOS,
2715 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2716 TOOL_CTRL_ID_PLAYER_3,
2720 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2721 TOOL_BUTTON_PLAYER4_XPOS, TOOL_BUTTON_PLAYER4_YPOS,
2722 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2723 TOOL_CTRL_ID_PLAYER_4,
2728 void CreateToolButtons()
2732 for (i=0; i<NUM_TOOL_BUTTONS; i++)
2734 Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
2735 Bitmap *deco_bitmap = None;
2736 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
2737 struct GadgetInfo *gi;
2738 unsigned long event_mask;
2739 int gd_xoffset, gd_yoffset;
2740 int gd_x1, gd_x2, gd_y;
2743 event_mask = GD_EVENT_RELEASED;
2745 gd_xoffset = toolbutton_info[i].xpos;
2746 gd_yoffset = toolbutton_info[i].ypos;
2747 gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
2748 gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
2749 gd_y = DOOR_GFX_PAGEY1 + gd_yoffset;
2751 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
2753 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
2755 getMiniGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr),
2756 &deco_bitmap, &deco_x, &deco_y);
2757 deco_xpos = (toolbutton_info[i].width - MINI_TILEX) / 2;
2758 deco_ypos = (toolbutton_info[i].height - MINI_TILEY) / 2;
2761 gi = CreateGadget(GDI_CUSTOM_ID, id,
2762 GDI_INFO_TEXT, toolbutton_info[i].infotext,
2763 GDI_X, DX + toolbutton_info[i].x,
2764 GDI_Y, DY + toolbutton_info[i].y,
2765 GDI_WIDTH, toolbutton_info[i].width,
2766 GDI_HEIGHT, toolbutton_info[i].height,
2767 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
2768 GDI_STATE, GD_BUTTON_UNPRESSED,
2769 GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
2770 GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
2771 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
2772 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
2773 GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
2774 GDI_DECORATION_SHIFTING, 1, 1,
2775 GDI_EVENT_MASK, event_mask,
2776 GDI_CALLBACK_ACTION, HandleToolButtons,
2780 Error(ERR_EXIT, "cannot create gadget");
2782 tool_gadget[id] = gi;
2786 void FreeToolButtons()
2790 for (i=0; i<NUM_TOOL_BUTTONS; i++)
2791 FreeGadget(tool_gadget[i]);
2794 static void UnmapToolButtons()
2798 for (i=0; i<NUM_TOOL_BUTTONS; i++)
2799 UnmapGadget(tool_gadget[i]);
2802 static void HandleToolButtons(struct GadgetInfo *gi)
2804 request_gadget_id = gi->custom_id;
2807 int get_next_element(int element)
2811 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
2812 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
2813 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
2814 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
2815 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
2816 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
2817 case EL_AMOEBA_DROPPING: return EL_AMOEBA_WET;
2819 default: return element;
2823 int el_act_dir2img(int element, int action, int direction)
2825 element = GFX_ELEMENT(element);
2826 direction = MV_DIR_BIT(direction);
2828 return element_info[element].direction_graphic[action][direction];
2831 static int el_act_dir2crm(int element, int action, int direction)
2833 element = GFX_ELEMENT(element);
2834 direction = MV_DIR_BIT(direction);
2836 return element_info[element].direction_crumbled[action][direction];
2839 int el_act2img(int element, int action)
2841 element = GFX_ELEMENT(element);
2843 return element_info[element].graphic[action];
2846 int el_act2crm(int element, int action)
2848 element = GFX_ELEMENT(element);
2850 return element_info[element].crumbled[action];
2853 int el_dir2img(int element, int direction)
2855 element = GFX_ELEMENT(element);
2857 return el_act_dir2img(element, ACTION_DEFAULT, direction);
2860 int el2img(int element)
2862 element = GFX_ELEMENT(element);
2864 return element_info[element].graphic[ACTION_DEFAULT];
2867 int el2edimg(int element)
2869 element = GFX_ELEMENT(element);
2871 return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
2874 int el2preimg(int element)
2876 element = GFX_ELEMENT(element);
2878 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];