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);
691 GfxElement[jx][jy] = EL_UNDEFINED;
693 DrawLevelField(jx, jy);
697 /* ----------------------------------------------------------------------- */
698 /* draw player himself */
699 /* ----------------------------------------------------------------------- */
701 if (player->use_murphy_graphic)
703 static int last_horizontal_dir = MV_LEFT;
706 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
707 last_horizontal_dir = move_dir;
709 direction = (player->snapped ? move_dir : last_horizontal_dir);
711 graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, direction);
714 graphic = el_act_dir2img(player->element_nr, player->GfxAction, move_dir);
716 frame = getGraphicAnimationFrame(graphic, player->Frame);
720 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
721 sxx = player->GfxPos;
723 syy = player->GfxPos;
726 if (!setup.soft_scrolling && ScreenMovPos)
729 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
731 if (SHIELD_ON(player))
733 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
734 IMG_SHIELD_NORMAL_ACTIVE);
735 int frame = getGraphicAnimationFrame(graphic, -1);
737 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
740 /* ----------------------------------------------------------------------- */
741 /* draw things the player is pushing, if needed */
742 /* ----------------------------------------------------------------------- */
745 printf("::: %d, %d [%d, %d] [%d]\n",
746 player->Pushing, player_is_moving, player->GfxAction,
747 player->is_moving, player_is_moving);
751 if (player->Pushing && player->is_moving)
753 if (player->Pushing && player_is_moving)
756 int px = SCREENX(next_jx), py = SCREENY(next_jy);
758 if (Back[next_jx][next_jy])
759 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
762 if ((sxx || syy) && element == EL_SOKOBAN_OBJECT)
763 DrawGraphicShiftedThruMask(px, py, sxx, syy, IMG_SOKOBAN_OBJECT, 0,
767 (element == EL_SOKOBAN_FIELD_EMPTY ||
768 Feld[next_jx][next_jy] == EL_SOKOBAN_FIELD_FULL))
769 DrawGraphicShiftedThruMask(px, py, sxx, syy, IMG_SOKOBAN_OBJECT, 0,
775 int element = MovingOrBlocked2Element(next_jx, next_jy);
778 int element = Feld[jx][jy];
780 int element = Feld[next_jx][next_jy];
785 int graphic = el2img(element);
789 if ((sxx || syy) && IS_PUSHABLE(element))
792 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
793 frame = getGraphicAnimationFrame(graphic, player->Frame);
797 printf("::: pushing %d: %d ...\n", sxx, frame);
800 DrawGraphicShifted(px, py, sxx, syy, graphic, frame,
801 NO_CUTTING, NO_MASKING);
806 /* ----------------------------------------------------------------------- */
807 /* draw things in front of player (active dynamite or dynabombs) */
808 /* ----------------------------------------------------------------------- */
810 if (IS_ACTIVE_BOMB(element))
812 graphic = el2img(element);
813 frame = getGraphicAnimationFrame(graphic, GfxFrame[jx][jy]);
815 if (game.emulation == EMU_SUPAPLEX)
816 DrawGraphic(sx, sy, IMG_SP_DISK_RED, frame);
818 DrawGraphicThruMask(sx, sy, graphic, frame);
821 if (player_is_moving && last_element == EL_EXPLOSION)
824 int graphic = el_act2img(GfxElement[last_jx][last_jy], ACTION_EXPLODING);
826 int stored = Store[last_jx][last_jy];
827 int graphic = (game.emulation != EMU_SUPAPLEX ? IMG_EXPLOSION :
828 stored == EL_SP_INFOTRON ? IMG_SP_EXPLOSION_INFOTRON :
831 int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
832 int phase = ExplodePhase[last_jx][last_jy] - 1;
833 int frame = getGraphicAnimationFrame(graphic, phase - delay);
836 DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy), graphic, frame);
839 /* ----------------------------------------------------------------------- */
840 /* draw elements the player is just walking/passing through/under */
841 /* ----------------------------------------------------------------------- */
843 /* handle the field the player is leaving ... */
844 if (player_is_moving && IS_ACCESSIBLE_INSIDE(last_element))
845 DrawLevelField(last_jx, last_jy);
846 else if (player_is_moving && IS_ACCESSIBLE_UNDER(last_element))
847 DrawLevelFieldThruMask(last_jx, last_jy);
849 /* ... and the field the player is entering */
850 if (IS_ACCESSIBLE_INSIDE(element))
851 DrawLevelField(jx, jy);
852 else if (IS_ACCESSIBLE_UNDER(element))
853 DrawLevelFieldThruMask(jx, jy);
855 if (setup.direct_draw)
857 int dest_x = SX + SCREENX(MIN(jx, last_jx)) * TILEX;
858 int dest_y = SY + SCREENY(MIN(jy, last_jy)) * TILEY;
859 int x_size = TILEX * (1 + ABS(jx - last_jx));
860 int y_size = TILEY * (1 + ABS(jy - last_jy));
862 BlitBitmap(drawto_field, window,
863 dest_x, dest_y, x_size, y_size, dest_x, dest_y);
864 SetDrawtoField(DRAW_DIRECT);
867 MarkTileDirty(sx,sy);
870 void getGraphicSource(int graphic, int frame, Bitmap **bitmap, int *x, int *y)
872 struct GraphicInfo *g = &graphic_info[graphic];
876 if (g->offset_y == 0) /* frames are ordered horizontally */
878 int max_width = g->anim_frames_per_line * g->width;
880 *x = (g->src_x + frame * g->offset_x) % max_width;
881 *y = g->src_y + (g->src_x + frame * g->offset_x) / max_width * g->height;
883 else if (g->offset_x == 0) /* frames are ordered vertically */
885 int max_height = g->anim_frames_per_line * g->height;
887 *x = g->src_x + (g->src_y + frame * g->offset_y) / max_height * g->width;
888 *y = (g->src_y + frame * g->offset_y) % max_height;
890 else /* frames are ordered diagonally */
892 *x = g->src_x + frame * g->offset_x;
893 *y = g->src_y + frame * g->offset_y;
897 void DrawGraphic(int x, int y, int graphic, int frame)
900 if (!IN_SCR_FIELD(x, y))
902 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
903 printf("DrawGraphic(): This should never happen!\n");
908 DrawGraphicExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic, frame);
912 void DrawGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
918 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
919 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
922 void DrawGraphicThruMask(int x, int y, int graphic, int frame)
925 if (!IN_SCR_FIELD(x, y))
927 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
928 printf("DrawGraphicThruMask(): This should never happen!\n");
933 DrawGraphicThruMaskExt(drawto_field, FX + x * TILEX, FY + y *TILEY, graphic,
938 void DrawGraphicThruMaskExt(DrawBuffer *d, int dest_x, int dest_y, int graphic,
946 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
947 drawing_gc = src_bitmap->stored_clip_gc;
949 GC drawing_gc = src_bitmap->stored_clip_gc;
950 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
951 int src_x = graphic_info[graphic].src_x;
952 int src_y = graphic_info[graphic].src_y;
953 int offset_x = graphic_info[graphic].offset_x;
954 int offset_y = graphic_info[graphic].offset_y;
956 src_x += frame * offset_x;
957 src_y += frame * offset_y;
961 SetClipOrigin(src_bitmap, drawing_gc, dest_x - src_x, dest_y - src_y);
962 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX, TILEY, dest_x, dest_y);
965 void DrawMiniGraphic(int x, int y, int graphic)
967 DrawMiniGraphicExt(drawto, SX + x * MINI_TILEX,SY + y * MINI_TILEY, graphic);
968 MarkTileDirty(x / 2, y / 2);
971 void getMiniGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
973 struct GraphicInfo *g = &graphic_info[graphic];
975 int mini_starty = g->bitmap->height * 2 / 3;
978 *x = mini_startx + g->src_x / 2;
979 *y = mini_starty + g->src_y / 2;
982 void DrawMiniGraphicExt(DrawBuffer *d, int x, int y, int graphic)
987 getMiniGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
988 BlitBitmap(src_bitmap, d, src_x, src_y, MINI_TILEX, MINI_TILEY, x, y);
991 void DrawGraphicShifted(int x,int y, int dx,int dy, int graphic, int frame,
992 int cut_mode, int mask_mode)
997 int width = TILEX, height = TILEY;
1003 DrawGraphic(x, y, graphic, frame);
1007 if (dx || dy) /* shifted graphic */
1009 if (x < BX1) /* object enters playfield from the left */
1016 else if (x > BX2) /* object enters playfield from the right */
1022 else if (x==BX1 && dx < 0) /* object leaves playfield to the left */
1028 else if (x==BX2 && dx > 0) /* object leaves playfield to the right */
1030 else if (dx) /* general horizontal movement */
1031 MarkTileDirty(x + SIGN(dx), y);
1033 if (y < BY1) /* object enters playfield from the top */
1035 if (cut_mode==CUT_BELOW) /* object completely above top border */
1043 else if (y > BY2) /* object enters playfield from the bottom */
1049 else if (y==BY1 && dy < 0) /* object leaves playfield to the top */
1055 else if (dy > 0 && cut_mode == CUT_ABOVE)
1057 if (y == BY2) /* object completely above bottom border */
1063 MarkTileDirty(x, y + 1);
1064 } /* object leaves playfield to the bottom */
1065 else if (dy > 0 && (y == BY2 || cut_mode == CUT_BELOW))
1067 else if (dy) /* general vertical movement */
1068 MarkTileDirty(x, y + SIGN(dy));
1072 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1074 src_bitmap = graphic_info[graphic].bitmap;
1075 src_x = graphic_info[graphic].src_x;
1076 src_y = graphic_info[graphic].src_y;
1077 offset_x = graphic_info[graphic].offset_x;
1078 offset_y = graphic_info[graphic].offset_y;
1080 src_x += frame * offset_x;
1081 src_y += frame * offset_y;
1084 drawing_gc = src_bitmap->stored_clip_gc;
1089 dest_x = FX + x * TILEX + dx;
1090 dest_y = FY + y * TILEY + dy;
1093 if (!IN_SCR_FIELD(x,y))
1095 printf("DrawGraphicShifted(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
1096 printf("DrawGraphicShifted(): This should never happen!\n");
1101 if (mask_mode == USE_MASKING)
1103 SetClipOrigin(src_bitmap, drawing_gc, dest_x - src_x, dest_y - src_y);
1104 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1108 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1114 void DrawGraphicShiftedThruMask(int x, int y, int dx, int dy, int graphic,
1115 int frame, int cut_mode)
1117 DrawGraphicShifted(x,y, dx,dy, graphic, frame, cut_mode, USE_MASKING);
1120 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
1121 int cut_mode, int mask_mode)
1123 int lx = LEVELX(x), ly = LEVELY(y);
1127 if (IN_LEV_FIELD(lx, ly))
1129 SetRandomAnimationValue(lx, ly);
1131 graphic = el_act_dir2img(element, GfxAction[lx][ly], MovDir[lx][ly]);
1132 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1134 else /* border element */
1136 graphic = el2img(element);
1137 frame = getGraphicAnimationFrame(graphic, -1);
1140 if (element == EL_EXPANDABLE_WALL)
1142 boolean left_stopped = FALSE, right_stopped = FALSE;
1144 if (!IN_LEV_FIELD(lx - 1, ly) || IS_WALL(Feld[lx - 1][ly]))
1145 left_stopped = TRUE;
1146 if (!IN_LEV_FIELD(lx + 1, ly) || IS_WALL(Feld[lx + 1][ly]))
1147 right_stopped = TRUE;
1149 if (left_stopped && right_stopped)
1151 else if (left_stopped)
1153 graphic = IMG_EXPANDABLE_WALL_GROWING_RIGHT;
1154 frame = graphic_info[graphic].anim_frames - 1;
1156 else if (right_stopped)
1158 graphic = IMG_EXPANDABLE_WALL_GROWING_LEFT;
1159 frame = graphic_info[graphic].anim_frames - 1;
1164 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, mask_mode);
1165 else if (mask_mode == USE_MASKING)
1166 DrawGraphicThruMask(x, y, graphic, frame);
1168 DrawGraphic(x, y, graphic, frame);
1171 void DrawLevelElementExt(int x, int y, int dx, int dy, int element,
1172 int cut_mode, int mask_mode)
1174 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1175 DrawScreenElementExt(SCREENX(x), SCREENY(y), dx, dy, element,
1176 cut_mode, mask_mode);
1179 void DrawScreenElementShifted(int x, int y, int dx, int dy, int element,
1182 DrawScreenElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1185 void DrawLevelElementShifted(int x, int y, int dx, int dy, int element,
1188 DrawLevelElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1191 void DrawLevelElementThruMask(int x, int y, int element)
1193 DrawLevelElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1196 void DrawLevelFieldThruMask(int x, int y)
1198 DrawLevelElementExt(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
1201 static void DrawLevelFieldCrumbledSandExt(int x, int y, int graphic, int frame)
1205 int sx = SCREENX(x), sy = SCREENY(y);
1207 int width, height, cx, cy, i;
1209 int crumbled_border_size = graphic_info[graphic].border_size;
1211 int snip = TILEX / 8; /* number of border pixels from "crumbled graphic" */
1213 static int xy[4][2] =
1222 if (x == 0 && y == 7)
1223 printf("::: %d, %d [%d]\n", GfxElement[x][y], Feld[x][y],
1224 crumbled_border_size);
1227 if (!IN_LEV_FIELD(x, y))
1230 element = (GfxElement[x][y] != EL_UNDEFINED && Feld[x][y] != EL_EXPLOSION ?
1231 GfxElement[x][y] : Feld[x][y]);
1233 /* crumble field itself */
1234 if (CAN_BE_CRUMBLED(element) && !IS_MOVING(x, y))
1236 if (!IN_SCR_FIELD(sx, sy))
1239 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1243 int xx = x + xy[i][0];
1244 int yy = y + xy[i][1];
1246 element = (IN_LEV_FIELD(xx, yy) ? Feld[xx][yy] : BorderElement);
1248 /* check if neighbour field is of same type */
1249 if (CAN_BE_CRUMBLED(element) && !IS_MOVING(xx, yy))
1253 if (Feld[x][y] == EL_CUSTOM_START + 123)
1254 printf("::: crumble [%d] THE CHAOS ENGINE (%d, %d): %d, %d\n",
1255 i, Feld[x][y], element,
1256 CAN_BE_CRUMBLED(element), IS_MOVING(x, y));
1259 if (i == 1 || i == 2)
1261 width = crumbled_border_size;
1263 cx = (i == 2 ? TILEX - crumbled_border_size : 0);
1269 height = crumbled_border_size;
1271 cy = (i == 3 ? TILEY - crumbled_border_size : 0);
1274 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1275 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
1278 MarkTileDirty(sx, sy);
1280 else /* crumble neighbour fields */
1283 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1288 int xx = x + xy[i][0];
1289 int yy = y + xy[i][1];
1290 int sxx = sx + xy[i][0];
1291 int syy = sy + xy[i][1];
1293 if (!IN_LEV_FIELD(xx, yy) ||
1294 !IN_SCR_FIELD(sxx, syy) ||
1295 !CAN_BE_CRUMBLED(Feld[xx][yy]) ||
1300 graphic = el_act2crm(Feld[xx][yy], ACTION_DEFAULT);
1301 crumbled_border_size = graphic_info[graphic].border_size;
1303 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1306 if (i == 1 || i == 2)
1308 width = crumbled_border_size;
1310 cx = (i == 1 ? TILEX - crumbled_border_size : 0);
1316 height = crumbled_border_size;
1318 cy = (i == 0 ? TILEY - crumbled_border_size : 0);
1321 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1322 width, height, FX + sxx * TILEX + cx, FY + syy * TILEY + cy);
1324 MarkTileDirty(sxx, syy);
1329 void DrawLevelFieldCrumbledSand(int x, int y)
1334 if (!IN_LEV_FIELD(x, y))
1337 graphic = el_act2crm(Feld[x][y], ACTION_DEFAULT);
1339 DrawLevelFieldCrumbledSandExt(x, y, graphic, 0);
1341 DrawLevelFieldCrumbledSandExt(x, y, IMG_SAND_CRUMBLED, 0);
1345 void DrawLevelFieldCrumbledSandDigging(int x, int y, int direction,
1349 int graphic1 = el_act_dir2img(GfxElement[x][y], ACTION_DIGGING, direction);
1350 int graphic2 = el_act_dir2crm(GfxElement[x][y], ACTION_DIGGING, direction);
1352 int graphic1 = el_act_dir2img(EL_SAND, ACTION_DIGGING, direction);
1353 int graphic2 = el_act_dir2img(EL_SAND_CRUMBLED, ACTION_DIGGING, direction);
1355 int frame1 = getGraphicAnimationFrame(graphic1, step_frame);
1356 int frame2 = getGraphicAnimationFrame(graphic2, step_frame);
1357 int sx = SCREENX(x), sy = SCREENY(y);
1359 DrawGraphic(sx, sy, graphic1, frame1);
1360 DrawLevelFieldCrumbledSandExt(x, y, graphic2, frame2);
1363 void DrawLevelFieldCrumbledSandNeighbours(int x, int y)
1365 int sx = SCREENX(x), sy = SCREENY(y);
1366 static int xy[4][2] =
1377 int xx = x + xy[i][0];
1378 int yy = y + xy[i][1];
1379 int sxx = sx + xy[i][0];
1380 int syy = sy + xy[i][1];
1382 if (!IN_LEV_FIELD(xx, yy) ||
1383 !IN_SCR_FIELD(sxx, syy) ||
1384 !CAN_BE_CRUMBLED(Feld[xx][yy]) ||
1388 DrawLevelField(xx, yy);
1392 static int getBorderElement(int x, int y)
1396 { EL_STEELWALL_TOPLEFT, EL_INVISIBLE_STEELWALL_TOPLEFT },
1397 { EL_STEELWALL_TOPRIGHT, EL_INVISIBLE_STEELWALL_TOPRIGHT },
1398 { EL_STEELWALL_BOTTOMLEFT, EL_INVISIBLE_STEELWALL_BOTTOMLEFT },
1399 { EL_STEELWALL_BOTTOMRIGHT, EL_INVISIBLE_STEELWALL_BOTTOMRIGHT },
1400 { EL_STEELWALL_VERTICAL, EL_INVISIBLE_STEELWALL_VERTICAL },
1401 { EL_STEELWALL_HORIZONTAL, EL_INVISIBLE_STEELWALL_HORIZONTAL },
1402 { EL_STEELWALL, EL_INVISIBLE_STEELWALL }
1404 int steel_type = (BorderElement == EL_STEELWALL ? 0 : 1);
1405 int steel_position = (x == -1 && y == -1 ? 0 :
1406 x == lev_fieldx && y == -1 ? 1 :
1407 x == -1 && y == lev_fieldy ? 2 :
1408 x == lev_fieldx && y == lev_fieldy ? 3 :
1409 x == -1 || x == lev_fieldx ? 4 :
1410 y == -1 || y == lev_fieldy ? 5 : 6);
1412 return border[steel_position][steel_type];
1415 void DrawScreenElement(int x, int y, int element)
1417 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
1418 DrawLevelFieldCrumbledSand(LEVELX(x), LEVELY(y));
1421 void DrawLevelElement(int x, int y, int element)
1423 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1424 DrawScreenElement(SCREENX(x), SCREENY(y), element);
1427 void DrawScreenField(int x, int y)
1429 int lx = LEVELX(x), ly = LEVELY(y);
1430 int element, content;
1432 if (!IN_LEV_FIELD(lx, ly))
1434 if (lx < -1 || lx > lev_fieldx || ly < -1 || ly > lev_fieldy)
1437 element = getBorderElement(lx, ly);
1439 DrawScreenElement(x, y, element);
1443 element = Feld[lx][ly];
1444 content = Store[lx][ly];
1446 if (IS_MOVING(lx, ly))
1448 int horiz_move = (MovDir[lx][ly] == MV_LEFT || MovDir[lx][ly] == MV_RIGHT);
1449 boolean cut_mode = NO_CUTTING;
1451 if (element == EL_QUICKSAND_EMPTYING ||
1452 element == EL_MAGIC_WALL_EMPTYING ||
1453 element == EL_BD_MAGIC_WALL_EMPTYING ||
1454 element == EL_AMOEBA_DROPPING)
1455 cut_mode = CUT_ABOVE;
1456 else if (element == EL_QUICKSAND_FILLING ||
1457 element == EL_MAGIC_WALL_FILLING ||
1458 element == EL_BD_MAGIC_WALL_FILLING)
1459 cut_mode = CUT_BELOW;
1461 if (cut_mode == CUT_ABOVE)
1462 DrawScreenElementShifted(x, y, 0, 0, element, NO_CUTTING);
1464 DrawScreenElement(x, y, EL_EMPTY);
1467 DrawScreenElementShifted(x, y, MovPos[lx][ly], 0, element, NO_CUTTING);
1468 else if (cut_mode == NO_CUTTING)
1469 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], element, cut_mode);
1471 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], content, cut_mode);
1473 if (content == EL_ACID)
1474 DrawLevelElementThruMask(lx, ly + 1, EL_ACID);
1476 else if (IS_BLOCKED(lx, ly))
1481 boolean cut_mode = NO_CUTTING;
1482 int element_old, content_old;
1484 Blocked2Moving(lx, ly, &oldx, &oldy);
1487 horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
1488 MovDir[oldx][oldy] == MV_RIGHT);
1490 element_old = Feld[oldx][oldy];
1491 content_old = Store[oldx][oldy];
1493 if (element_old == EL_QUICKSAND_EMPTYING ||
1494 element_old == EL_MAGIC_WALL_EMPTYING ||
1495 element_old == EL_BD_MAGIC_WALL_EMPTYING ||
1496 element_old == EL_AMOEBA_DROPPING)
1497 cut_mode = CUT_ABOVE;
1499 DrawScreenElement(x, y, EL_EMPTY);
1502 DrawScreenElementShifted(sx, sy, MovPos[oldx][oldy], 0, element_old,
1504 else if (cut_mode == NO_CUTTING)
1505 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], element_old,
1508 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], content_old,
1511 else if (IS_DRAWABLE(element))
1512 DrawScreenElement(x, y, element);
1514 DrawScreenElement(x, y, EL_EMPTY);
1517 void DrawLevelField(int x, int y)
1519 if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1520 DrawScreenField(SCREENX(x), SCREENY(y));
1521 else if (IS_MOVING(x, y))
1525 Moving2Blocked(x, y, &newx, &newy);
1526 if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
1527 DrawScreenField(SCREENX(newx), SCREENY(newy));
1529 else if (IS_BLOCKED(x, y))
1533 Blocked2Moving(x, y, &oldx, &oldy);
1534 if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
1535 DrawScreenField(SCREENX(oldx), SCREENY(oldy));
1539 void DrawMiniElement(int x, int y, int element)
1543 graphic = el2edimg(element);
1544 DrawMiniGraphic(x, y, graphic);
1547 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
1549 int x = sx + scroll_x, y = sy + scroll_y;
1551 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
1552 DrawMiniElement(sx, sy, EL_EMPTY);
1553 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
1554 DrawMiniElement(sx, sy, Feld[x][y]);
1556 DrawMiniGraphic(sx, sy, el2edimg(getBorderElement(x, y)));
1560 void DrawEnvelopeBackground(int startx, int starty, int x, int y,
1561 int xsize, int ysize, int font_nr)
1563 int font_width = getFontWidth(font_nr);
1564 int font_height = getFontHeight(font_nr);
1565 int graphic = IMG_GAME_ENVELOPE_BACKGROUND;
1568 int dst_x = SX + startx + x * font_width;
1569 int dst_y = SY + starty + y * font_height;
1570 int width = graphic_info[graphic].width;
1571 int height = graphic_info[graphic].height;
1572 int inner_width = MAX(width - 2 * font_width, font_width);
1573 int inner_height = MAX(height - 2 * font_height, font_height);
1574 int inner_sx = (width >= 3 * font_width ? font_width : 0);
1575 int inner_sy = (height >= 3 * font_height ? font_height : 0);
1576 boolean draw_masked = graphic_info[graphic].draw_masked;
1578 getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
1580 if (src_bitmap == NULL || width < font_width || height < font_height)
1582 ClearRectangle(drawto, dst_x, dst_y, font_width, font_height);
1586 src_x += (x == 0 ? 0 : x == xsize - 1 ? width - font_width :
1587 inner_sx + (x - 1) * font_width % inner_width);
1588 src_y += (y == 0 ? 0 : y == ysize - 1 ? height - font_height :
1589 inner_sy + (y - 1) * font_height % inner_height);
1593 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1594 dst_x - src_x, dst_y - src_y);
1595 BlitBitmapMasked(src_bitmap, drawto, src_x, src_y, font_width, font_height,
1599 BlitBitmap(src_bitmap, drawto, src_x, src_y, font_width, font_height,
1605 void DrawEnvelopeBackground(int dst_x, int dst_y, int ex, int ey, int font_nr)
1607 int font_width = getFontWidth(font_nr);
1608 int font_height = getFontHeight(font_nr);
1609 int graphic = IMG_GAME_ENVELOPE_BACKGROUND;
1612 int width = graphic_info[graphic].width;
1613 int height = graphic_info[graphic].height;
1614 boolean draw_masked = graphic_info[graphic].draw_masked;
1616 getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
1618 if (src_bitmap == NULL)
1620 ClearRectangle(drawto, dst_x, dst_y, font_width, font_height);
1624 src_x += (ex == -1 ? 0 : ex == +1 ? width - font_width : font_width);
1625 src_y += (ey == -1 ? 0 : ey == +1 ? height - font_height : font_height);
1629 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1630 dst_x - src_x, dst_y - src_y);
1631 BlitBitmapMasked(src_bitmap, drawto, src_x, src_y, font_width, font_height,
1635 BlitBitmap(src_bitmap, drawto, src_x, src_y, font_width, font_height,
1642 int graphic = IMG_GAME_ENVELOPE_BACKGROUND;
1643 boolean draw_masked = graphic_info[graphic].draw_masked;
1644 int mask_mode = (draw_masked ? BLIT_MASKED : BLIT_ON_BACKGROUND);
1645 int font_nr = FONT_TEXT_1;
1646 int font_width = getFontWidth(font_nr);
1647 int font_height = getFontHeight(font_nr);
1648 boolean ffwd_delay = (tape.playing && tape.fast_forward);
1649 int anim_delay = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
1650 int wait_delay = (ffwd_delay ? 500 : 1000);
1653 /* open envelope window horizontally */
1654 for (i = 0; i <= level.envelope_xsize; i++)
1658 int startx = (SXSIZE - xsize * font_width) / 2;
1659 int starty = (SYSIZE - ysize * font_height) / 2;
1661 SetDrawtoField(DRAW_BUFFERED);
1663 BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
1665 SetDrawtoField(DRAW_BACKBUFFER);
1668 for (y=0; y < ysize; y++) for (x=0; x < xsize; x++)
1669 DrawEnvelopeBackground(startx, starty, x, y, xsize, ysize, font_nr);
1671 for (y=0; y < ysize; y++) for (x=0; x < xsize; x++)
1673 int sx = SX + startx + x * font_width;
1674 int sy = SY + starty + y * font_height;
1675 int ex = (x == 0 ? -1 : x == xsize - 1 ? +1 : 0);
1676 int ey = (y == 0 ? -1 : y == ysize - 1 ? +1 : 0);
1678 DrawEnvelopeBackground(sx, sy, ex, ey, font_nr);
1682 redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
1688 /* open envelope window vertically */
1689 for (i = 0; i <= level.envelope_ysize; i++)
1691 int xsize = level.envelope_xsize + 2;
1693 int startx = (SXSIZE - xsize * font_width) / 2;
1694 int starty = (SYSIZE - ysize * font_height) / 2;
1696 SetDrawtoField(DRAW_BUFFERED);
1698 BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
1700 SetDrawtoField(DRAW_BACKBUFFER);
1703 for (y=0; y < ysize; y++) for (x=0; x < xsize; x++)
1704 DrawEnvelopeBackground(startx, starty, x, y, xsize, ysize, font_nr);
1706 for (y=0; y < ysize; y++) for (x=0; x < xsize; x++)
1708 int sx = SX + startx + x * font_width;
1709 int sy = SY + starty + y * font_height;
1710 int ex = (x == 0 ? -1 : x == xsize - 1 ? +1 : 0);
1711 int ey = (y == 0 ? -1 : y == ysize - 1 ? +1 : 0);
1713 DrawEnvelopeBackground(sx, sy, ex, ey, font_nr);
1717 DrawTextToTextArea(SX + startx + font_width,
1718 SY + starty + font_height, level.envelope,
1719 FONT_TEXT_1, level.envelope_xsize, i, mask_mode);
1721 redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
1730 WaitForEventToContinue();
1732 /* close envelope window vertically */
1733 for (i = level.envelope_ysize; i >= 0; i--)
1735 int xsize = level.envelope_xsize + 2;
1737 int startx = (SXSIZE - xsize * font_width) / 2;
1738 int starty = (SYSIZE - ysize * font_height) / 2;
1740 SetDrawtoField(DRAW_BUFFERED);
1742 BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
1744 SetDrawtoField(DRAW_BACKBUFFER);
1747 for (y=0; y < ysize; y++) for (x=0; x < xsize; x++)
1748 DrawEnvelopeBackground(startx, starty, x, y, xsize, ysize, font_nr);
1750 for (y=0; y < ysize; y++) for (x=0; x < xsize; x++)
1752 int sx = SX + startx + x * font_width;
1753 int sy = SY + starty + y * font_height;
1754 int ex = (x == 0 ? -1 : x == xsize - 1 ? +1 : 0);
1755 int ey = (y == 0 ? -1 : y == ysize - 1 ? +1 : 0);
1757 DrawEnvelopeBackground(sx, sy, ex, ey, font_nr);
1761 DrawTextToTextArea(SX + startx + font_width,
1762 SY + starty + font_height, level.envelope,
1763 FONT_TEXT_1, level.envelope_xsize, i, mask_mode);
1765 redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
1771 /* close envelope window horizontally */
1772 for (i = level.envelope_xsize; i >= 0; i--)
1776 int startx = (SXSIZE - xsize * font_width) / 2;
1777 int starty = (SYSIZE - ysize * font_height) / 2;
1779 SetDrawtoField(DRAW_BUFFERED);
1781 BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
1783 SetDrawtoField(DRAW_BACKBUFFER);
1786 for (y=0; y < ysize; y++) for (x=0; x < xsize; x++)
1787 DrawEnvelopeBackground(startx, starty, x, y, xsize, ysize, font_nr);
1789 for (y=0; y < ysize; y++) for (x=0; x < xsize; x++)
1791 int sx = SX + startx + x * font_width;
1792 int sy = SY + starty + y * font_height;
1793 int ex = (x == 0 ? -1 : x == xsize - 1 ? +1 : 0);
1794 int ey = (y == 0 ? -1 : y == ysize - 1 ? +1 : 0);
1796 DrawEnvelopeBackground(sx, sy, ex, ey, font_nr);
1800 redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
1806 SetDrawtoField(DRAW_BUFFERED);
1808 redraw_mask |= REDRAW_FIELD;
1812 void getMicroGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
1814 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
1815 int mini_startx = src_bitmap->width * 3 / 4;
1816 int mini_starty = src_bitmap->height * 2 / 3;
1817 int src_x = mini_startx + graphic_info[graphic].src_x / 8;
1818 int src_y = mini_starty + graphic_info[graphic].src_y / 8;
1820 *bitmap = src_bitmap;
1825 void DrawMicroElement(int xpos, int ypos, int element)
1829 int graphic = el2preimg(element);
1831 getMicroGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
1832 BlitBitmap(src_bitmap, drawto, src_x, src_y, MICRO_TILEX, MICRO_TILEY,
1840 SetDrawBackgroundMask(REDRAW_NONE);
1843 for(x=BX1; x<=BX2; x++)
1844 for(y=BY1; y<=BY2; y++)
1845 DrawScreenField(x, y);
1847 redraw_mask |= REDRAW_FIELD;
1850 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
1854 for(x=0; x<size_x; x++)
1855 for(y=0; y<size_y; y++)
1856 DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
1858 redraw_mask |= REDRAW_FIELD;
1861 static void DrawMicroLevelExt(int xpos, int ypos, int from_x, int from_y)
1865 DrawBackground(xpos, ypos, MICROLEV_XSIZE, MICROLEV_YSIZE);
1867 if (lev_fieldx < STD_LEV_FIELDX)
1868 xpos += (STD_LEV_FIELDX - lev_fieldx) / 2 * MICRO_TILEX;
1869 if (lev_fieldy < STD_LEV_FIELDY)
1870 ypos += (STD_LEV_FIELDY - lev_fieldy) / 2 * MICRO_TILEY;
1872 xpos += MICRO_TILEX;
1873 ypos += MICRO_TILEY;
1875 for(x=-1; x<=STD_LEV_FIELDX; x++)
1877 for(y=-1; y<=STD_LEV_FIELDY; y++)
1879 int lx = from_x + x, ly = from_y + y;
1881 if (lx >= 0 && lx < lev_fieldx && ly >= 0 && ly < lev_fieldy)
1882 DrawMicroElement(xpos + x * MICRO_TILEX, ypos + y * MICRO_TILEY,
1883 level.field[lx][ly]);
1884 else if (lx >= -1 && lx < lev_fieldx+1 && ly >= -1 && ly < lev_fieldy+1
1885 && BorderElement != EL_EMPTY)
1886 DrawMicroElement(xpos + x * MICRO_TILEX, ypos + y * MICRO_TILEY,
1887 getBorderElement(lx, ly));
1891 redraw_mask |= REDRAW_MICROLEVEL;
1894 #define MICROLABEL_EMPTY 0
1895 #define MICROLABEL_LEVEL_NAME 1
1896 #define MICROLABEL_CREATED_BY 2
1897 #define MICROLABEL_LEVEL_AUTHOR 3
1898 #define MICROLABEL_IMPORTED_FROM 4
1899 #define MICROLABEL_LEVEL_IMPORT_INFO 5
1901 static void DrawMicroLevelLabelExt(int mode)
1903 char label_text[MAX_OUTPUT_LINESIZE + 1];
1904 int max_len_label_text;
1905 int font_nr = FONT_TEXT_2;
1907 if (mode == MICROLABEL_CREATED_BY || mode == MICROLABEL_IMPORTED_FROM)
1908 font_nr = FONT_TEXT_3;
1910 max_len_label_text = SXSIZE / getFontWidth(font_nr);
1912 DrawBackground(SX, MICROLABEL_YPOS, SXSIZE, getFontHeight(font_nr));
1914 strncpy(label_text, (mode == MICROLABEL_LEVEL_NAME ? level.name :
1915 mode == MICROLABEL_CREATED_BY ? "created by" :
1916 mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
1917 mode == MICROLABEL_IMPORTED_FROM ? "imported from" :
1918 mode == MICROLABEL_LEVEL_IMPORT_INFO ?
1919 leveldir_current->imported_from : ""),
1920 max_len_label_text);
1921 label_text[max_len_label_text] = '\0';
1923 if (strlen(label_text) > 0)
1925 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
1926 int lypos = MICROLABEL_YPOS;
1928 DrawText(lxpos, lypos, label_text, font_nr);
1931 redraw_mask |= REDRAW_MICROLEVEL;
1934 void DrawMicroLevel(int xpos, int ypos, boolean restart)
1936 static unsigned long scroll_delay = 0;
1937 static unsigned long label_delay = 0;
1938 static int from_x, from_y, scroll_direction;
1939 static int label_state, label_counter;
1940 int last_game_status = game_status; /* save current game status */
1942 /* force PREVIEW font on preview level */
1943 game_status = GAME_MODE_PSEUDO_PREVIEW;
1947 from_x = from_y = 0;
1948 scroll_direction = MV_RIGHT;
1952 DrawMicroLevelExt(xpos, ypos, from_x, from_y);
1953 DrawMicroLevelLabelExt(label_state);
1955 /* initialize delay counters */
1956 DelayReached(&scroll_delay, 0);
1957 DelayReached(&label_delay, 0);
1959 if (leveldir_current->name)
1961 int text_width = getTextWidth(leveldir_current->name, FONT_TEXT_1);
1962 int lxpos = SX + (SXSIZE - text_width) / 2;
1963 int lypos = SY + 352;
1965 DrawText(lxpos, lypos, leveldir_current->name, FONT_TEXT_1);
1968 game_status = last_game_status; /* restore current game status */
1973 /* scroll micro level, if needed */
1974 if ((lev_fieldx > STD_LEV_FIELDX || lev_fieldy > STD_LEV_FIELDY) &&
1975 DelayReached(&scroll_delay, MICROLEVEL_SCROLL_DELAY))
1977 switch (scroll_direction)
1983 scroll_direction = MV_UP;
1987 if (from_x < lev_fieldx - STD_LEV_FIELDX)
1990 scroll_direction = MV_DOWN;
1997 scroll_direction = MV_RIGHT;
2001 if (from_y < lev_fieldy - STD_LEV_FIELDY)
2004 scroll_direction = MV_LEFT;
2011 DrawMicroLevelExt(xpos, ypos, from_x, from_y);
2014 /* redraw micro level label, if needed */
2015 if (strcmp(level.name, NAMELESS_LEVEL_NAME) != 0 &&
2016 strcmp(level.author, ANONYMOUS_NAME) != 0 &&
2017 strcmp(level.author, leveldir_current->name) != 0 &&
2018 DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
2020 int max_label_counter = 23;
2022 if (leveldir_current->imported_from != NULL)
2023 max_label_counter += 14;
2025 label_counter = (label_counter + 1) % max_label_counter;
2026 label_state = (label_counter >= 0 && label_counter <= 7 ?
2027 MICROLABEL_LEVEL_NAME :
2028 label_counter >= 9 && label_counter <= 12 ?
2029 MICROLABEL_CREATED_BY :
2030 label_counter >= 14 && label_counter <= 21 ?
2031 MICROLABEL_LEVEL_AUTHOR :
2032 label_counter >= 23 && label_counter <= 26 ?
2033 MICROLABEL_IMPORTED_FROM :
2034 label_counter >= 28 && label_counter <= 35 ?
2035 MICROLABEL_LEVEL_IMPORT_INFO : MICROLABEL_EMPTY);
2036 DrawMicroLevelLabelExt(label_state);
2039 game_status = last_game_status; /* restore current game status */
2042 void WaitForEventToContinue()
2044 boolean still_wait = TRUE;
2046 /* simulate releasing mouse button over last gadget, if still pressed */
2048 HandleGadgets(-1, -1, 0);
2050 button_status = MB_RELEASED;
2062 case EVENT_BUTTONPRESS:
2063 case EVENT_KEYPRESS:
2067 case EVENT_KEYRELEASE:
2068 ClearPlayerAction();
2072 HandleOtherEvents(&event);
2076 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
2083 /* don't eat all CPU time */
2088 #define MAX_REQUEST_LINES 13
2089 #define MAX_REQUEST_LINE_LEN 7
2091 boolean Request(char *text, unsigned int req_state)
2093 int mx, my, ty, result = -1;
2094 unsigned int old_door_state;
2095 int last_game_status = game_status; /* save current game status */
2098 SetMouseCursor(CURSOR_DEFAULT);
2101 #if defined(PLATFORM_UNIX)
2102 /* pause network game while waiting for request to answer */
2103 if (options.network &&
2104 game_status == GAME_MODE_PLAYING &&
2105 req_state & REQUEST_WAIT_FOR)
2106 SendToServer_PausePlaying();
2109 old_door_state = GetDoorState();
2111 /* simulate releasing mouse button over last gadget, if still pressed */
2113 HandleGadgets(-1, -1, 0);
2117 CloseDoor(DOOR_CLOSE_1);
2119 /* save old door content */
2120 BlitBitmap(bitmap_db_door, bitmap_db_door,
2121 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
2122 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
2124 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
2126 /* clear door drawing field */
2127 DrawBackground(DX, DY, DXSIZE, DYSIZE);
2129 /* force DOOR font on preview level */
2130 game_status = GAME_MODE_PSEUDO_DOOR;
2132 /* write text for request */
2133 for(ty=0; ty < MAX_REQUEST_LINES; ty++)
2135 char text_line[MAX_REQUEST_LINE_LEN + 1];
2141 for(tl=0,tx=0; tx < MAX_REQUEST_LINE_LEN; tl++,tx++)
2144 if (!tc || tc == ' ')
2155 strncpy(text_line, text, tl);
2158 DrawText(DX + (DXSIZE - tl * getFontWidth(FONT_TEXT_2)) / 2,
2159 DY + 8 + ty * (getFontHeight(FONT_TEXT_2) + 2),
2160 text_line, FONT_TEXT_2);
2162 text += tl + (tc == ' ' ? 1 : 0);
2165 game_status = last_game_status; /* restore current game status */
2167 if (req_state & REQ_ASK)
2169 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
2170 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
2172 else if (req_state & REQ_CONFIRM)
2174 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
2176 else if (req_state & REQ_PLAYER)
2178 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
2179 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
2180 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
2181 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
2184 /* copy request gadgets to door backbuffer */
2185 BlitBitmap(drawto, bitmap_db_door,
2186 DX, DY, DXSIZE, DYSIZE,
2187 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2189 OpenDoor(DOOR_OPEN_1);
2195 if (!(req_state & REQUEST_WAIT_FOR))
2197 SetDrawBackgroundMask(REDRAW_FIELD);
2202 if (game_status != GAME_MODE_MAIN)
2205 button_status = MB_RELEASED;
2207 request_gadget_id = -1;
2209 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
2212 SetMouseCursor(CURSOR_DEFAULT);
2225 case EVENT_BUTTONPRESS:
2226 case EVENT_BUTTONRELEASE:
2227 case EVENT_MOTIONNOTIFY:
2229 if (event.type == EVENT_MOTIONNOTIFY)
2231 if (!PointerInWindow(window))
2232 continue; /* window and pointer are on different screens */
2237 motion_status = TRUE;
2238 mx = ((MotionEvent *) &event)->x;
2239 my = ((MotionEvent *) &event)->y;
2243 motion_status = FALSE;
2244 mx = ((ButtonEvent *) &event)->x;
2245 my = ((ButtonEvent *) &event)->y;
2246 if (event.type == EVENT_BUTTONPRESS)
2247 button_status = ((ButtonEvent *) &event)->button;
2249 button_status = MB_RELEASED;
2252 /* this sets 'request_gadget_id' */
2253 HandleGadgets(mx, my, button_status);
2255 switch(request_gadget_id)
2257 case TOOL_CTRL_ID_YES:
2260 case TOOL_CTRL_ID_NO:
2263 case TOOL_CTRL_ID_CONFIRM:
2264 result = TRUE | FALSE;
2267 case TOOL_CTRL_ID_PLAYER_1:
2270 case TOOL_CTRL_ID_PLAYER_2:
2273 case TOOL_CTRL_ID_PLAYER_3:
2276 case TOOL_CTRL_ID_PLAYER_4:
2287 case EVENT_KEYPRESS:
2288 switch(GetEventKey((KeyEvent *)&event, TRUE))
2301 if (req_state & REQ_PLAYER)
2305 case EVENT_KEYRELEASE:
2306 ClearPlayerAction();
2310 HandleOtherEvents(&event);
2314 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
2316 int joy = AnyJoystick();
2318 if (joy & JOY_BUTTON_1)
2320 else if (joy & JOY_BUTTON_2)
2326 /* don't eat all CPU time */
2330 if (game_status != GAME_MODE_MAIN)
2335 if (!(req_state & REQ_STAY_OPEN))
2337 CloseDoor(DOOR_CLOSE_1);
2339 if (!(req_state & REQ_STAY_CLOSED) && (old_door_state & DOOR_OPEN_1))
2341 BlitBitmap(bitmap_db_door, bitmap_db_door,
2342 DOOR_GFX_PAGEX2,DOOR_GFX_PAGEY1, DXSIZE,DYSIZE,
2343 DOOR_GFX_PAGEX1,DOOR_GFX_PAGEY1);
2344 OpenDoor(DOOR_OPEN_1);
2350 SetDrawBackgroundMask(REDRAW_FIELD);
2352 #if defined(PLATFORM_UNIX)
2353 /* continue network game after request */
2354 if (options.network &&
2355 game_status == GAME_MODE_PLAYING &&
2356 req_state & REQUEST_WAIT_FOR)
2357 SendToServer_ContinuePlaying();
2363 unsigned int OpenDoor(unsigned int door_state)
2365 unsigned int new_door_state;
2367 if (door_state & DOOR_COPY_BACK)
2369 BlitBitmap(bitmap_db_door, bitmap_db_door,
2370 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE + VYSIZE,
2371 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2372 door_state &= ~DOOR_COPY_BACK;
2375 new_door_state = MoveDoor(door_state);
2377 return(new_door_state);
2380 unsigned int CloseDoor(unsigned int door_state)
2382 unsigned int new_door_state;
2384 BlitBitmap(backbuffer, bitmap_db_door,
2385 DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2386 BlitBitmap(backbuffer, bitmap_db_door,
2387 VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
2389 new_door_state = MoveDoor(door_state);
2391 return(new_door_state);
2394 unsigned int GetDoorState()
2396 return MoveDoor(DOOR_GET_STATE);
2399 unsigned int SetDoorState(unsigned int door_state)
2401 return MoveDoor(door_state | DOOR_SET_STATE);
2404 unsigned int MoveDoor(unsigned int door_state)
2406 static int door1 = DOOR_OPEN_1;
2407 static int door2 = DOOR_CLOSE_2;
2408 static unsigned long door_delay = 0;
2409 int x, start, stepsize = door.step_offset;
2410 unsigned long door_delay_value = door.step_delay;
2412 if (door_state == DOOR_GET_STATE)
2413 return(door1 | door2);
2415 if (door_state & DOOR_SET_STATE)
2417 if (door_state & DOOR_ACTION_1)
2418 door1 = door_state & DOOR_ACTION_1;
2419 if (door_state & DOOR_ACTION_2)
2420 door2 = door_state & DOOR_ACTION_2;
2422 return(door1 | door2);
2425 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
2426 door_state &= ~DOOR_OPEN_1;
2427 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
2428 door_state &= ~DOOR_CLOSE_1;
2429 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
2430 door_state &= ~DOOR_OPEN_2;
2431 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
2432 door_state &= ~DOOR_CLOSE_2;
2434 if (setup.quick_doors)
2437 door_delay_value = 0;
2439 StopSound(SND_DOOR_OPENING);
2440 StopSound(SND_DOOR_CLOSING);
2443 if (global.autoplay_leveldir)
2445 door_state |= DOOR_NO_DELAY;
2446 door_state &= ~DOOR_CLOSE_ALL;
2449 if (door_state & DOOR_ACTION)
2451 if (!(door_state & DOOR_NO_DELAY))
2453 /* opening door sound has priority over simultaneously closing door */
2454 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
2455 PlaySoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
2456 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
2457 PlaySoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
2460 start = ((door_state & DOOR_NO_DELAY) ? DXSIZE : 0);
2462 for(x=start; x<=DXSIZE; x+=stepsize)
2464 Bitmap *bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
2465 GC gc = bitmap->stored_clip_gc;
2467 if (!(door_state & DOOR_NO_DELAY))
2468 WaitUntilDelayReached(&door_delay, door_delay_value);
2470 if (door_state & DOOR_ACTION_1)
2472 int i = (door_state & DOOR_OPEN_1 ? DXSIZE-x : x);
2473 int j = (DXSIZE - i) / 3;
2475 BlitBitmap(bitmap_db_door, drawto,
2476 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + i/2,
2477 DXSIZE,DYSIZE - i/2, DX, DY);
2479 ClearRectangle(drawto, DX, DY + DYSIZE - i/2, DXSIZE,i/2);
2481 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2482 BlitBitmapMasked(bitmap, drawto,
2483 DXSIZE, DOOR_GFX_PAGEY1, i, 77,
2484 DX + DXSIZE - i, DY + j);
2485 BlitBitmapMasked(bitmap, drawto,
2486 DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63,
2487 DX + DXSIZE - i, DY + 140 + j);
2488 SetClipOrigin(bitmap, gc, DX - DXSIZE + i, DY - (DOOR_GFX_PAGEY1 + j));
2489 BlitBitmapMasked(bitmap, drawto,
2490 DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j,
2492 BlitBitmapMasked(bitmap, drawto,
2493 DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63,
2496 BlitBitmapMasked(bitmap, drawto,
2497 DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
2499 BlitBitmapMasked(bitmap, drawto,
2500 DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
2502 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2503 BlitBitmapMasked(bitmap, drawto,
2504 DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
2505 DX + DXSIZE - i, DY + 77 + j);
2506 BlitBitmapMasked(bitmap, drawto,
2507 DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
2508 DX + DXSIZE - i, DY + 203 + j);
2510 redraw_mask |= REDRAW_DOOR_1;
2513 if (door_state & DOOR_ACTION_2)
2515 int i = (door_state & DOOR_OPEN_2 ? VXSIZE - x : x);
2516 int j = (VXSIZE - i) / 3;
2518 BlitBitmap(bitmap_db_door, drawto,
2519 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + i/2,
2520 VXSIZE, VYSIZE - i/2, VX, VY);
2522 ClearRectangle(drawto, VX, VY + VYSIZE-i/2, VXSIZE, i/2);
2524 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2525 BlitBitmapMasked(bitmap, drawto,
2526 VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2,
2527 VX + VXSIZE-i, VY+j);
2528 SetClipOrigin(bitmap, gc,
2529 VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
2530 BlitBitmapMasked(bitmap, drawto,
2531 VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j,
2534 BlitBitmapMasked(bitmap, drawto,
2535 VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2,
2536 i, VYSIZE / 2, VX, VY + VYSIZE / 2 - j);
2537 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2538 BlitBitmapMasked(bitmap, drawto,
2539 VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2,
2541 VX + VXSIZE - i, VY + VYSIZE / 2 + j);
2543 redraw_mask |= REDRAW_DOOR_2;
2548 if (game_status == GAME_MODE_MAIN)
2553 if (setup.quick_doors)
2555 StopSound(SND_DOOR_OPENING);
2556 StopSound(SND_DOOR_CLOSING);
2559 if (door_state & DOOR_ACTION_1)
2560 door1 = door_state & DOOR_ACTION_1;
2561 if (door_state & DOOR_ACTION_2)
2562 door2 = door_state & DOOR_ACTION_2;
2564 return (door1 | door2);
2567 void DrawSpecialEditorDoor()
2569 /* draw bigger toolbox window */
2570 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
2571 DOOR_GFX_PAGEX7, 0, EXSIZE + 8, 8,
2573 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
2574 EX - 4, VY - 4, EXSIZE + 8, EYSIZE - VYSIZE + 4,
2577 redraw_mask |= REDRAW_ALL;
2580 void UndrawSpecialEditorDoor()
2582 /* draw normal tape recorder window */
2583 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
2584 EX - 4, EY - 12, EXSIZE + 8, EYSIZE - VYSIZE + 12,
2587 redraw_mask |= REDRAW_ALL;
2591 /* ---------- new tool button stuff ---------------------------------------- */
2593 /* graphic position values for tool buttons */
2594 #define TOOL_BUTTON_YES_XPOS 2
2595 #define TOOL_BUTTON_YES_YPOS 250
2596 #define TOOL_BUTTON_YES_GFX_YPOS 0
2597 #define TOOL_BUTTON_YES_XSIZE 46
2598 #define TOOL_BUTTON_YES_YSIZE 28
2599 #define TOOL_BUTTON_NO_XPOS 52
2600 #define TOOL_BUTTON_NO_YPOS TOOL_BUTTON_YES_YPOS
2601 #define TOOL_BUTTON_NO_GFX_YPOS TOOL_BUTTON_YES_GFX_YPOS
2602 #define TOOL_BUTTON_NO_XSIZE TOOL_BUTTON_YES_XSIZE
2603 #define TOOL_BUTTON_NO_YSIZE TOOL_BUTTON_YES_YSIZE
2604 #define TOOL_BUTTON_CONFIRM_XPOS TOOL_BUTTON_YES_XPOS
2605 #define TOOL_BUTTON_CONFIRM_YPOS TOOL_BUTTON_YES_YPOS
2606 #define TOOL_BUTTON_CONFIRM_GFX_YPOS 30
2607 #define TOOL_BUTTON_CONFIRM_XSIZE 96
2608 #define TOOL_BUTTON_CONFIRM_YSIZE TOOL_BUTTON_YES_YSIZE
2609 #define TOOL_BUTTON_PLAYER_XSIZE 30
2610 #define TOOL_BUTTON_PLAYER_YSIZE 30
2611 #define TOOL_BUTTON_PLAYER_GFX_XPOS 5
2612 #define TOOL_BUTTON_PLAYER_GFX_YPOS 185
2613 #define TOOL_BUTTON_PLAYER_XPOS (5 + TOOL_BUTTON_PLAYER_XSIZE / 2)
2614 #define TOOL_BUTTON_PLAYER_YPOS (215 - TOOL_BUTTON_PLAYER_YSIZE / 2)
2615 #define TOOL_BUTTON_PLAYER1_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2616 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2617 #define TOOL_BUTTON_PLAYER2_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2618 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2619 #define TOOL_BUTTON_PLAYER3_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2620 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2621 #define TOOL_BUTTON_PLAYER4_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2622 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2623 #define TOOL_BUTTON_PLAYER1_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2624 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2625 #define TOOL_BUTTON_PLAYER2_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2626 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2627 #define TOOL_BUTTON_PLAYER3_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2628 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2629 #define TOOL_BUTTON_PLAYER4_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2630 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2639 } toolbutton_info[NUM_TOOL_BUTTONS] =
2642 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_GFX_YPOS,
2643 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_YPOS,
2644 TOOL_BUTTON_YES_XSIZE, TOOL_BUTTON_YES_YSIZE,
2649 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_GFX_YPOS,
2650 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_YPOS,
2651 TOOL_BUTTON_NO_XSIZE, TOOL_BUTTON_NO_YSIZE,
2656 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_GFX_YPOS,
2657 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_YPOS,
2658 TOOL_BUTTON_CONFIRM_XSIZE, TOOL_BUTTON_CONFIRM_YSIZE,
2659 TOOL_CTRL_ID_CONFIRM,
2663 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2664 TOOL_BUTTON_PLAYER1_XPOS, TOOL_BUTTON_PLAYER1_YPOS,
2665 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2666 TOOL_CTRL_ID_PLAYER_1,
2670 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2671 TOOL_BUTTON_PLAYER2_XPOS, TOOL_BUTTON_PLAYER2_YPOS,
2672 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2673 TOOL_CTRL_ID_PLAYER_2,
2677 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2678 TOOL_BUTTON_PLAYER3_XPOS, TOOL_BUTTON_PLAYER3_YPOS,
2679 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2680 TOOL_CTRL_ID_PLAYER_3,
2684 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2685 TOOL_BUTTON_PLAYER4_XPOS, TOOL_BUTTON_PLAYER4_YPOS,
2686 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2687 TOOL_CTRL_ID_PLAYER_4,
2692 void CreateToolButtons()
2696 for (i=0; i<NUM_TOOL_BUTTONS; i++)
2698 Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
2699 Bitmap *deco_bitmap = None;
2700 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
2701 struct GadgetInfo *gi;
2702 unsigned long event_mask;
2703 int gd_xoffset, gd_yoffset;
2704 int gd_x1, gd_x2, gd_y;
2707 event_mask = GD_EVENT_RELEASED;
2709 gd_xoffset = toolbutton_info[i].xpos;
2710 gd_yoffset = toolbutton_info[i].ypos;
2711 gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
2712 gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
2713 gd_y = DOOR_GFX_PAGEY1 + gd_yoffset;
2715 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
2717 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
2719 getMiniGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr),
2720 &deco_bitmap, &deco_x, &deco_y);
2721 deco_xpos = (toolbutton_info[i].width - MINI_TILEX) / 2;
2722 deco_ypos = (toolbutton_info[i].height - MINI_TILEY) / 2;
2725 gi = CreateGadget(GDI_CUSTOM_ID, id,
2726 GDI_INFO_TEXT, toolbutton_info[i].infotext,
2727 GDI_X, DX + toolbutton_info[i].x,
2728 GDI_Y, DY + toolbutton_info[i].y,
2729 GDI_WIDTH, toolbutton_info[i].width,
2730 GDI_HEIGHT, toolbutton_info[i].height,
2731 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
2732 GDI_STATE, GD_BUTTON_UNPRESSED,
2733 GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
2734 GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
2735 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
2736 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
2737 GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
2738 GDI_DECORATION_SHIFTING, 1, 1,
2739 GDI_EVENT_MASK, event_mask,
2740 GDI_CALLBACK_ACTION, HandleToolButtons,
2744 Error(ERR_EXIT, "cannot create gadget");
2746 tool_gadget[id] = gi;
2750 void FreeToolButtons()
2754 for (i=0; i<NUM_TOOL_BUTTONS; i++)
2755 FreeGadget(tool_gadget[i]);
2758 static void UnmapToolButtons()
2762 for (i=0; i<NUM_TOOL_BUTTONS; i++)
2763 UnmapGadget(tool_gadget[i]);
2766 static void HandleToolButtons(struct GadgetInfo *gi)
2768 request_gadget_id = gi->custom_id;
2771 int get_next_element(int element)
2775 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
2776 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
2777 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
2778 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
2779 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
2780 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
2781 case EL_AMOEBA_DROPPING: return EL_AMOEBA_WET;
2783 default: return element;
2787 int el_act_dir2img(int element, int action, int direction)
2789 element = GFX_ELEMENT(element);
2790 direction = MV_DIR_BIT(direction);
2792 return element_info[element].direction_graphic[action][direction];
2795 static int el_act_dir2crm(int element, int action, int direction)
2797 element = GFX_ELEMENT(element);
2798 direction = MV_DIR_BIT(direction);
2800 return element_info[element].direction_crumbled[action][direction];
2803 int el_act2img(int element, int action)
2805 element = GFX_ELEMENT(element);
2807 return element_info[element].graphic[action];
2810 int el_act2crm(int element, int action)
2812 element = GFX_ELEMENT(element);
2814 return element_info[element].crumbled[action];
2817 int el_dir2img(int element, int direction)
2819 element = GFX_ELEMENT(element);
2821 return el_act_dir2img(element, ACTION_DEFAULT, direction);
2824 int el2img(int element)
2826 element = GFX_ELEMENT(element);
2828 return element_info[element].graphic[ACTION_DEFAULT];
2831 int el2edimg(int element)
2833 element = GFX_ELEMENT(element);
2835 return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
2838 int el2preimg(int element)
2840 element = GFX_ELEMENT(element);
2842 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];