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,
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);
1660 /* open envelope window horizontally */
1661 for (i = 0; i <= level.envelope_xsize; i++)
1665 int startx = (SXSIZE - xsize * font_width) / 2;
1666 int starty = (SYSIZE - ysize * font_height) / 2;
1668 SetDrawtoField(DRAW_BUFFERED);
1670 BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
1672 SetDrawtoField(DRAW_BACKBUFFER);
1675 for (y=0; y < ysize; y++) for (x=0; x < xsize; x++)
1676 DrawEnvelopeBackground(startx, starty, x, y, xsize, ysize, font_nr);
1678 for (y=0; y < ysize; y++) for (x=0; x < xsize; x++)
1680 int sx = SX + startx + x * font_width;
1681 int sy = SY + starty + y * font_height;
1682 int ex = (x == 0 ? -1 : x == xsize - 1 ? +1 : 0);
1683 int ey = (y == 0 ? -1 : y == ysize - 1 ? +1 : 0);
1685 DrawEnvelopeBackground(sx, sy, ex, ey, font_nr);
1689 redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
1695 /* open envelope window vertically */
1696 for (i = 0; i <= level.envelope_ysize; i++)
1698 int xsize = level.envelope_xsize + 2;
1700 int startx = (SXSIZE - xsize * font_width) / 2;
1701 int starty = (SYSIZE - ysize * font_height) / 2;
1703 SetDrawtoField(DRAW_BUFFERED);
1705 BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
1707 SetDrawtoField(DRAW_BACKBUFFER);
1710 for (y=0; y < ysize; y++) for (x=0; x < xsize; x++)
1711 DrawEnvelopeBackground(startx, starty, x, y, xsize, ysize, font_nr);
1713 for (y=0; y < ysize; y++) for (x=0; x < xsize; x++)
1715 int sx = SX + startx + x * font_width;
1716 int sy = SY + starty + y * font_height;
1717 int ex = (x == 0 ? -1 : x == xsize - 1 ? +1 : 0);
1718 int ey = (y == 0 ? -1 : y == ysize - 1 ? +1 : 0);
1720 DrawEnvelopeBackground(sx, sy, ex, ey, font_nr);
1724 DrawTextToTextArea(SX + startx + font_width,
1725 SY + starty + font_height, level.envelope,
1726 FONT_TEXT_1, level.envelope_xsize, i, mask_mode);
1728 redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
1737 WaitForEventToContinue();
1739 /* close envelope window vertically */
1740 for (i = level.envelope_ysize; i >= 0; i--)
1742 int xsize = level.envelope_xsize + 2;
1744 int startx = (SXSIZE - xsize * font_width) / 2;
1745 int starty = (SYSIZE - ysize * font_height) / 2;
1747 SetDrawtoField(DRAW_BUFFERED);
1749 BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
1751 SetDrawtoField(DRAW_BACKBUFFER);
1754 for (y=0; y < ysize; y++) for (x=0; x < xsize; x++)
1755 DrawEnvelopeBackground(startx, starty, x, y, xsize, ysize, font_nr);
1757 for (y=0; y < ysize; y++) for (x=0; x < xsize; x++)
1759 int sx = SX + startx + x * font_width;
1760 int sy = SY + starty + y * font_height;
1761 int ex = (x == 0 ? -1 : x == xsize - 1 ? +1 : 0);
1762 int ey = (y == 0 ? -1 : y == ysize - 1 ? +1 : 0);
1764 DrawEnvelopeBackground(sx, sy, ex, ey, font_nr);
1768 DrawTextToTextArea(SX + startx + font_width,
1769 SY + starty + font_height, level.envelope,
1770 FONT_TEXT_1, level.envelope_xsize, i, mask_mode);
1772 redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
1778 /* close envelope window horizontally */
1779 for (i = level.envelope_xsize; i >= 0; i--)
1783 int startx = (SXSIZE - xsize * font_width) / 2;
1784 int starty = (SYSIZE - ysize * font_height) / 2;
1786 SetDrawtoField(DRAW_BUFFERED);
1788 BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
1790 SetDrawtoField(DRAW_BACKBUFFER);
1793 for (y=0; y < ysize; y++) for (x=0; x < xsize; x++)
1794 DrawEnvelopeBackground(startx, starty, x, y, xsize, ysize, font_nr);
1796 for (y=0; y < ysize; y++) for (x=0; x < xsize; x++)
1798 int sx = SX + startx + x * font_width;
1799 int sy = SY + starty + y * font_height;
1800 int ex = (x == 0 ? -1 : x == xsize - 1 ? +1 : 0);
1801 int ey = (y == 0 ? -1 : y == ysize - 1 ? +1 : 0);
1803 DrawEnvelopeBackground(sx, sy, ex, ey, font_nr);
1807 redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
1813 SetDrawtoField(DRAW_BUFFERED);
1815 redraw_mask |= REDRAW_FIELD;
1819 void getMicroGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
1821 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
1822 int mini_startx = src_bitmap->width * 3 / 4;
1823 int mini_starty = src_bitmap->height * 2 / 3;
1824 int src_x = mini_startx + graphic_info[graphic].src_x / 8;
1825 int src_y = mini_starty + graphic_info[graphic].src_y / 8;
1827 *bitmap = src_bitmap;
1832 void DrawMicroElement(int xpos, int ypos, int element)
1836 int graphic = el2preimg(element);
1838 getMicroGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
1839 BlitBitmap(src_bitmap, drawto, src_x, src_y, MICRO_TILEX, MICRO_TILEY,
1847 SetDrawBackgroundMask(REDRAW_NONE);
1850 for(x=BX1; x<=BX2; x++)
1851 for(y=BY1; y<=BY2; y++)
1852 DrawScreenField(x, y);
1854 redraw_mask |= REDRAW_FIELD;
1857 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
1861 for(x=0; x<size_x; x++)
1862 for(y=0; y<size_y; y++)
1863 DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
1865 redraw_mask |= REDRAW_FIELD;
1868 static void DrawMicroLevelExt(int xpos, int ypos, int from_x, int from_y)
1872 DrawBackground(xpos, ypos, MICROLEV_XSIZE, MICROLEV_YSIZE);
1874 if (lev_fieldx < STD_LEV_FIELDX)
1875 xpos += (STD_LEV_FIELDX - lev_fieldx) / 2 * MICRO_TILEX;
1876 if (lev_fieldy < STD_LEV_FIELDY)
1877 ypos += (STD_LEV_FIELDY - lev_fieldy) / 2 * MICRO_TILEY;
1879 xpos += MICRO_TILEX;
1880 ypos += MICRO_TILEY;
1882 for(x=-1; x<=STD_LEV_FIELDX; x++)
1884 for(y=-1; y<=STD_LEV_FIELDY; y++)
1886 int lx = from_x + x, ly = from_y + y;
1888 if (lx >= 0 && lx < lev_fieldx && ly >= 0 && ly < lev_fieldy)
1889 DrawMicroElement(xpos + x * MICRO_TILEX, ypos + y * MICRO_TILEY,
1890 level.field[lx][ly]);
1891 else if (lx >= -1 && lx < lev_fieldx+1 && ly >= -1 && ly < lev_fieldy+1
1892 && BorderElement != EL_EMPTY)
1893 DrawMicroElement(xpos + x * MICRO_TILEX, ypos + y * MICRO_TILEY,
1894 getBorderElement(lx, ly));
1898 redraw_mask |= REDRAW_MICROLEVEL;
1901 #define MICROLABEL_EMPTY 0
1902 #define MICROLABEL_LEVEL_NAME 1
1903 #define MICROLABEL_CREATED_BY 2
1904 #define MICROLABEL_LEVEL_AUTHOR 3
1905 #define MICROLABEL_IMPORTED_FROM 4
1906 #define MICROLABEL_LEVEL_IMPORT_INFO 5
1908 static void DrawMicroLevelLabelExt(int mode)
1910 char label_text[MAX_OUTPUT_LINESIZE + 1];
1911 int max_len_label_text;
1912 int font_nr = FONT_TEXT_2;
1914 if (mode == MICROLABEL_CREATED_BY || mode == MICROLABEL_IMPORTED_FROM)
1915 font_nr = FONT_TEXT_3;
1917 max_len_label_text = SXSIZE / getFontWidth(font_nr);
1919 DrawBackground(SX, MICROLABEL_YPOS, SXSIZE, getFontHeight(font_nr));
1921 strncpy(label_text, (mode == MICROLABEL_LEVEL_NAME ? level.name :
1922 mode == MICROLABEL_CREATED_BY ? "created by" :
1923 mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
1924 mode == MICROLABEL_IMPORTED_FROM ? "imported from" :
1925 mode == MICROLABEL_LEVEL_IMPORT_INFO ?
1926 leveldir_current->imported_from : ""),
1927 max_len_label_text);
1928 label_text[max_len_label_text] = '\0';
1930 if (strlen(label_text) > 0)
1932 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
1933 int lypos = MICROLABEL_YPOS;
1935 DrawText(lxpos, lypos, label_text, font_nr);
1938 redraw_mask |= REDRAW_MICROLEVEL;
1941 void DrawMicroLevel(int xpos, int ypos, boolean restart)
1943 static unsigned long scroll_delay = 0;
1944 static unsigned long label_delay = 0;
1945 static int from_x, from_y, scroll_direction;
1946 static int label_state, label_counter;
1947 int last_game_status = game_status; /* save current game status */
1949 /* force PREVIEW font on preview level */
1950 game_status = GAME_MODE_PSEUDO_PREVIEW;
1954 from_x = from_y = 0;
1955 scroll_direction = MV_RIGHT;
1959 DrawMicroLevelExt(xpos, ypos, from_x, from_y);
1960 DrawMicroLevelLabelExt(label_state);
1962 /* initialize delay counters */
1963 DelayReached(&scroll_delay, 0);
1964 DelayReached(&label_delay, 0);
1966 if (leveldir_current->name)
1968 int text_width = getTextWidth(leveldir_current->name, FONT_TEXT_1);
1969 int lxpos = SX + (SXSIZE - text_width) / 2;
1970 int lypos = SY + 352;
1972 DrawText(lxpos, lypos, leveldir_current->name, FONT_TEXT_1);
1975 game_status = last_game_status; /* restore current game status */
1980 /* scroll micro level, if needed */
1981 if ((lev_fieldx > STD_LEV_FIELDX || lev_fieldy > STD_LEV_FIELDY) &&
1982 DelayReached(&scroll_delay, MICROLEVEL_SCROLL_DELAY))
1984 switch (scroll_direction)
1990 scroll_direction = MV_UP;
1994 if (from_x < lev_fieldx - STD_LEV_FIELDX)
1997 scroll_direction = MV_DOWN;
2004 scroll_direction = MV_RIGHT;
2008 if (from_y < lev_fieldy - STD_LEV_FIELDY)
2011 scroll_direction = MV_LEFT;
2018 DrawMicroLevelExt(xpos, ypos, from_x, from_y);
2021 /* redraw micro level label, if needed */
2022 if (strcmp(level.name, NAMELESS_LEVEL_NAME) != 0 &&
2023 strcmp(level.author, ANONYMOUS_NAME) != 0 &&
2024 strcmp(level.author, leveldir_current->name) != 0 &&
2025 DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
2027 int max_label_counter = 23;
2029 if (leveldir_current->imported_from != NULL)
2030 max_label_counter += 14;
2032 label_counter = (label_counter + 1) % max_label_counter;
2033 label_state = (label_counter >= 0 && label_counter <= 7 ?
2034 MICROLABEL_LEVEL_NAME :
2035 label_counter >= 9 && label_counter <= 12 ?
2036 MICROLABEL_CREATED_BY :
2037 label_counter >= 14 && label_counter <= 21 ?
2038 MICROLABEL_LEVEL_AUTHOR :
2039 label_counter >= 23 && label_counter <= 26 ?
2040 MICROLABEL_IMPORTED_FROM :
2041 label_counter >= 28 && label_counter <= 35 ?
2042 MICROLABEL_LEVEL_IMPORT_INFO : MICROLABEL_EMPTY);
2043 DrawMicroLevelLabelExt(label_state);
2046 game_status = last_game_status; /* restore current game status */
2049 void WaitForEventToContinue()
2051 boolean still_wait = TRUE;
2053 /* simulate releasing mouse button over last gadget, if still pressed */
2055 HandleGadgets(-1, -1, 0);
2057 button_status = MB_RELEASED;
2069 case EVENT_BUTTONPRESS:
2070 case EVENT_KEYPRESS:
2074 case EVENT_KEYRELEASE:
2075 ClearPlayerAction();
2079 HandleOtherEvents(&event);
2083 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
2090 /* don't eat all CPU time */
2095 #define MAX_REQUEST_LINES 13
2096 #define MAX_REQUEST_LINE_LEN 7
2098 boolean Request(char *text, unsigned int req_state)
2100 int mx, my, ty, result = -1;
2101 unsigned int old_door_state;
2102 int last_game_status = game_status; /* save current game status */
2105 SetMouseCursor(CURSOR_DEFAULT);
2108 #if defined(PLATFORM_UNIX)
2109 /* pause network game while waiting for request to answer */
2110 if (options.network &&
2111 game_status == GAME_MODE_PLAYING &&
2112 req_state & REQUEST_WAIT_FOR)
2113 SendToServer_PausePlaying();
2116 old_door_state = GetDoorState();
2118 /* simulate releasing mouse button over last gadget, if still pressed */
2120 HandleGadgets(-1, -1, 0);
2124 CloseDoor(DOOR_CLOSE_1);
2126 /* save old door content */
2127 BlitBitmap(bitmap_db_door, bitmap_db_door,
2128 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
2129 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
2131 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
2133 /* clear door drawing field */
2134 DrawBackground(DX, DY, DXSIZE, DYSIZE);
2136 /* force DOOR font on preview level */
2137 game_status = GAME_MODE_PSEUDO_DOOR;
2139 /* write text for request */
2140 for(ty=0; ty < MAX_REQUEST_LINES; ty++)
2142 char text_line[MAX_REQUEST_LINE_LEN + 1];
2148 for(tl=0,tx=0; tx < MAX_REQUEST_LINE_LEN; tl++,tx++)
2151 if (!tc || tc == ' ')
2162 strncpy(text_line, text, tl);
2165 DrawText(DX + (DXSIZE - tl * getFontWidth(FONT_TEXT_2)) / 2,
2166 DY + 8 + ty * (getFontHeight(FONT_TEXT_2) + 2),
2167 text_line, FONT_TEXT_2);
2169 text += tl + (tc == ' ' ? 1 : 0);
2172 game_status = last_game_status; /* restore current game status */
2174 if (req_state & REQ_ASK)
2176 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
2177 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
2179 else if (req_state & REQ_CONFIRM)
2181 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
2183 else if (req_state & REQ_PLAYER)
2185 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
2186 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
2187 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
2188 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
2191 /* copy request gadgets to door backbuffer */
2192 BlitBitmap(drawto, bitmap_db_door,
2193 DX, DY, DXSIZE, DYSIZE,
2194 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2196 OpenDoor(DOOR_OPEN_1);
2202 if (!(req_state & REQUEST_WAIT_FOR))
2204 SetDrawBackgroundMask(REDRAW_FIELD);
2209 if (game_status != GAME_MODE_MAIN)
2212 button_status = MB_RELEASED;
2214 request_gadget_id = -1;
2216 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
2219 SetMouseCursor(CURSOR_DEFAULT);
2232 case EVENT_BUTTONPRESS:
2233 case EVENT_BUTTONRELEASE:
2234 case EVENT_MOTIONNOTIFY:
2236 if (event.type == EVENT_MOTIONNOTIFY)
2238 if (!PointerInWindow(window))
2239 continue; /* window and pointer are on different screens */
2244 motion_status = TRUE;
2245 mx = ((MotionEvent *) &event)->x;
2246 my = ((MotionEvent *) &event)->y;
2250 motion_status = FALSE;
2251 mx = ((ButtonEvent *) &event)->x;
2252 my = ((ButtonEvent *) &event)->y;
2253 if (event.type == EVENT_BUTTONPRESS)
2254 button_status = ((ButtonEvent *) &event)->button;
2256 button_status = MB_RELEASED;
2259 /* this sets 'request_gadget_id' */
2260 HandleGadgets(mx, my, button_status);
2262 switch(request_gadget_id)
2264 case TOOL_CTRL_ID_YES:
2267 case TOOL_CTRL_ID_NO:
2270 case TOOL_CTRL_ID_CONFIRM:
2271 result = TRUE | FALSE;
2274 case TOOL_CTRL_ID_PLAYER_1:
2277 case TOOL_CTRL_ID_PLAYER_2:
2280 case TOOL_CTRL_ID_PLAYER_3:
2283 case TOOL_CTRL_ID_PLAYER_4:
2294 case EVENT_KEYPRESS:
2295 switch(GetEventKey((KeyEvent *)&event, TRUE))
2308 if (req_state & REQ_PLAYER)
2312 case EVENT_KEYRELEASE:
2313 ClearPlayerAction();
2317 HandleOtherEvents(&event);
2321 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
2323 int joy = AnyJoystick();
2325 if (joy & JOY_BUTTON_1)
2327 else if (joy & JOY_BUTTON_2)
2333 /* don't eat all CPU time */
2337 if (game_status != GAME_MODE_MAIN)
2342 if (!(req_state & REQ_STAY_OPEN))
2344 CloseDoor(DOOR_CLOSE_1);
2346 if (!(req_state & REQ_STAY_CLOSED) && (old_door_state & DOOR_OPEN_1))
2348 BlitBitmap(bitmap_db_door, bitmap_db_door,
2349 DOOR_GFX_PAGEX2,DOOR_GFX_PAGEY1, DXSIZE,DYSIZE,
2350 DOOR_GFX_PAGEX1,DOOR_GFX_PAGEY1);
2351 OpenDoor(DOOR_OPEN_1);
2357 SetDrawBackgroundMask(REDRAW_FIELD);
2359 #if defined(PLATFORM_UNIX)
2360 /* continue network game after request */
2361 if (options.network &&
2362 game_status == GAME_MODE_PLAYING &&
2363 req_state & REQUEST_WAIT_FOR)
2364 SendToServer_ContinuePlaying();
2370 unsigned int OpenDoor(unsigned int door_state)
2372 unsigned int new_door_state;
2374 if (door_state & DOOR_COPY_BACK)
2376 BlitBitmap(bitmap_db_door, bitmap_db_door,
2377 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE + VYSIZE,
2378 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2379 door_state &= ~DOOR_COPY_BACK;
2382 new_door_state = MoveDoor(door_state);
2384 return(new_door_state);
2387 unsigned int CloseDoor(unsigned int door_state)
2389 unsigned int new_door_state;
2391 BlitBitmap(backbuffer, bitmap_db_door,
2392 DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2393 BlitBitmap(backbuffer, bitmap_db_door,
2394 VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
2396 new_door_state = MoveDoor(door_state);
2398 return(new_door_state);
2401 unsigned int GetDoorState()
2403 return MoveDoor(DOOR_GET_STATE);
2406 unsigned int SetDoorState(unsigned int door_state)
2408 return MoveDoor(door_state | DOOR_SET_STATE);
2411 unsigned int MoveDoor(unsigned int door_state)
2413 static int door1 = DOOR_OPEN_1;
2414 static int door2 = DOOR_CLOSE_2;
2415 static unsigned long door_delay = 0;
2416 int x, start, stepsize = door.step_offset;
2417 unsigned long door_delay_value = door.step_delay;
2419 if (door_state == DOOR_GET_STATE)
2420 return(door1 | door2);
2422 if (door_state & DOOR_SET_STATE)
2424 if (door_state & DOOR_ACTION_1)
2425 door1 = door_state & DOOR_ACTION_1;
2426 if (door_state & DOOR_ACTION_2)
2427 door2 = door_state & DOOR_ACTION_2;
2429 return(door1 | door2);
2432 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
2433 door_state &= ~DOOR_OPEN_1;
2434 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
2435 door_state &= ~DOOR_CLOSE_1;
2436 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
2437 door_state &= ~DOOR_OPEN_2;
2438 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
2439 door_state &= ~DOOR_CLOSE_2;
2441 if (setup.quick_doors)
2444 door_delay_value = 0;
2446 StopSound(SND_DOOR_OPENING);
2447 StopSound(SND_DOOR_CLOSING);
2450 if (global.autoplay_leveldir)
2452 door_state |= DOOR_NO_DELAY;
2453 door_state &= ~DOOR_CLOSE_ALL;
2456 if (door_state & DOOR_ACTION)
2458 if (!(door_state & DOOR_NO_DELAY))
2460 /* opening door sound has priority over simultaneously closing door */
2461 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
2462 PlaySoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
2463 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
2464 PlaySoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
2467 start = ((door_state & DOOR_NO_DELAY) ? DXSIZE : 0);
2469 for(x=start; x<=DXSIZE; x+=stepsize)
2471 Bitmap *bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
2472 GC gc = bitmap->stored_clip_gc;
2474 if (!(door_state & DOOR_NO_DELAY))
2475 WaitUntilDelayReached(&door_delay, door_delay_value);
2477 if (door_state & DOOR_ACTION_1)
2479 int i = (door_state & DOOR_OPEN_1 ? DXSIZE-x : x);
2480 int j = (DXSIZE - i) / 3;
2482 BlitBitmap(bitmap_db_door, drawto,
2483 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + i/2,
2484 DXSIZE,DYSIZE - i/2, DX, DY);
2486 ClearRectangle(drawto, DX, DY + DYSIZE - i/2, DXSIZE,i/2);
2488 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2489 BlitBitmapMasked(bitmap, drawto,
2490 DXSIZE, DOOR_GFX_PAGEY1, i, 77,
2491 DX + DXSIZE - i, DY + j);
2492 BlitBitmapMasked(bitmap, drawto,
2493 DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63,
2494 DX + DXSIZE - i, DY + 140 + j);
2495 SetClipOrigin(bitmap, gc, DX - DXSIZE + i, DY - (DOOR_GFX_PAGEY1 + j));
2496 BlitBitmapMasked(bitmap, drawto,
2497 DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j,
2499 BlitBitmapMasked(bitmap, drawto,
2500 DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63,
2503 BlitBitmapMasked(bitmap, drawto,
2504 DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
2506 BlitBitmapMasked(bitmap, drawto,
2507 DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
2509 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2510 BlitBitmapMasked(bitmap, drawto,
2511 DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
2512 DX + DXSIZE - i, DY + 77 + j);
2513 BlitBitmapMasked(bitmap, drawto,
2514 DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
2515 DX + DXSIZE - i, DY + 203 + j);
2517 redraw_mask |= REDRAW_DOOR_1;
2520 if (door_state & DOOR_ACTION_2)
2522 int i = (door_state & DOOR_OPEN_2 ? VXSIZE - x : x);
2523 int j = (VXSIZE - i) / 3;
2525 BlitBitmap(bitmap_db_door, drawto,
2526 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + i/2,
2527 VXSIZE, VYSIZE - i/2, VX, VY);
2529 ClearRectangle(drawto, VX, VY + VYSIZE-i/2, VXSIZE, i/2);
2531 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2532 BlitBitmapMasked(bitmap, drawto,
2533 VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2,
2534 VX + VXSIZE-i, VY+j);
2535 SetClipOrigin(bitmap, gc,
2536 VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
2537 BlitBitmapMasked(bitmap, drawto,
2538 VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j,
2541 BlitBitmapMasked(bitmap, drawto,
2542 VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2,
2543 i, VYSIZE / 2, VX, VY + VYSIZE / 2 - j);
2544 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2545 BlitBitmapMasked(bitmap, drawto,
2546 VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2,
2548 VX + VXSIZE - i, VY + VYSIZE / 2 + j);
2550 redraw_mask |= REDRAW_DOOR_2;
2555 if (game_status == GAME_MODE_MAIN)
2560 if (setup.quick_doors)
2562 StopSound(SND_DOOR_OPENING);
2563 StopSound(SND_DOOR_CLOSING);
2566 if (door_state & DOOR_ACTION_1)
2567 door1 = door_state & DOOR_ACTION_1;
2568 if (door_state & DOOR_ACTION_2)
2569 door2 = door_state & DOOR_ACTION_2;
2571 return (door1 | door2);
2574 void DrawSpecialEditorDoor()
2576 /* draw bigger toolbox window */
2577 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
2578 DOOR_GFX_PAGEX7, 0, EXSIZE + 8, 8,
2580 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
2581 EX - 4, VY - 4, EXSIZE + 8, EYSIZE - VYSIZE + 4,
2584 redraw_mask |= REDRAW_ALL;
2587 void UndrawSpecialEditorDoor()
2589 /* draw normal tape recorder window */
2590 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
2591 EX - 4, EY - 12, EXSIZE + 8, EYSIZE - VYSIZE + 12,
2594 redraw_mask |= REDRAW_ALL;
2598 /* ---------- new tool button stuff ---------------------------------------- */
2600 /* graphic position values for tool buttons */
2601 #define TOOL_BUTTON_YES_XPOS 2
2602 #define TOOL_BUTTON_YES_YPOS 250
2603 #define TOOL_BUTTON_YES_GFX_YPOS 0
2604 #define TOOL_BUTTON_YES_XSIZE 46
2605 #define TOOL_BUTTON_YES_YSIZE 28
2606 #define TOOL_BUTTON_NO_XPOS 52
2607 #define TOOL_BUTTON_NO_YPOS TOOL_BUTTON_YES_YPOS
2608 #define TOOL_BUTTON_NO_GFX_YPOS TOOL_BUTTON_YES_GFX_YPOS
2609 #define TOOL_BUTTON_NO_XSIZE TOOL_BUTTON_YES_XSIZE
2610 #define TOOL_BUTTON_NO_YSIZE TOOL_BUTTON_YES_YSIZE
2611 #define TOOL_BUTTON_CONFIRM_XPOS TOOL_BUTTON_YES_XPOS
2612 #define TOOL_BUTTON_CONFIRM_YPOS TOOL_BUTTON_YES_YPOS
2613 #define TOOL_BUTTON_CONFIRM_GFX_YPOS 30
2614 #define TOOL_BUTTON_CONFIRM_XSIZE 96
2615 #define TOOL_BUTTON_CONFIRM_YSIZE TOOL_BUTTON_YES_YSIZE
2616 #define TOOL_BUTTON_PLAYER_XSIZE 30
2617 #define TOOL_BUTTON_PLAYER_YSIZE 30
2618 #define TOOL_BUTTON_PLAYER_GFX_XPOS 5
2619 #define TOOL_BUTTON_PLAYER_GFX_YPOS 185
2620 #define TOOL_BUTTON_PLAYER_XPOS (5 + TOOL_BUTTON_PLAYER_XSIZE / 2)
2621 #define TOOL_BUTTON_PLAYER_YPOS (215 - TOOL_BUTTON_PLAYER_YSIZE / 2)
2622 #define TOOL_BUTTON_PLAYER1_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2623 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2624 #define TOOL_BUTTON_PLAYER2_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2625 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2626 #define TOOL_BUTTON_PLAYER3_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2627 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2628 #define TOOL_BUTTON_PLAYER4_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2629 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2630 #define TOOL_BUTTON_PLAYER1_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2631 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2632 #define TOOL_BUTTON_PLAYER2_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2633 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2634 #define TOOL_BUTTON_PLAYER3_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2635 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2636 #define TOOL_BUTTON_PLAYER4_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2637 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2646 } toolbutton_info[NUM_TOOL_BUTTONS] =
2649 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_GFX_YPOS,
2650 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_YPOS,
2651 TOOL_BUTTON_YES_XSIZE, TOOL_BUTTON_YES_YSIZE,
2656 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_GFX_YPOS,
2657 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_YPOS,
2658 TOOL_BUTTON_NO_XSIZE, TOOL_BUTTON_NO_YSIZE,
2663 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_GFX_YPOS,
2664 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_YPOS,
2665 TOOL_BUTTON_CONFIRM_XSIZE, TOOL_BUTTON_CONFIRM_YSIZE,
2666 TOOL_CTRL_ID_CONFIRM,
2670 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2671 TOOL_BUTTON_PLAYER1_XPOS, TOOL_BUTTON_PLAYER1_YPOS,
2672 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2673 TOOL_CTRL_ID_PLAYER_1,
2677 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2678 TOOL_BUTTON_PLAYER2_XPOS, TOOL_BUTTON_PLAYER2_YPOS,
2679 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2680 TOOL_CTRL_ID_PLAYER_2,
2684 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2685 TOOL_BUTTON_PLAYER3_XPOS, TOOL_BUTTON_PLAYER3_YPOS,
2686 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2687 TOOL_CTRL_ID_PLAYER_3,
2691 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2692 TOOL_BUTTON_PLAYER4_XPOS, TOOL_BUTTON_PLAYER4_YPOS,
2693 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2694 TOOL_CTRL_ID_PLAYER_4,
2699 void CreateToolButtons()
2703 for (i=0; i<NUM_TOOL_BUTTONS; i++)
2705 Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
2706 Bitmap *deco_bitmap = None;
2707 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
2708 struct GadgetInfo *gi;
2709 unsigned long event_mask;
2710 int gd_xoffset, gd_yoffset;
2711 int gd_x1, gd_x2, gd_y;
2714 event_mask = GD_EVENT_RELEASED;
2716 gd_xoffset = toolbutton_info[i].xpos;
2717 gd_yoffset = toolbutton_info[i].ypos;
2718 gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
2719 gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
2720 gd_y = DOOR_GFX_PAGEY1 + gd_yoffset;
2722 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
2724 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
2726 getMiniGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr),
2727 &deco_bitmap, &deco_x, &deco_y);
2728 deco_xpos = (toolbutton_info[i].width - MINI_TILEX) / 2;
2729 deco_ypos = (toolbutton_info[i].height - MINI_TILEY) / 2;
2732 gi = CreateGadget(GDI_CUSTOM_ID, id,
2733 GDI_INFO_TEXT, toolbutton_info[i].infotext,
2734 GDI_X, DX + toolbutton_info[i].x,
2735 GDI_Y, DY + toolbutton_info[i].y,
2736 GDI_WIDTH, toolbutton_info[i].width,
2737 GDI_HEIGHT, toolbutton_info[i].height,
2738 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
2739 GDI_STATE, GD_BUTTON_UNPRESSED,
2740 GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
2741 GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
2742 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
2743 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
2744 GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
2745 GDI_DECORATION_SHIFTING, 1, 1,
2746 GDI_EVENT_MASK, event_mask,
2747 GDI_CALLBACK_ACTION, HandleToolButtons,
2751 Error(ERR_EXIT, "cannot create gadget");
2753 tool_gadget[id] = gi;
2757 void FreeToolButtons()
2761 for (i=0; i<NUM_TOOL_BUTTONS; i++)
2762 FreeGadget(tool_gadget[i]);
2765 static void UnmapToolButtons()
2769 for (i=0; i<NUM_TOOL_BUTTONS; i++)
2770 UnmapGadget(tool_gadget[i]);
2773 static void HandleToolButtons(struct GadgetInfo *gi)
2775 request_gadget_id = gi->custom_id;
2778 int get_next_element(int element)
2782 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
2783 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
2784 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
2785 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
2786 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
2787 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
2788 case EL_AMOEBA_DROPPING: return EL_AMOEBA_WET;
2790 default: return element;
2794 int el_act_dir2img(int element, int action, int direction)
2796 element = GFX_ELEMENT(element);
2797 direction = MV_DIR_BIT(direction);
2799 return element_info[element].direction_graphic[action][direction];
2802 static int el_act_dir2crm(int element, int action, int direction)
2804 element = GFX_ELEMENT(element);
2805 direction = MV_DIR_BIT(direction);
2807 return element_info[element].direction_crumbled[action][direction];
2810 int el_act2img(int element, int action)
2812 element = GFX_ELEMENT(element);
2814 return element_info[element].graphic[action];
2817 int el_act2crm(int element, int action)
2819 element = GFX_ELEMENT(element);
2821 return element_info[element].crumbled[action];
2824 int el_dir2img(int element, int direction)
2826 element = GFX_ELEMENT(element);
2828 return el_act_dir2img(element, ACTION_DEFAULT, direction);
2831 int el2img(int element)
2833 element = GFX_ELEMENT(element);
2835 return element_info[element].graphic[ACTION_DEFAULT];
2838 int el2edimg(int element)
2840 element = GFX_ELEMENT(element);
2842 return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
2845 int el2preimg(int element)
2847 element = GFX_ELEMENT(element);
2849 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];