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);
1302 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1305 if (i == 1 || i == 2)
1307 width = crumbled_border_size;
1309 cx = (i == 1 ? TILEX - crumbled_border_size : 0);
1315 height = crumbled_border_size;
1317 cy = (i == 0 ? TILEY - crumbled_border_size : 0);
1320 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1321 width, height, FX + sxx * TILEX + cx, FY + syy * TILEY + cy);
1323 MarkTileDirty(sxx, syy);
1328 void DrawLevelFieldCrumbledSand(int x, int y)
1333 if (!IN_LEV_FIELD(x, y))
1336 graphic = el_act2crm(Feld[x][y], ACTION_DEFAULT);
1338 DrawLevelFieldCrumbledSandExt(x, y, graphic, 0);
1340 DrawLevelFieldCrumbledSandExt(x, y, IMG_SAND_CRUMBLED, 0);
1344 void DrawLevelFieldCrumbledSandDigging(int x, int y, int direction,
1348 int graphic1 = el_act_dir2img(GfxElement[x][y], ACTION_DIGGING, direction);
1349 int graphic2 = el_act_dir2crm(GfxElement[x][y], ACTION_DIGGING, direction);
1351 int graphic1 = el_act_dir2img(EL_SAND, ACTION_DIGGING, direction);
1352 int graphic2 = el_act_dir2img(EL_SAND_CRUMBLED, ACTION_DIGGING, direction);
1354 int frame1 = getGraphicAnimationFrame(graphic1, step_frame);
1355 int frame2 = getGraphicAnimationFrame(graphic2, step_frame);
1356 int sx = SCREENX(x), sy = SCREENY(y);
1358 DrawGraphic(sx, sy, graphic1, frame1);
1359 DrawLevelFieldCrumbledSandExt(x, y, graphic2, frame2);
1362 void DrawLevelFieldCrumbledSandNeighbours(int x, int y)
1364 int sx = SCREENX(x), sy = SCREENY(y);
1365 static int xy[4][2] =
1376 int xx = x + xy[i][0];
1377 int yy = y + xy[i][1];
1378 int sxx = sx + xy[i][0];
1379 int syy = sy + xy[i][1];
1381 if (!IN_LEV_FIELD(xx, yy) ||
1382 !IN_SCR_FIELD(sxx, syy) ||
1383 !CAN_BE_CRUMBLED(Feld[xx][yy]) ||
1387 DrawLevelField(xx, yy);
1391 static int getBorderElement(int x, int y)
1395 { EL_STEELWALL_TOPLEFT, EL_INVISIBLE_STEELWALL_TOPLEFT },
1396 { EL_STEELWALL_TOPRIGHT, EL_INVISIBLE_STEELWALL_TOPRIGHT },
1397 { EL_STEELWALL_BOTTOMLEFT, EL_INVISIBLE_STEELWALL_BOTTOMLEFT },
1398 { EL_STEELWALL_BOTTOMRIGHT, EL_INVISIBLE_STEELWALL_BOTTOMRIGHT },
1399 { EL_STEELWALL_VERTICAL, EL_INVISIBLE_STEELWALL_VERTICAL },
1400 { EL_STEELWALL_HORIZONTAL, EL_INVISIBLE_STEELWALL_HORIZONTAL },
1401 { EL_STEELWALL, EL_INVISIBLE_STEELWALL }
1403 int steel_type = (BorderElement == EL_STEELWALL ? 0 : 1);
1404 int steel_position = (x == -1 && y == -1 ? 0 :
1405 x == lev_fieldx && y == -1 ? 1 :
1406 x == -1 && y == lev_fieldy ? 2 :
1407 x == lev_fieldx && y == lev_fieldy ? 3 :
1408 x == -1 || x == lev_fieldx ? 4 :
1409 y == -1 || y == lev_fieldy ? 5 : 6);
1411 return border[steel_position][steel_type];
1414 void DrawScreenElement(int x, int y, int element)
1416 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
1417 DrawLevelFieldCrumbledSand(LEVELX(x), LEVELY(y));
1420 void DrawLevelElement(int x, int y, int element)
1422 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1423 DrawScreenElement(SCREENX(x), SCREENY(y), element);
1426 void DrawScreenField(int x, int y)
1428 int lx = LEVELX(x), ly = LEVELY(y);
1429 int element, content;
1431 if (!IN_LEV_FIELD(lx, ly))
1433 if (lx < -1 || lx > lev_fieldx || ly < -1 || ly > lev_fieldy)
1436 element = getBorderElement(lx, ly);
1438 DrawScreenElement(x, y, element);
1442 element = Feld[lx][ly];
1443 content = Store[lx][ly];
1445 if (IS_MOVING(lx, ly))
1447 int horiz_move = (MovDir[lx][ly] == MV_LEFT || MovDir[lx][ly] == MV_RIGHT);
1448 boolean cut_mode = NO_CUTTING;
1450 if (element == EL_QUICKSAND_EMPTYING ||
1451 element == EL_MAGIC_WALL_EMPTYING ||
1452 element == EL_BD_MAGIC_WALL_EMPTYING ||
1453 element == EL_AMOEBA_DROPPING)
1454 cut_mode = CUT_ABOVE;
1455 else if (element == EL_QUICKSAND_FILLING ||
1456 element == EL_MAGIC_WALL_FILLING ||
1457 element == EL_BD_MAGIC_WALL_FILLING)
1458 cut_mode = CUT_BELOW;
1460 if (cut_mode == CUT_ABOVE)
1461 DrawScreenElementShifted(x, y, 0, 0, element, NO_CUTTING);
1463 DrawScreenElement(x, y, EL_EMPTY);
1466 DrawScreenElementShifted(x, y, MovPos[lx][ly], 0, element, NO_CUTTING);
1467 else if (cut_mode == NO_CUTTING)
1468 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], element, cut_mode);
1470 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], content, cut_mode);
1472 if (content == EL_ACID)
1473 DrawLevelElementThruMask(lx, ly + 1, EL_ACID);
1475 else if (IS_BLOCKED(lx, ly))
1480 boolean cut_mode = NO_CUTTING;
1481 int element_old, content_old;
1483 Blocked2Moving(lx, ly, &oldx, &oldy);
1486 horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
1487 MovDir[oldx][oldy] == MV_RIGHT);
1489 element_old = Feld[oldx][oldy];
1490 content_old = Store[oldx][oldy];
1492 if (element_old == EL_QUICKSAND_EMPTYING ||
1493 element_old == EL_MAGIC_WALL_EMPTYING ||
1494 element_old == EL_BD_MAGIC_WALL_EMPTYING ||
1495 element_old == EL_AMOEBA_DROPPING)
1496 cut_mode = CUT_ABOVE;
1498 DrawScreenElement(x, y, EL_EMPTY);
1501 DrawScreenElementShifted(sx, sy, MovPos[oldx][oldy], 0, element_old,
1503 else if (cut_mode == NO_CUTTING)
1504 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], element_old,
1507 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], content_old,
1510 else if (IS_DRAWABLE(element))
1511 DrawScreenElement(x, y, element);
1513 DrawScreenElement(x, y, EL_EMPTY);
1516 void DrawLevelField(int x, int y)
1518 if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1519 DrawScreenField(SCREENX(x), SCREENY(y));
1520 else if (IS_MOVING(x, y))
1524 Moving2Blocked(x, y, &newx, &newy);
1525 if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
1526 DrawScreenField(SCREENX(newx), SCREENY(newy));
1528 else if (IS_BLOCKED(x, y))
1532 Blocked2Moving(x, y, &oldx, &oldy);
1533 if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
1534 DrawScreenField(SCREENX(oldx), SCREENY(oldy));
1538 void DrawMiniElement(int x, int y, int element)
1542 graphic = el2edimg(element);
1543 DrawMiniGraphic(x, y, graphic);
1546 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
1548 int x = sx + scroll_x, y = sy + scroll_y;
1550 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
1551 DrawMiniElement(sx, sy, EL_EMPTY);
1552 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
1553 DrawMiniElement(sx, sy, Feld[x][y]);
1555 DrawMiniGraphic(sx, sy, el2edimg(getBorderElement(x, y)));
1559 void DrawEnvelopeBackground(int startx, int starty, int x, int y,
1560 int xsize, int ysize, int font_nr)
1562 int font_width = getFontWidth(font_nr);
1563 int font_height = getFontHeight(font_nr);
1564 int graphic = IMG_GAME_ENVELOPE_BACKGROUND;
1567 int dst_x = SX + startx + x * font_width;
1568 int dst_y = SY + starty + y * font_height;
1569 int width = graphic_info[graphic].width;
1570 int height = graphic_info[graphic].height;
1571 int inner_width = MAX(width - 2 * font_width, font_width);
1572 int inner_height = MAX(height - 2 * font_height, font_height);
1573 int inner_sx = (width >= 3 * font_width ? font_width : 0);
1574 int inner_sy = (height >= 3 * font_height ? font_height : 0);
1575 boolean draw_masked = graphic_info[graphic].draw_masked;
1577 getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
1579 if (src_bitmap == NULL || width < font_width || height < font_height)
1581 ClearRectangle(drawto, dst_x, dst_y, font_width, font_height);
1585 src_x += (x == 0 ? 0 : x == xsize - 1 ? width - font_width :
1586 inner_sx + (x - 1) * font_width % inner_width);
1587 src_y += (y == 0 ? 0 : y == ysize - 1 ? height - font_height :
1588 inner_sy + (y - 1) * font_height % inner_height);
1592 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1593 dst_x - src_x, dst_y - src_y);
1594 BlitBitmapMasked(src_bitmap, drawto, src_x, src_y, font_width, font_height,
1598 BlitBitmap(src_bitmap, drawto, src_x, src_y, font_width, font_height,
1604 void DrawEnvelopeBackground(int dst_x, int dst_y, int ex, int ey, int font_nr)
1606 int font_width = getFontWidth(font_nr);
1607 int font_height = getFontHeight(font_nr);
1608 int graphic = IMG_GAME_ENVELOPE_BACKGROUND;
1611 int width = graphic_info[graphic].width;
1612 int height = graphic_info[graphic].height;
1613 boolean draw_masked = graphic_info[graphic].draw_masked;
1615 getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
1617 if (src_bitmap == NULL)
1619 ClearRectangle(drawto, dst_x, dst_y, font_width, font_height);
1623 src_x += (ex == -1 ? 0 : ex == +1 ? width - font_width : font_width);
1624 src_y += (ey == -1 ? 0 : ey == +1 ? height - font_height : font_height);
1628 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1629 dst_x - src_x, dst_y - src_y);
1630 BlitBitmapMasked(src_bitmap, drawto, src_x, src_y, font_width, font_height,
1634 BlitBitmap(src_bitmap, drawto, src_x, src_y, font_width, font_height,
1641 int graphic = IMG_GAME_ENVELOPE_BACKGROUND;
1642 boolean draw_masked = graphic_info[graphic].draw_masked;
1643 int mask_mode = (draw_masked ? BLIT_MASKED : BLIT_ON_BACKGROUND);
1644 int font_nr = FONT_TEXT_1;
1645 int font_width = getFontWidth(font_nr);
1646 int font_height = getFontHeight(font_nr);
1647 boolean ffwd_delay = (tape.playing && tape.fast_forward);
1648 int anim_delay = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
1649 int wait_delay = (ffwd_delay ? 500 : 1000);
1652 /* open envelope window horizontally */
1653 for (i = 0; i <= level.envelope_xsize; i++)
1657 int startx = (SXSIZE - xsize * font_width) / 2;
1658 int starty = (SYSIZE - ysize * font_height) / 2;
1660 SetDrawtoField(DRAW_BUFFERED);
1662 BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
1664 SetDrawtoField(DRAW_BACKBUFFER);
1667 for (y=0; y < ysize; y++) for (x=0; x < xsize; x++)
1668 DrawEnvelopeBackground(startx, starty, x, y, xsize, ysize, font_nr);
1670 for (y=0; y < ysize; y++) for (x=0; x < xsize; x++)
1672 int sx = SX + startx + x * font_width;
1673 int sy = SY + starty + y * font_height;
1674 int ex = (x == 0 ? -1 : x == xsize - 1 ? +1 : 0);
1675 int ey = (y == 0 ? -1 : y == ysize - 1 ? +1 : 0);
1677 DrawEnvelopeBackground(sx, sy, ex, ey, font_nr);
1681 redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
1687 /* open envelope window vertically */
1688 for (i = 0; i <= level.envelope_ysize; i++)
1690 int xsize = level.envelope_xsize + 2;
1692 int startx = (SXSIZE - xsize * font_width) / 2;
1693 int starty = (SYSIZE - ysize * font_height) / 2;
1695 SetDrawtoField(DRAW_BUFFERED);
1697 BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
1699 SetDrawtoField(DRAW_BACKBUFFER);
1702 for (y=0; y < ysize; y++) for (x=0; x < xsize; x++)
1703 DrawEnvelopeBackground(startx, starty, x, y, xsize, ysize, font_nr);
1705 for (y=0; y < ysize; y++) for (x=0; x < xsize; x++)
1707 int sx = SX + startx + x * font_width;
1708 int sy = SY + starty + y * font_height;
1709 int ex = (x == 0 ? -1 : x == xsize - 1 ? +1 : 0);
1710 int ey = (y == 0 ? -1 : y == ysize - 1 ? +1 : 0);
1712 DrawEnvelopeBackground(sx, sy, ex, ey, font_nr);
1716 DrawTextToTextArea(SX + startx + font_width,
1717 SY + starty + font_height, level.envelope,
1718 FONT_TEXT_1, level.envelope_xsize, i, mask_mode);
1720 redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
1729 WaitForEventToContinue();
1731 /* close envelope window vertically */
1732 for (i = level.envelope_ysize; i >= 0; i--)
1734 int xsize = level.envelope_xsize + 2;
1736 int startx = (SXSIZE - xsize * font_width) / 2;
1737 int starty = (SYSIZE - ysize * font_height) / 2;
1739 SetDrawtoField(DRAW_BUFFERED);
1741 BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
1743 SetDrawtoField(DRAW_BACKBUFFER);
1746 for (y=0; y < ysize; y++) for (x=0; x < xsize; x++)
1747 DrawEnvelopeBackground(startx, starty, x, y, xsize, ysize, font_nr);
1749 for (y=0; y < ysize; y++) for (x=0; x < xsize; x++)
1751 int sx = SX + startx + x * font_width;
1752 int sy = SY + starty + y * font_height;
1753 int ex = (x == 0 ? -1 : x == xsize - 1 ? +1 : 0);
1754 int ey = (y == 0 ? -1 : y == ysize - 1 ? +1 : 0);
1756 DrawEnvelopeBackground(sx, sy, ex, ey, font_nr);
1760 DrawTextToTextArea(SX + startx + font_width,
1761 SY + starty + font_height, level.envelope,
1762 FONT_TEXT_1, level.envelope_xsize, i, mask_mode);
1764 redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
1770 /* close envelope window horizontally */
1771 for (i = level.envelope_xsize; i >= 0; i--)
1775 int startx = (SXSIZE - xsize * font_width) / 2;
1776 int starty = (SYSIZE - ysize * font_height) / 2;
1778 SetDrawtoField(DRAW_BUFFERED);
1780 BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
1782 SetDrawtoField(DRAW_BACKBUFFER);
1785 for (y=0; y < ysize; y++) for (x=0; x < xsize; x++)
1786 DrawEnvelopeBackground(startx, starty, x, y, xsize, ysize, font_nr);
1788 for (y=0; y < ysize; y++) for (x=0; x < xsize; x++)
1790 int sx = SX + startx + x * font_width;
1791 int sy = SY + starty + y * font_height;
1792 int ex = (x == 0 ? -1 : x == xsize - 1 ? +1 : 0);
1793 int ey = (y == 0 ? -1 : y == ysize - 1 ? +1 : 0);
1795 DrawEnvelopeBackground(sx, sy, ex, ey, font_nr);
1799 redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
1805 SetDrawtoField(DRAW_BUFFERED);
1807 redraw_mask |= REDRAW_FIELD;
1811 void getMicroGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
1813 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
1814 int mini_startx = src_bitmap->width * 3 / 4;
1815 int mini_starty = src_bitmap->height * 2 / 3;
1816 int src_x = mini_startx + graphic_info[graphic].src_x / 8;
1817 int src_y = mini_starty + graphic_info[graphic].src_y / 8;
1819 *bitmap = src_bitmap;
1824 void DrawMicroElement(int xpos, int ypos, int element)
1828 int graphic = el2preimg(element);
1830 getMicroGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
1831 BlitBitmap(src_bitmap, drawto, src_x, src_y, MICRO_TILEX, MICRO_TILEY,
1839 SetDrawBackgroundMask(REDRAW_NONE);
1842 for(x=BX1; x<=BX2; x++)
1843 for(y=BY1; y<=BY2; y++)
1844 DrawScreenField(x, y);
1846 redraw_mask |= REDRAW_FIELD;
1849 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
1853 for(x=0; x<size_x; x++)
1854 for(y=0; y<size_y; y++)
1855 DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
1857 redraw_mask |= REDRAW_FIELD;
1860 static void DrawMicroLevelExt(int xpos, int ypos, int from_x, int from_y)
1864 DrawBackground(xpos, ypos, MICROLEV_XSIZE, MICROLEV_YSIZE);
1866 if (lev_fieldx < STD_LEV_FIELDX)
1867 xpos += (STD_LEV_FIELDX - lev_fieldx) / 2 * MICRO_TILEX;
1868 if (lev_fieldy < STD_LEV_FIELDY)
1869 ypos += (STD_LEV_FIELDY - lev_fieldy) / 2 * MICRO_TILEY;
1871 xpos += MICRO_TILEX;
1872 ypos += MICRO_TILEY;
1874 for(x=-1; x<=STD_LEV_FIELDX; x++)
1876 for(y=-1; y<=STD_LEV_FIELDY; y++)
1878 int lx = from_x + x, ly = from_y + y;
1880 if (lx >= 0 && lx < lev_fieldx && ly >= 0 && ly < lev_fieldy)
1881 DrawMicroElement(xpos + x * MICRO_TILEX, ypos + y * MICRO_TILEY,
1882 level.field[lx][ly]);
1883 else if (lx >= -1 && lx < lev_fieldx+1 && ly >= -1 && ly < lev_fieldy+1
1884 && BorderElement != EL_EMPTY)
1885 DrawMicroElement(xpos + x * MICRO_TILEX, ypos + y * MICRO_TILEY,
1886 getBorderElement(lx, ly));
1890 redraw_mask |= REDRAW_MICROLEVEL;
1893 #define MICROLABEL_EMPTY 0
1894 #define MICROLABEL_LEVEL_NAME 1
1895 #define MICROLABEL_CREATED_BY 2
1896 #define MICROLABEL_LEVEL_AUTHOR 3
1897 #define MICROLABEL_IMPORTED_FROM 4
1898 #define MICROLABEL_LEVEL_IMPORT_INFO 5
1900 static void DrawMicroLevelLabelExt(int mode)
1902 char label_text[MAX_OUTPUT_LINESIZE + 1];
1903 int max_len_label_text;
1904 int font_nr = FONT_TEXT_2;
1906 if (mode == MICROLABEL_CREATED_BY || mode == MICROLABEL_IMPORTED_FROM)
1907 font_nr = FONT_TEXT_3;
1909 max_len_label_text = SXSIZE / getFontWidth(font_nr);
1911 DrawBackground(SX, MICROLABEL_YPOS, SXSIZE, getFontHeight(font_nr));
1913 strncpy(label_text, (mode == MICROLABEL_LEVEL_NAME ? level.name :
1914 mode == MICROLABEL_CREATED_BY ? "created by" :
1915 mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
1916 mode == MICROLABEL_IMPORTED_FROM ? "imported from" :
1917 mode == MICROLABEL_LEVEL_IMPORT_INFO ?
1918 leveldir_current->imported_from : ""),
1919 max_len_label_text);
1920 label_text[max_len_label_text] = '\0';
1922 if (strlen(label_text) > 0)
1924 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
1925 int lypos = MICROLABEL_YPOS;
1927 DrawText(lxpos, lypos, label_text, font_nr);
1930 redraw_mask |= REDRAW_MICROLEVEL;
1933 void DrawMicroLevel(int xpos, int ypos, boolean restart)
1935 static unsigned long scroll_delay = 0;
1936 static unsigned long label_delay = 0;
1937 static int from_x, from_y, scroll_direction;
1938 static int label_state, label_counter;
1939 int last_game_status = game_status; /* save current game status */
1941 /* force PREVIEW font on preview level */
1942 game_status = GAME_MODE_PSEUDO_PREVIEW;
1946 from_x = from_y = 0;
1947 scroll_direction = MV_RIGHT;
1951 DrawMicroLevelExt(xpos, ypos, from_x, from_y);
1952 DrawMicroLevelLabelExt(label_state);
1954 /* initialize delay counters */
1955 DelayReached(&scroll_delay, 0);
1956 DelayReached(&label_delay, 0);
1958 if (leveldir_current->name)
1960 int text_width = getTextWidth(leveldir_current->name, FONT_TEXT_1);
1961 int lxpos = SX + (SXSIZE - text_width) / 2;
1962 int lypos = SY + 352;
1964 DrawText(lxpos, lypos, leveldir_current->name, FONT_TEXT_1);
1967 game_status = last_game_status; /* restore current game status */
1972 /* scroll micro level, if needed */
1973 if ((lev_fieldx > STD_LEV_FIELDX || lev_fieldy > STD_LEV_FIELDY) &&
1974 DelayReached(&scroll_delay, MICROLEVEL_SCROLL_DELAY))
1976 switch (scroll_direction)
1982 scroll_direction = MV_UP;
1986 if (from_x < lev_fieldx - STD_LEV_FIELDX)
1989 scroll_direction = MV_DOWN;
1996 scroll_direction = MV_RIGHT;
2000 if (from_y < lev_fieldy - STD_LEV_FIELDY)
2003 scroll_direction = MV_LEFT;
2010 DrawMicroLevelExt(xpos, ypos, from_x, from_y);
2013 /* redraw micro level label, if needed */
2014 if (strcmp(level.name, NAMELESS_LEVEL_NAME) != 0 &&
2015 strcmp(level.author, ANONYMOUS_NAME) != 0 &&
2016 strcmp(level.author, leveldir_current->name) != 0 &&
2017 DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
2019 int max_label_counter = 23;
2021 if (leveldir_current->imported_from != NULL)
2022 max_label_counter += 14;
2024 label_counter = (label_counter + 1) % max_label_counter;
2025 label_state = (label_counter >= 0 && label_counter <= 7 ?
2026 MICROLABEL_LEVEL_NAME :
2027 label_counter >= 9 && label_counter <= 12 ?
2028 MICROLABEL_CREATED_BY :
2029 label_counter >= 14 && label_counter <= 21 ?
2030 MICROLABEL_LEVEL_AUTHOR :
2031 label_counter >= 23 && label_counter <= 26 ?
2032 MICROLABEL_IMPORTED_FROM :
2033 label_counter >= 28 && label_counter <= 35 ?
2034 MICROLABEL_LEVEL_IMPORT_INFO : MICROLABEL_EMPTY);
2035 DrawMicroLevelLabelExt(label_state);
2038 game_status = last_game_status; /* restore current game status */
2041 void WaitForEventToContinue()
2043 boolean still_wait = TRUE;
2045 /* simulate releasing mouse button over last gadget, if still pressed */
2047 HandleGadgets(-1, -1, 0);
2049 button_status = MB_RELEASED;
2061 case EVENT_BUTTONPRESS:
2062 case EVENT_KEYPRESS:
2066 case EVENT_KEYRELEASE:
2067 ClearPlayerAction();
2071 HandleOtherEvents(&event);
2075 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
2082 /* don't eat all CPU time */
2087 #define MAX_REQUEST_LINES 13
2088 #define MAX_REQUEST_LINE_LEN 7
2090 boolean Request(char *text, unsigned int req_state)
2092 int mx, my, ty, result = -1;
2093 unsigned int old_door_state;
2094 int last_game_status = game_status; /* save current game status */
2097 SetMouseCursor(CURSOR_DEFAULT);
2100 #if defined(PLATFORM_UNIX)
2101 /* pause network game while waiting for request to answer */
2102 if (options.network &&
2103 game_status == GAME_MODE_PLAYING &&
2104 req_state & REQUEST_WAIT_FOR)
2105 SendToServer_PausePlaying();
2108 old_door_state = GetDoorState();
2110 /* simulate releasing mouse button over last gadget, if still pressed */
2112 HandleGadgets(-1, -1, 0);
2116 CloseDoor(DOOR_CLOSE_1);
2118 /* save old door content */
2119 BlitBitmap(bitmap_db_door, bitmap_db_door,
2120 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
2121 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
2123 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
2125 /* clear door drawing field */
2126 DrawBackground(DX, DY, DXSIZE, DYSIZE);
2128 /* force DOOR font on preview level */
2129 game_status = GAME_MODE_PSEUDO_DOOR;
2131 /* write text for request */
2132 for(ty=0; ty < MAX_REQUEST_LINES; ty++)
2134 char text_line[MAX_REQUEST_LINE_LEN + 1];
2140 for(tl=0,tx=0; tx < MAX_REQUEST_LINE_LEN; tl++,tx++)
2143 if (!tc || tc == ' ')
2154 strncpy(text_line, text, tl);
2157 DrawText(DX + (DXSIZE - tl * getFontWidth(FONT_TEXT_2)) / 2,
2158 DY + 8 + ty * (getFontHeight(FONT_TEXT_2) + 2),
2159 text_line, FONT_TEXT_2);
2161 text += tl + (tc == ' ' ? 1 : 0);
2164 game_status = last_game_status; /* restore current game status */
2166 if (req_state & REQ_ASK)
2168 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
2169 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
2171 else if (req_state & REQ_CONFIRM)
2173 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
2175 else if (req_state & REQ_PLAYER)
2177 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
2178 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
2179 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
2180 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
2183 /* copy request gadgets to door backbuffer */
2184 BlitBitmap(drawto, bitmap_db_door,
2185 DX, DY, DXSIZE, DYSIZE,
2186 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2188 OpenDoor(DOOR_OPEN_1);
2194 if (!(req_state & REQUEST_WAIT_FOR))
2196 SetDrawBackgroundMask(REDRAW_FIELD);
2201 if (game_status != GAME_MODE_MAIN)
2204 button_status = MB_RELEASED;
2206 request_gadget_id = -1;
2208 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
2211 SetMouseCursor(CURSOR_DEFAULT);
2224 case EVENT_BUTTONPRESS:
2225 case EVENT_BUTTONRELEASE:
2226 case EVENT_MOTIONNOTIFY:
2228 if (event.type == EVENT_MOTIONNOTIFY)
2230 if (!PointerInWindow(window))
2231 continue; /* window and pointer are on different screens */
2236 motion_status = TRUE;
2237 mx = ((MotionEvent *) &event)->x;
2238 my = ((MotionEvent *) &event)->y;
2242 motion_status = FALSE;
2243 mx = ((ButtonEvent *) &event)->x;
2244 my = ((ButtonEvent *) &event)->y;
2245 if (event.type == EVENT_BUTTONPRESS)
2246 button_status = ((ButtonEvent *) &event)->button;
2248 button_status = MB_RELEASED;
2251 /* this sets 'request_gadget_id' */
2252 HandleGadgets(mx, my, button_status);
2254 switch(request_gadget_id)
2256 case TOOL_CTRL_ID_YES:
2259 case TOOL_CTRL_ID_NO:
2262 case TOOL_CTRL_ID_CONFIRM:
2263 result = TRUE | FALSE;
2266 case TOOL_CTRL_ID_PLAYER_1:
2269 case TOOL_CTRL_ID_PLAYER_2:
2272 case TOOL_CTRL_ID_PLAYER_3:
2275 case TOOL_CTRL_ID_PLAYER_4:
2286 case EVENT_KEYPRESS:
2287 switch(GetEventKey((KeyEvent *)&event, TRUE))
2300 if (req_state & REQ_PLAYER)
2304 case EVENT_KEYRELEASE:
2305 ClearPlayerAction();
2309 HandleOtherEvents(&event);
2313 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
2315 int joy = AnyJoystick();
2317 if (joy & JOY_BUTTON_1)
2319 else if (joy & JOY_BUTTON_2)
2325 /* don't eat all CPU time */
2329 if (game_status != GAME_MODE_MAIN)
2334 if (!(req_state & REQ_STAY_OPEN))
2336 CloseDoor(DOOR_CLOSE_1);
2338 if (!(req_state & REQ_STAY_CLOSED) && (old_door_state & DOOR_OPEN_1))
2340 BlitBitmap(bitmap_db_door, bitmap_db_door,
2341 DOOR_GFX_PAGEX2,DOOR_GFX_PAGEY1, DXSIZE,DYSIZE,
2342 DOOR_GFX_PAGEX1,DOOR_GFX_PAGEY1);
2343 OpenDoor(DOOR_OPEN_1);
2349 SetDrawBackgroundMask(REDRAW_FIELD);
2351 #if defined(PLATFORM_UNIX)
2352 /* continue network game after request */
2353 if (options.network &&
2354 game_status == GAME_MODE_PLAYING &&
2355 req_state & REQUEST_WAIT_FOR)
2356 SendToServer_ContinuePlaying();
2362 unsigned int OpenDoor(unsigned int door_state)
2364 unsigned int new_door_state;
2366 if (door_state & DOOR_COPY_BACK)
2368 BlitBitmap(bitmap_db_door, bitmap_db_door,
2369 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE + VYSIZE,
2370 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2371 door_state &= ~DOOR_COPY_BACK;
2374 new_door_state = MoveDoor(door_state);
2376 return(new_door_state);
2379 unsigned int CloseDoor(unsigned int door_state)
2381 unsigned int new_door_state;
2383 BlitBitmap(backbuffer, bitmap_db_door,
2384 DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2385 BlitBitmap(backbuffer, bitmap_db_door,
2386 VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
2388 new_door_state = MoveDoor(door_state);
2390 return(new_door_state);
2393 unsigned int GetDoorState()
2395 return MoveDoor(DOOR_GET_STATE);
2398 unsigned int SetDoorState(unsigned int door_state)
2400 return MoveDoor(door_state | DOOR_SET_STATE);
2403 unsigned int MoveDoor(unsigned int door_state)
2405 static int door1 = DOOR_OPEN_1;
2406 static int door2 = DOOR_CLOSE_2;
2407 static unsigned long door_delay = 0;
2408 int x, start, stepsize = door.step_offset;
2409 unsigned long door_delay_value = door.step_delay;
2411 if (door_state == DOOR_GET_STATE)
2412 return(door1 | door2);
2414 if (door_state & DOOR_SET_STATE)
2416 if (door_state & DOOR_ACTION_1)
2417 door1 = door_state & DOOR_ACTION_1;
2418 if (door_state & DOOR_ACTION_2)
2419 door2 = door_state & DOOR_ACTION_2;
2421 return(door1 | door2);
2424 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
2425 door_state &= ~DOOR_OPEN_1;
2426 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
2427 door_state &= ~DOOR_CLOSE_1;
2428 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
2429 door_state &= ~DOOR_OPEN_2;
2430 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
2431 door_state &= ~DOOR_CLOSE_2;
2433 if (setup.quick_doors)
2436 door_delay_value = 0;
2438 StopSound(SND_DOOR_OPENING);
2439 StopSound(SND_DOOR_CLOSING);
2442 if (global.autoplay_leveldir)
2444 door_state |= DOOR_NO_DELAY;
2445 door_state &= ~DOOR_CLOSE_ALL;
2448 if (door_state & DOOR_ACTION)
2450 if (!(door_state & DOOR_NO_DELAY))
2452 /* opening door sound has priority over simultaneously closing door */
2453 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
2454 PlaySoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
2455 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
2456 PlaySoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
2459 start = ((door_state & DOOR_NO_DELAY) ? DXSIZE : 0);
2461 for(x=start; x<=DXSIZE; x+=stepsize)
2463 Bitmap *bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
2464 GC gc = bitmap->stored_clip_gc;
2466 if (!(door_state & DOOR_NO_DELAY))
2467 WaitUntilDelayReached(&door_delay, door_delay_value);
2469 if (door_state & DOOR_ACTION_1)
2471 int i = (door_state & DOOR_OPEN_1 ? DXSIZE-x : x);
2472 int j = (DXSIZE - i) / 3;
2474 BlitBitmap(bitmap_db_door, drawto,
2475 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + i/2,
2476 DXSIZE,DYSIZE - i/2, DX, DY);
2478 ClearRectangle(drawto, DX, DY + DYSIZE - i/2, DXSIZE,i/2);
2480 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2481 BlitBitmapMasked(bitmap, drawto,
2482 DXSIZE, DOOR_GFX_PAGEY1, i, 77,
2483 DX + DXSIZE - i, DY + j);
2484 BlitBitmapMasked(bitmap, drawto,
2485 DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63,
2486 DX + DXSIZE - i, DY + 140 + j);
2487 SetClipOrigin(bitmap, gc, DX - DXSIZE + i, DY - (DOOR_GFX_PAGEY1 + j));
2488 BlitBitmapMasked(bitmap, drawto,
2489 DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j,
2491 BlitBitmapMasked(bitmap, drawto,
2492 DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63,
2495 BlitBitmapMasked(bitmap, drawto,
2496 DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
2498 BlitBitmapMasked(bitmap, drawto,
2499 DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
2501 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2502 BlitBitmapMasked(bitmap, drawto,
2503 DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
2504 DX + DXSIZE - i, DY + 77 + j);
2505 BlitBitmapMasked(bitmap, drawto,
2506 DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
2507 DX + DXSIZE - i, DY + 203 + j);
2509 redraw_mask |= REDRAW_DOOR_1;
2512 if (door_state & DOOR_ACTION_2)
2514 int i = (door_state & DOOR_OPEN_2 ? VXSIZE - x : x);
2515 int j = (VXSIZE - i) / 3;
2517 BlitBitmap(bitmap_db_door, drawto,
2518 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + i/2,
2519 VXSIZE, VYSIZE - i/2, VX, VY);
2521 ClearRectangle(drawto, VX, VY + VYSIZE-i/2, VXSIZE, i/2);
2523 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2524 BlitBitmapMasked(bitmap, drawto,
2525 VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2,
2526 VX + VXSIZE-i, VY+j);
2527 SetClipOrigin(bitmap, gc,
2528 VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
2529 BlitBitmapMasked(bitmap, drawto,
2530 VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j,
2533 BlitBitmapMasked(bitmap, drawto,
2534 VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2,
2535 i, VYSIZE / 2, VX, VY + VYSIZE / 2 - j);
2536 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2537 BlitBitmapMasked(bitmap, drawto,
2538 VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2,
2540 VX + VXSIZE - i, VY + VYSIZE / 2 + j);
2542 redraw_mask |= REDRAW_DOOR_2;
2547 if (game_status == GAME_MODE_MAIN)
2552 if (setup.quick_doors)
2554 StopSound(SND_DOOR_OPENING);
2555 StopSound(SND_DOOR_CLOSING);
2558 if (door_state & DOOR_ACTION_1)
2559 door1 = door_state & DOOR_ACTION_1;
2560 if (door_state & DOOR_ACTION_2)
2561 door2 = door_state & DOOR_ACTION_2;
2563 return (door1 | door2);
2566 void DrawSpecialEditorDoor()
2568 /* draw bigger toolbox window */
2569 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
2570 DOOR_GFX_PAGEX7, 0, EXSIZE + 8, 8,
2572 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
2573 EX - 4, VY - 4, EXSIZE + 8, EYSIZE - VYSIZE + 4,
2576 redraw_mask |= REDRAW_ALL;
2579 void UndrawSpecialEditorDoor()
2581 /* draw normal tape recorder window */
2582 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
2583 EX - 4, EY - 12, EXSIZE + 8, EYSIZE - VYSIZE + 12,
2586 redraw_mask |= REDRAW_ALL;
2590 /* ---------- new tool button stuff ---------------------------------------- */
2592 /* graphic position values for tool buttons */
2593 #define TOOL_BUTTON_YES_XPOS 2
2594 #define TOOL_BUTTON_YES_YPOS 250
2595 #define TOOL_BUTTON_YES_GFX_YPOS 0
2596 #define TOOL_BUTTON_YES_XSIZE 46
2597 #define TOOL_BUTTON_YES_YSIZE 28
2598 #define TOOL_BUTTON_NO_XPOS 52
2599 #define TOOL_BUTTON_NO_YPOS TOOL_BUTTON_YES_YPOS
2600 #define TOOL_BUTTON_NO_GFX_YPOS TOOL_BUTTON_YES_GFX_YPOS
2601 #define TOOL_BUTTON_NO_XSIZE TOOL_BUTTON_YES_XSIZE
2602 #define TOOL_BUTTON_NO_YSIZE TOOL_BUTTON_YES_YSIZE
2603 #define TOOL_BUTTON_CONFIRM_XPOS TOOL_BUTTON_YES_XPOS
2604 #define TOOL_BUTTON_CONFIRM_YPOS TOOL_BUTTON_YES_YPOS
2605 #define TOOL_BUTTON_CONFIRM_GFX_YPOS 30
2606 #define TOOL_BUTTON_CONFIRM_XSIZE 96
2607 #define TOOL_BUTTON_CONFIRM_YSIZE TOOL_BUTTON_YES_YSIZE
2608 #define TOOL_BUTTON_PLAYER_XSIZE 30
2609 #define TOOL_BUTTON_PLAYER_YSIZE 30
2610 #define TOOL_BUTTON_PLAYER_GFX_XPOS 5
2611 #define TOOL_BUTTON_PLAYER_GFX_YPOS 185
2612 #define TOOL_BUTTON_PLAYER_XPOS (5 + TOOL_BUTTON_PLAYER_XSIZE / 2)
2613 #define TOOL_BUTTON_PLAYER_YPOS (215 - TOOL_BUTTON_PLAYER_YSIZE / 2)
2614 #define TOOL_BUTTON_PLAYER1_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2615 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2616 #define TOOL_BUTTON_PLAYER2_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2617 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2618 #define TOOL_BUTTON_PLAYER3_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2619 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2620 #define TOOL_BUTTON_PLAYER4_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2621 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2622 #define TOOL_BUTTON_PLAYER1_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2623 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2624 #define TOOL_BUTTON_PLAYER2_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2625 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2626 #define TOOL_BUTTON_PLAYER3_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2627 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2628 #define TOOL_BUTTON_PLAYER4_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2629 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2638 } toolbutton_info[NUM_TOOL_BUTTONS] =
2641 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_GFX_YPOS,
2642 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_YPOS,
2643 TOOL_BUTTON_YES_XSIZE, TOOL_BUTTON_YES_YSIZE,
2648 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_GFX_YPOS,
2649 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_YPOS,
2650 TOOL_BUTTON_NO_XSIZE, TOOL_BUTTON_NO_YSIZE,
2655 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_GFX_YPOS,
2656 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_YPOS,
2657 TOOL_BUTTON_CONFIRM_XSIZE, TOOL_BUTTON_CONFIRM_YSIZE,
2658 TOOL_CTRL_ID_CONFIRM,
2662 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2663 TOOL_BUTTON_PLAYER1_XPOS, TOOL_BUTTON_PLAYER1_YPOS,
2664 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2665 TOOL_CTRL_ID_PLAYER_1,
2669 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2670 TOOL_BUTTON_PLAYER2_XPOS, TOOL_BUTTON_PLAYER2_YPOS,
2671 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2672 TOOL_CTRL_ID_PLAYER_2,
2676 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2677 TOOL_BUTTON_PLAYER3_XPOS, TOOL_BUTTON_PLAYER3_YPOS,
2678 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2679 TOOL_CTRL_ID_PLAYER_3,
2683 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2684 TOOL_BUTTON_PLAYER4_XPOS, TOOL_BUTTON_PLAYER4_YPOS,
2685 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2686 TOOL_CTRL_ID_PLAYER_4,
2691 void CreateToolButtons()
2695 for (i=0; i<NUM_TOOL_BUTTONS; i++)
2697 Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
2698 Bitmap *deco_bitmap = None;
2699 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
2700 struct GadgetInfo *gi;
2701 unsigned long event_mask;
2702 int gd_xoffset, gd_yoffset;
2703 int gd_x1, gd_x2, gd_y;
2706 event_mask = GD_EVENT_RELEASED;
2708 gd_xoffset = toolbutton_info[i].xpos;
2709 gd_yoffset = toolbutton_info[i].ypos;
2710 gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
2711 gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
2712 gd_y = DOOR_GFX_PAGEY1 + gd_yoffset;
2714 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
2716 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
2718 getMiniGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr),
2719 &deco_bitmap, &deco_x, &deco_y);
2720 deco_xpos = (toolbutton_info[i].width - MINI_TILEX) / 2;
2721 deco_ypos = (toolbutton_info[i].height - MINI_TILEY) / 2;
2724 gi = CreateGadget(GDI_CUSTOM_ID, id,
2725 GDI_INFO_TEXT, toolbutton_info[i].infotext,
2726 GDI_X, DX + toolbutton_info[i].x,
2727 GDI_Y, DY + toolbutton_info[i].y,
2728 GDI_WIDTH, toolbutton_info[i].width,
2729 GDI_HEIGHT, toolbutton_info[i].height,
2730 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
2731 GDI_STATE, GD_BUTTON_UNPRESSED,
2732 GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
2733 GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
2734 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
2735 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
2736 GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
2737 GDI_DECORATION_SHIFTING, 1, 1,
2738 GDI_EVENT_MASK, event_mask,
2739 GDI_CALLBACK_ACTION, HandleToolButtons,
2743 Error(ERR_EXIT, "cannot create gadget");
2745 tool_gadget[id] = gi;
2749 void FreeToolButtons()
2753 for (i=0; i<NUM_TOOL_BUTTONS; i++)
2754 FreeGadget(tool_gadget[i]);
2757 static void UnmapToolButtons()
2761 for (i=0; i<NUM_TOOL_BUTTONS; i++)
2762 UnmapGadget(tool_gadget[i]);
2765 static void HandleToolButtons(struct GadgetInfo *gi)
2767 request_gadget_id = gi->custom_id;
2770 int get_next_element(int element)
2774 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
2775 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
2776 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
2777 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
2778 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
2779 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
2780 case EL_AMOEBA_DROPPING: return EL_AMOEBA_WET;
2782 default: return element;
2786 int el_act_dir2img(int element, int action, int direction)
2788 element = GFX_ELEMENT(element);
2789 direction = MV_DIR_BIT(direction);
2791 return element_info[element].direction_graphic[action][direction];
2794 static int el_act_dir2crm(int element, int action, int direction)
2796 element = GFX_ELEMENT(element);
2797 direction = MV_DIR_BIT(direction);
2799 return element_info[element].direction_crumbled[action][direction];
2802 int el_act2img(int element, int action)
2804 element = GFX_ELEMENT(element);
2806 return element_info[element].graphic[action];
2809 int el_act2crm(int element, int action)
2811 element = GFX_ELEMENT(element);
2813 return element_info[element].crumbled[action];
2816 int el_dir2img(int element, int direction)
2818 element = GFX_ELEMENT(element);
2820 return el_act_dir2img(element, ACTION_DEFAULT, direction);
2823 int el2img(int element)
2825 element = GFX_ELEMENT(element);
2827 return element_info[element].graphic[ACTION_DEFAULT];
2830 int el2edimg(int element)
2832 element = GFX_ELEMENT(element);
2834 return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
2837 int el2preimg(int element)
2839 element = GFX_ELEMENT(element);
2841 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];