1 /***********************************************************
2 * Rocks'n'Diamonds -- McDuffin Strikes Back! *
3 *----------------------------------------------------------*
4 * (c) 1995-2002 Artsoft Entertainment *
6 * Detmolder Strasse 189 *
9 * e-mail: info@artsoft.org *
10 *----------------------------------------------------------*
12 ***********************************************************/
14 #include "libgame/libgame.h"
23 /* tool button identifiers */
24 #define TOOL_CTRL_ID_YES 0
25 #define TOOL_CTRL_ID_NO 1
26 #define TOOL_CTRL_ID_CONFIRM 2
27 #define TOOL_CTRL_ID_PLAYER_1 3
28 #define TOOL_CTRL_ID_PLAYER_2 4
29 #define TOOL_CTRL_ID_PLAYER_3 5
30 #define TOOL_CTRL_ID_PLAYER_4 6
32 #define NUM_TOOL_BUTTONS 7
34 /* forward declaration for internal use */
35 static void UnmapToolButtons();
36 static void HandleToolButtons(struct GadgetInfo *);
37 static int el_act_dir2crm(int, int, int);
38 static int el_act2crm(int, int);
40 static struct GadgetInfo *tool_gadget[NUM_TOOL_BUTTONS];
41 static int request_gadget_id = -1;
43 void SetDrawtoField(int mode)
45 if (mode == DRAW_BUFFERED && setup.soft_scrolling)
56 drawto_field = fieldbuffer;
58 else /* DRAW_DIRECT, DRAW_BACKBUFFER */
69 drawto_field = (mode == DRAW_DIRECT ? window : backbuffer);
73 void RedrawPlayfield(boolean force_redraw, int x, int y, int width, int height)
75 if (game_status == GAME_MODE_PLAYING && !game.envelope_active)
81 width = gfx.sxsize + 2 * TILEX;
82 height = gfx.sysize + 2 * TILEY;
85 if (force_redraw || setup.direct_draw)
88 int x1 = (x - SX) / TILEX, y1 = (y - SY) / TILEY;
89 int x2 = (x - SX + width) / TILEX, y2 = (y - SY + height) / TILEY;
91 if (setup.direct_draw)
92 SetDrawtoField(DRAW_BACKBUFFER);
94 for (xx = BX1; xx <= BX2; xx++)
95 for (yy = BY1; yy <= BY2; yy++)
96 if (xx >= x1 && xx <= x2 && yy >= y1 && yy <= y2)
97 DrawScreenField(xx, yy);
100 if (setup.direct_draw)
101 SetDrawtoField(DRAW_DIRECT);
104 if (setup.soft_scrolling)
106 int fx = FX, fy = FY;
108 fx += (ScreenMovDir & (MV_LEFT|MV_RIGHT) ? ScreenGfxPos : 0);
109 fy += (ScreenMovDir & (MV_UP|MV_DOWN) ? ScreenGfxPos : 0);
111 BlitBitmap(fieldbuffer, backbuffer, fx,fy, SXSIZE,SYSIZE, SX,SY);
115 BlitBitmap(drawto, window, x, y, width, height, x, y);
121 DrawBuffer *buffer = (drawto_field == window ? backbuffer : drawto_field);
123 if (setup.direct_draw && game_status == GAME_MODE_PLAYING)
124 redraw_mask &= ~REDRAW_MAIN;
126 if (redraw_mask & REDRAW_TILES && redraw_tiles > REDRAWTILES_THRESHOLD)
127 redraw_mask |= REDRAW_FIELD;
129 if (redraw_mask & REDRAW_FIELD)
130 redraw_mask &= ~REDRAW_TILES;
132 if (redraw_mask == REDRAW_NONE)
135 if (global.fps_slowdown && game_status == GAME_MODE_PLAYING)
137 static boolean last_frame_skipped = FALSE;
138 boolean skip_even_when_not_scrolling = TRUE;
139 boolean just_scrolling = (ScreenMovDir != 0);
140 boolean verbose = FALSE;
142 if (global.fps_slowdown_factor > 1 &&
143 (FrameCounter % global.fps_slowdown_factor) &&
144 (just_scrolling || skip_even_when_not_scrolling))
146 redraw_mask &= ~REDRAW_MAIN;
148 last_frame_skipped = TRUE;
151 printf("FRAME SKIPPED\n");
155 if (last_frame_skipped)
156 redraw_mask |= REDRAW_FIELD;
158 last_frame_skipped = FALSE;
161 printf("frame not skipped\n");
165 /* synchronize X11 graphics at this point; if we would synchronize the
166 display immediately after the buffer switching (after the XFlush),
167 this could mean that we have to wait for the graphics to complete,
168 although we could go on doing calculations for the next frame */
172 if (redraw_mask & REDRAW_ALL)
174 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
178 if (redraw_mask & REDRAW_FIELD)
180 if (game_status != GAME_MODE_PLAYING ||
181 redraw_mask & REDRAW_FROM_BACKBUFFER)
183 BlitBitmap(backbuffer, window,
184 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE, REAL_SX, REAL_SY);
188 int fx = FX, fy = FY;
190 if (setup.soft_scrolling)
192 fx += (ScreenMovDir & (MV_LEFT | MV_RIGHT) ? ScreenGfxPos : 0);
193 fy += (ScreenMovDir & (MV_UP | MV_DOWN) ? ScreenGfxPos : 0);
196 if (setup.soft_scrolling ||
197 ABS(ScreenMovPos) + ScrollStepSize == TILEX ||
198 ABS(ScreenMovPos) == ScrollStepSize ||
199 redraw_tiles > REDRAWTILES_THRESHOLD)
201 BlitBitmap(buffer, window, fx, fy, SXSIZE, SYSIZE, SX, SY);
205 printf("redrawing all (ScreenGfxPos == %d) because %s\n",
207 (setup.soft_scrolling ?
208 "setup.soft_scrolling" :
209 ABS(ScreenGfxPos) + ScrollStepSize == TILEX ?
210 "ABS(ScreenGfxPos) + ScrollStepSize == TILEX" :
211 ABS(ScreenGfxPos) == ScrollStepSize ?
212 "ABS(ScreenGfxPos) == ScrollStepSize" :
213 "redraw_tiles > REDRAWTILES_THRESHOLD"));
219 redraw_mask &= ~REDRAW_MAIN;
222 if (redraw_mask & REDRAW_DOORS)
224 if (redraw_mask & REDRAW_DOOR_1)
225 BlitBitmap(backbuffer, window, DX, DY, DXSIZE, DYSIZE, DX, DY);
226 if (redraw_mask & REDRAW_DOOR_2)
228 if ((redraw_mask & REDRAW_DOOR_2) == REDRAW_DOOR_2)
229 BlitBitmap(backbuffer, window, VX,VY, VXSIZE,VYSIZE, VX,VY);
232 if (redraw_mask & REDRAW_VIDEO_1)
233 BlitBitmap(backbuffer, window,
234 VX+VIDEO_DISPLAY1_XPOS,VY+VIDEO_DISPLAY1_YPOS,
235 VIDEO_DISPLAY_XSIZE,VIDEO_DISPLAY_YSIZE,
236 VX+VIDEO_DISPLAY1_XPOS,VY+VIDEO_DISPLAY1_YPOS);
237 if (redraw_mask & REDRAW_VIDEO_2)
238 BlitBitmap(backbuffer, window,
239 VX+VIDEO_DISPLAY2_XPOS,VY+VIDEO_DISPLAY2_YPOS,
240 VIDEO_DISPLAY_XSIZE,VIDEO_DISPLAY_YSIZE,
241 VX+VIDEO_DISPLAY2_XPOS,VY+VIDEO_DISPLAY2_YPOS);
242 if (redraw_mask & REDRAW_VIDEO_3)
243 BlitBitmap(backbuffer, window,
244 VX+VIDEO_CONTROL_XPOS,VY+VIDEO_CONTROL_YPOS,
245 VIDEO_CONTROL_XSIZE,VIDEO_CONTROL_YSIZE,
246 VX+VIDEO_CONTROL_XPOS,VY+VIDEO_CONTROL_YPOS);
250 if (redraw_mask & REDRAW_DOOR_3)
251 BlitBitmap(backbuffer, window, EX, EY, EXSIZE, EYSIZE, EX, EY);
253 redraw_mask &= ~REDRAW_DOORS;
256 if (redraw_mask & REDRAW_MICROLEVEL)
258 BlitBitmap(backbuffer, window, SX, SY + 10 * TILEY, SXSIZE, 7 * TILEY,
259 SX, SY + 10 * TILEY);
261 redraw_mask &= ~REDRAW_MICROLEVEL;
264 if (redraw_mask & REDRAW_TILES)
266 for (x = 0; x < SCR_FIELDX; x++)
267 for (y =0 ; y < SCR_FIELDY; y++)
268 if (redraw[redraw_x1 + x][redraw_y1 + y])
269 BlitBitmap(buffer, window,
270 FX + x * TILEX, FX + y * TILEY, TILEX, TILEY,
271 SX + x * TILEX, SY + y * TILEY);
274 if (redraw_mask & REDRAW_FPS) /* display frames per second */
279 sprintf(info1, " (only every %d. frame)", global.fps_slowdown_factor);
280 if (!global.fps_slowdown)
283 sprintf(text, "%.1f fps%s", global.frames_per_second, info1);
284 DrawTextExt(window, SX, SY, text, FONT_TEXT_2, BLIT_OPAQUE);
289 for (x = 0; x < MAX_BUF_XSIZE; x++)
290 for (y = 0; y < MAX_BUF_YSIZE; y++)
293 redraw_mask = REDRAW_NONE;
299 long fading_delay = 300;
301 if (setup.fading && (redraw_mask & REDRAW_FIELD))
308 ClearRectangle(window, REAL_SX,REAL_SY,FULL_SXSIZE,FULL_SYSIZE);
311 for (i = 0; i < 2 * FULL_SYSIZE; i++)
313 for (y = 0; y < FULL_SYSIZE; y++)
315 BlitBitmap(backbuffer, window,
316 REAL_SX,REAL_SY+i, FULL_SXSIZE,1, REAL_SX,REAL_SY+i);
324 for (i = 1; i < FULL_SYSIZE; i+=2)
325 BlitBitmap(backbuffer, window,
326 REAL_SX,REAL_SY+i, FULL_SXSIZE,1, REAL_SX,REAL_SY+i);
332 SetClipOrigin(clip_gc[PIX_FADEMASK], 0, 0);
333 BlitBitmapMasked(backbuffer, window,
334 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
339 SetClipOrigin(clip_gc[PIX_FADEMASK], -1, -1);
340 BlitBitmapMasked(backbuffer, window,
341 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
346 SetClipOrigin(clip_gc[PIX_FADEMASK], 0, -1);
347 BlitBitmapMasked(backbuffer, window,
348 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
353 SetClipOrigin(clip_gc[PIX_FADEMASK], -1, 0);
354 BlitBitmapMasked(backbuffer, window,
355 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
360 redraw_mask &= ~REDRAW_MAIN;
367 void SetMainBackgroundImage(int graphic)
369 SetMainBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
370 graphic_info[graphic].bitmap ?
371 graphic_info[graphic].bitmap :
372 graphic_info[IMG_BACKGROUND].bitmap);
375 void SetDoorBackgroundImage(int graphic)
377 SetDoorBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
378 graphic_info[graphic].bitmap ?
379 graphic_info[graphic].bitmap :
380 graphic_info[IMG_BACKGROUND].bitmap);
383 void DrawBackground(int dest_x, int dest_y, int width, int height)
385 ClearRectangleOnBackground(backbuffer, dest_x, dest_y, width, height);
387 redraw_mask |= REDRAW_FIELD;
392 DrawBackground(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
394 if (setup.soft_scrolling && game_status == GAME_MODE_PLAYING)
396 ClearRectangle(fieldbuffer, 0, 0, FXSIZE, FYSIZE);
397 SetDrawtoField(DRAW_BUFFERED);
400 SetDrawtoField(DRAW_BACKBUFFER);
402 if (setup.direct_draw && game_status == GAME_MODE_PLAYING)
404 ClearRectangle(window, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
405 SetDrawtoField(DRAW_DIRECT);
409 void MarkTileDirty(int x, int y)
411 int xx = redraw_x1 + x;
412 int yy = redraw_y1 + y;
417 redraw[xx][yy] = TRUE;
418 redraw_mask |= REDRAW_TILES;
421 void SetBorderElement()
425 BorderElement = EL_EMPTY;
427 for (y = 0; y < lev_fieldy && BorderElement == EL_EMPTY; y++)
429 for (x = 0; x < lev_fieldx; x++)
431 if (!IS_INDESTRUCTIBLE(Feld[x][y]))
432 BorderElement = EL_STEELWALL;
434 if (y != 0 && y != lev_fieldy - 1 && x != lev_fieldx - 1)
440 void SetRandomAnimationValue(int x, int y)
442 gfx.anim_random_frame = GfxRandom[x][y];
445 inline int getGraphicAnimationFrame(int graphic, int sync_frame)
447 /* animation synchronized with global frame counter, not move position */
448 if (graphic_info[graphic].anim_global_sync || sync_frame < 0)
449 sync_frame = FrameCounter;
451 return getAnimationFrame(graphic_info[graphic].anim_frames,
452 graphic_info[graphic].anim_delay,
453 graphic_info[graphic].anim_mode,
454 graphic_info[graphic].anim_start_frame,
458 inline void DrawGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
459 int graphic, int sync_frame, int mask_mode)
461 int frame = getGraphicAnimationFrame(graphic, sync_frame);
463 if (mask_mode == USE_MASKING)
464 DrawGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
466 DrawGraphicExt(dst_bitmap, x, y, graphic, frame);
469 inline void DrawGraphicAnimation(int x, int y, int graphic)
471 int lx = LEVELX(x), ly = LEVELY(y);
473 if (!IN_SCR_FIELD(x, y))
476 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
477 graphic, GfxFrame[lx][ly], NO_MASKING);
481 void DrawLevelGraphicAnimation(int x, int y, int graphic)
483 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
486 void DrawLevelElementAnimation(int x, int y, int element)
489 int graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
491 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
493 DrawGraphicAnimation(SCREENX(x), SCREENY(y), el2img(element));
497 inline void DrawLevelGraphicAnimationIfNeeded(int x, int y, int graphic)
499 int sx = SCREENX(x), sy = SCREENY(y);
501 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
504 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
507 DrawGraphicAnimation(sx, sy, graphic);
509 if (GFX_CRUMBLED(Feld[x][y]))
510 DrawLevelFieldCrumbledSand(x, y);
513 void DrawLevelElementAnimationIfNeeded(int x, int y, int element)
515 int sx = SCREENX(x), sy = SCREENY(y);
518 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
521 graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
523 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
526 DrawGraphicAnimation(sx, sy, graphic);
528 if (GFX_CRUMBLED(element))
529 DrawLevelFieldCrumbledSand(x, y);
532 static int getPlayerGraphic(struct PlayerInfo *player, int move_dir)
534 if (player->use_murphy_graphic)
536 /* this works only because currently only one player can be "murphy" ... */
537 static int last_horizontal_dir = MV_LEFT;
538 int graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, move_dir);
540 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
541 last_horizontal_dir = move_dir;
543 if (graphic == IMG_SP_MURPHY) /* undefined => use special graphic */
545 int direction = (player->is_snapping ? move_dir : last_horizontal_dir);
547 graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, direction);
553 return el_act_dir2img(player->element_nr, player->GfxAction, move_dir);
556 static boolean equalGraphics(int graphic1, int graphic2)
558 struct GraphicInfo *g1 = &graphic_info[graphic1];
559 struct GraphicInfo *g2 = &graphic_info[graphic2];
561 return (g1->bitmap == g2->bitmap &&
562 g1->src_x == g2->src_x &&
563 g1->src_y == g2->src_y &&
564 g1->anim_frames == g2->anim_frames &&
565 g1->anim_delay == g2->anim_delay &&
566 g1->anim_mode == g2->anim_mode);
569 void DrawAllPlayers()
573 for (i = 0; i < MAX_PLAYERS; i++)
574 if (stored_player[i].active)
575 DrawPlayer(&stored_player[i]);
578 void DrawPlayerField(int x, int y)
580 if (!IS_PLAYER(x, y))
583 DrawPlayer(PLAYERINFO(x, y));
586 void DrawPlayer(struct PlayerInfo *player)
590 int move_dir = player->MovDir;
592 int last_jx = player->last_jx;
593 int last_jy = player->last_jy;
594 int next_jx = jx + (jx - last_jx);
595 int next_jy = jy + (jy - last_jy);
596 boolean player_is_moving = (last_jx != jx || last_jy != jy ? TRUE : FALSE);
598 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? +1 : 0);
599 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? +1 : 0);
600 int last_jx = (player->is_moving ? jx - dx : jx);
601 int last_jy = (player->is_moving ? jy - dy : jy);
602 int next_jx = jx + dx;
603 int next_jy = jy + dy;
604 boolean player_is_moving = (player->MovPos ? TRUE : FALSE);
606 int sx = SCREENX(jx), sy = SCREENY(jy);
607 int sxx = 0, syy = 0;
608 int element = Feld[jx][jy], last_element = Feld[last_jx][last_jy];
610 int action = ACTION_DEFAULT;
611 int last_player_graphic = getPlayerGraphic(player, move_dir);
612 int last_player_frame = player->Frame;
615 if (!player->active || !IN_SCR_FIELD(SCREENX(last_jx), SCREENY(last_jy)))
619 if (!IN_LEV_FIELD(jx, jy))
621 printf("DrawPlayerField(): x = %d, y = %d\n",jx,jy);
622 printf("DrawPlayerField(): sx = %d, sy = %d\n",sx,sy);
623 printf("DrawPlayerField(): This should never happen!\n");
628 if (element == EL_EXPLOSION)
631 action = (player->is_pushing ? ACTION_PUSHING :
632 player->is_digging ? ACTION_DIGGING :
633 player->is_collecting ? ACTION_COLLECTING :
634 player->is_moving ? ACTION_MOVING :
635 player->is_snapping ? ACTION_SNAPPING :
636 player->is_waiting ? player->action_waiting : ACTION_DEFAULT);
638 InitPlayerGfxAnimation(player, action, move_dir);
640 /* ----------------------------------------------------------------------- */
641 /* draw things in the field the player is leaving, if needed */
642 /* ----------------------------------------------------------------------- */
645 if (player->is_moving)
647 if (player_is_moving)
650 if (Back[last_jx][last_jy] && IS_DRAWABLE(last_element))
652 DrawLevelElement(last_jx, last_jy, Back[last_jx][last_jy]);
654 if (last_element == EL_DYNAMITE_ACTIVE ||
655 last_element == EL_SP_DISK_RED_ACTIVE)
656 DrawDynamite(last_jx, last_jy);
658 DrawLevelFieldThruMask(last_jx, last_jy);
660 else if (last_element == EL_DYNAMITE_ACTIVE ||
661 last_element == EL_SP_DISK_RED_ACTIVE)
662 DrawDynamite(last_jx, last_jy);
664 DrawLevelField(last_jx, last_jy);
666 if (player->is_pushing && IN_SCR_FIELD(SCREENX(next_jx), SCREENY(next_jy)))
667 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
670 if (!IN_SCR_FIELD(sx, sy))
673 if (setup.direct_draw)
674 SetDrawtoField(DRAW_BUFFERED);
676 /* ----------------------------------------------------------------------- */
677 /* draw things behind the player, if needed */
678 /* ----------------------------------------------------------------------- */
681 DrawLevelElement(jx, jy, Back[jx][jy]);
682 else if (IS_ACTIVE_BOMB(element))
683 DrawLevelElement(jx, jy, EL_EMPTY);
686 if (player_is_moving && GfxElement[jx][jy] != EL_UNDEFINED)
688 if (GFX_CRUMBLED(GfxElement[jx][jy]))
689 DrawLevelFieldCrumbledSandDigging(jx, jy, move_dir, player->StepFrame);
692 int old_element = GfxElement[jx][jy];
693 int old_graphic = el_act_dir2img(old_element, action, move_dir);
694 int frame = getGraphicAnimationFrame(old_graphic, player->StepFrame);
696 DrawGraphic(sx, sy, old_graphic, frame);
701 GfxElement[jx][jy] = EL_UNDEFINED;
703 DrawLevelField(jx, jy);
707 /* ----------------------------------------------------------------------- */
708 /* draw player himself */
709 /* ----------------------------------------------------------------------- */
713 graphic = getPlayerGraphic(player, move_dir);
715 /* in the case of changed player action or direction, prevent the current
716 animation frame from being restarted for identical animations */
717 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
718 player->Frame = last_player_frame;
722 if (player->use_murphy_graphic)
724 static int last_horizontal_dir = MV_LEFT;
726 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
727 last_horizontal_dir = move_dir;
729 graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, move_dir);
731 if (graphic == IMG_SP_MURPHY) /* undefined => use special graphic */
733 int direction = (player->is_snapping ? move_dir : last_horizontal_dir);
735 graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, direction);
739 graphic = el_act_dir2img(player->element_nr, player->GfxAction, move_dir);
743 frame = getGraphicAnimationFrame(graphic, player->Frame);
747 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
748 sxx = player->GfxPos;
750 syy = player->GfxPos;
753 if (!setup.soft_scrolling && ScreenMovPos)
756 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
758 if (SHIELD_ON(player))
760 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
761 IMG_SHIELD_NORMAL_ACTIVE);
762 int frame = getGraphicAnimationFrame(graphic, -1);
764 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
767 /* ----------------------------------------------------------------------- */
768 /* draw things the player is pushing, if needed */
769 /* ----------------------------------------------------------------------- */
772 printf("::: %d, %d [%d, %d] [%d]\n",
773 player->is_pushing, player_is_moving, player->GfxAction,
774 player->is_moving, player_is_moving);
778 if (player->is_pushing && player->is_moving)
780 if (player->is_pushing && player_is_moving)
783 int px = SCREENX(next_jx), py = SCREENY(next_jy);
785 if (Back[next_jx][next_jy])
786 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
788 if ((sxx || syy) && element == EL_SOKOBAN_OBJECT)
789 DrawGraphicShiftedThruMask(px, py, sxx, syy, IMG_SOKOBAN_OBJECT, 0,
793 int element = MovingOrBlocked2Element(next_jx, next_jy);
794 int graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
796 int frame = getGraphicAnimationFrame(graphic, player->StepFrame);
798 int frame = getGraphicAnimationFrame(graphic, player->Frame);
801 DrawGraphicShifted(px, py, sxx, syy, graphic, frame,
802 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)
823 int graphic = el_act2img(GfxElement[last_jx][last_jy], ACTION_EXPLODING);
824 int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
825 int phase = ExplodePhase[last_jx][last_jy] - 1;
826 int frame = getGraphicAnimationFrame(graphic, phase - delay);
829 DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy), graphic, frame);
832 /* ----------------------------------------------------------------------- */
833 /* draw elements the player is just walking/passing through/under */
834 /* ----------------------------------------------------------------------- */
836 /* handle the field the player is leaving ... */
837 if (player_is_moving && IS_ACCESSIBLE_INSIDE(last_element))
838 DrawLevelField(last_jx, last_jy);
839 else if (player_is_moving && IS_ACCESSIBLE_UNDER(last_element))
840 DrawLevelFieldThruMask(last_jx, last_jy);
842 /* ... and the field the player is entering */
843 if (IS_ACCESSIBLE_INSIDE(element))
844 DrawLevelField(jx, jy);
845 else if (IS_ACCESSIBLE_UNDER(element))
846 DrawLevelFieldThruMask(jx, jy);
848 if (setup.direct_draw)
850 int dest_x = SX + SCREENX(MIN(jx, last_jx)) * TILEX;
851 int dest_y = SY + SCREENY(MIN(jy, last_jy)) * TILEY;
852 int x_size = TILEX * (1 + ABS(jx - last_jx));
853 int y_size = TILEY * (1 + ABS(jy - last_jy));
855 BlitBitmap(drawto_field, window,
856 dest_x, dest_y, x_size, y_size, dest_x, dest_y);
857 SetDrawtoField(DRAW_DIRECT);
860 MarkTileDirty(sx,sy);
863 void getGraphicSource(int graphic, int frame, Bitmap **bitmap, int *x, int *y)
865 struct GraphicInfo *g = &graphic_info[graphic];
869 if (g->offset_y == 0) /* frames are ordered horizontally */
871 int max_width = g->anim_frames_per_line * g->width;
873 *x = (g->src_x + frame * g->offset_x) % max_width;
874 *y = g->src_y + (g->src_x + frame * g->offset_x) / max_width * g->height;
876 else if (g->offset_x == 0) /* frames are ordered vertically */
878 int max_height = g->anim_frames_per_line * g->height;
880 *x = g->src_x + (g->src_y + frame * g->offset_y) / max_height * g->width;
881 *y = (g->src_y + frame * g->offset_y) % max_height;
883 else /* frames are ordered diagonally */
885 *x = g->src_x + frame * g->offset_x;
886 *y = g->src_y + frame * g->offset_y;
890 void DrawGraphic(int x, int y, int graphic, int frame)
893 if (!IN_SCR_FIELD(x, y))
895 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
896 printf("DrawGraphic(): This should never happen!\n");
901 DrawGraphicExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic, frame);
905 void DrawGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
911 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
912 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
915 void DrawGraphicThruMask(int x, int y, int graphic, int frame)
918 if (!IN_SCR_FIELD(x, y))
920 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
921 printf("DrawGraphicThruMask(): This should never happen!\n");
926 DrawGraphicThruMaskExt(drawto_field, FX + x * TILEX, FY + y *TILEY, graphic,
931 void DrawGraphicThruMaskExt(DrawBuffer *d, int dest_x, int dest_y, int graphic,
939 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
940 drawing_gc = src_bitmap->stored_clip_gc;
942 GC drawing_gc = src_bitmap->stored_clip_gc;
943 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
944 int src_x = graphic_info[graphic].src_x;
945 int src_y = graphic_info[graphic].src_y;
946 int offset_x = graphic_info[graphic].offset_x;
947 int offset_y = graphic_info[graphic].offset_y;
949 src_x += frame * offset_x;
950 src_y += frame * offset_y;
954 SetClipOrigin(src_bitmap, drawing_gc, dest_x - src_x, dest_y - src_y);
955 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX, TILEY, dest_x, dest_y);
958 void DrawMiniGraphic(int x, int y, int graphic)
960 DrawMiniGraphicExt(drawto, SX + x * MINI_TILEX,SY + y * MINI_TILEY, graphic);
961 MarkTileDirty(x / 2, y / 2);
964 void getMiniGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
966 struct GraphicInfo *g = &graphic_info[graphic];
968 int mini_starty = g->bitmap->height * 2 / 3;
971 *x = mini_startx + g->src_x / 2;
972 *y = mini_starty + g->src_y / 2;
975 void DrawMiniGraphicExt(DrawBuffer *d, int x, int y, int graphic)
980 getMiniGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
981 BlitBitmap(src_bitmap, d, src_x, src_y, MINI_TILEX, MINI_TILEY, x, y);
984 void DrawGraphicShifted(int x,int y, int dx,int dy, int graphic, int frame,
985 int cut_mode, int mask_mode)
990 int width = TILEX, height = TILEY;
996 DrawGraphic(x, y, graphic, frame);
1000 if (dx || dy) /* shifted graphic */
1002 if (x < BX1) /* object enters playfield from the left */
1009 else if (x > BX2) /* object enters playfield from the right */
1015 else if (x==BX1 && dx < 0) /* object leaves playfield to the left */
1021 else if (x==BX2 && dx > 0) /* object leaves playfield to the right */
1023 else if (dx) /* general horizontal movement */
1024 MarkTileDirty(x + SIGN(dx), y);
1026 if (y < BY1) /* object enters playfield from the top */
1028 if (cut_mode==CUT_BELOW) /* object completely above top border */
1036 else if (y > BY2) /* object enters playfield from the bottom */
1042 else if (y==BY1 && dy < 0) /* object leaves playfield to the top */
1048 else if (dy > 0 && cut_mode == CUT_ABOVE)
1050 if (y == BY2) /* object completely above bottom border */
1056 MarkTileDirty(x, y + 1);
1057 } /* object leaves playfield to the bottom */
1058 else if (dy > 0 && (y == BY2 || cut_mode == CUT_BELOW))
1060 else if (dy) /* general vertical movement */
1061 MarkTileDirty(x, y + SIGN(dy));
1065 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1067 src_bitmap = graphic_info[graphic].bitmap;
1068 src_x = graphic_info[graphic].src_x;
1069 src_y = graphic_info[graphic].src_y;
1070 offset_x = graphic_info[graphic].offset_x;
1071 offset_y = graphic_info[graphic].offset_y;
1073 src_x += frame * offset_x;
1074 src_y += frame * offset_y;
1077 drawing_gc = src_bitmap->stored_clip_gc;
1082 dest_x = FX + x * TILEX + dx;
1083 dest_y = FY + y * TILEY + dy;
1086 if (!IN_SCR_FIELD(x,y))
1088 printf("DrawGraphicShifted(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
1089 printf("DrawGraphicShifted(): This should never happen!\n");
1094 if (mask_mode == USE_MASKING)
1096 SetClipOrigin(src_bitmap, drawing_gc, dest_x - src_x, dest_y - src_y);
1097 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1101 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1107 void DrawGraphicShiftedThruMask(int x, int y, int dx, int dy, int graphic,
1108 int frame, int cut_mode)
1110 DrawGraphicShifted(x,y, dx,dy, graphic, frame, cut_mode, USE_MASKING);
1113 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
1114 int cut_mode, int mask_mode)
1116 int lx = LEVELX(x), ly = LEVELY(y);
1120 if (IN_LEV_FIELD(lx, ly))
1122 SetRandomAnimationValue(lx, ly);
1124 graphic = el_act_dir2img(element, GfxAction[lx][ly], GfxDir[lx][ly]);
1125 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1127 else /* border element */
1129 graphic = el2img(element);
1130 frame = getGraphicAnimationFrame(graphic, -1);
1133 if (element == EL_EXPANDABLE_WALL)
1135 boolean left_stopped = FALSE, right_stopped = FALSE;
1137 if (!IN_LEV_FIELD(lx - 1, ly) || IS_WALL(Feld[lx - 1][ly]))
1138 left_stopped = TRUE;
1139 if (!IN_LEV_FIELD(lx + 1, ly) || IS_WALL(Feld[lx + 1][ly]))
1140 right_stopped = TRUE;
1142 if (left_stopped && right_stopped)
1144 else if (left_stopped)
1146 graphic = IMG_EXPANDABLE_WALL_GROWING_RIGHT;
1147 frame = graphic_info[graphic].anim_frames - 1;
1149 else if (right_stopped)
1151 graphic = IMG_EXPANDABLE_WALL_GROWING_LEFT;
1152 frame = graphic_info[graphic].anim_frames - 1;
1157 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, mask_mode);
1158 else if (mask_mode == USE_MASKING)
1159 DrawGraphicThruMask(x, y, graphic, frame);
1161 DrawGraphic(x, y, graphic, frame);
1164 void DrawLevelElementExt(int x, int y, int dx, int dy, int element,
1165 int cut_mode, int mask_mode)
1167 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1168 DrawScreenElementExt(SCREENX(x), SCREENY(y), dx, dy, element,
1169 cut_mode, mask_mode);
1172 void DrawScreenElementShifted(int x, int y, int dx, int dy, int element,
1175 DrawScreenElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1178 void DrawLevelElementShifted(int x, int y, int dx, int dy, int element,
1181 DrawLevelElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1184 void DrawLevelElementThruMask(int x, int y, int element)
1186 DrawLevelElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1189 void DrawLevelFieldThruMask(int x, int y)
1191 DrawLevelElementExt(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
1194 static void DrawLevelFieldCrumbledSandExt(int x, int y, int graphic, int frame)
1198 int sx = SCREENX(x), sy = SCREENY(y);
1200 int width, height, cx, cy, i;
1202 int crumbled_border_size = graphic_info[graphic].border_size;
1204 int snip = TILEX / 8; /* number of border pixels from "crumbled graphic" */
1206 static int xy[4][2] =
1215 if (x == 0 && y == 7)
1216 printf("::: %d, %d [%d]\n", GfxElement[x][y], Feld[x][y],
1217 crumbled_border_size);
1220 if (!IN_LEV_FIELD(x, y))
1223 element = (GfxElement[x][y] != EL_UNDEFINED && Feld[x][y] != EL_EXPLOSION ?
1224 GfxElement[x][y] : Feld[x][y]);
1226 /* crumble field itself */
1227 if (GFX_CRUMBLED(element) && !IS_MOVING(x, y))
1229 if (!IN_SCR_FIELD(sx, sy))
1232 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1234 for (i = 0; i < 4; i++)
1236 int xx = x + xy[i][0];
1237 int yy = y + xy[i][1];
1239 element = (IN_LEV_FIELD(xx, yy) ? Feld[xx][yy] : BorderElement);
1241 /* check if neighbour field is of same type */
1242 if (GFX_CRUMBLED(element) && !IS_MOVING(xx, yy))
1246 if (Feld[x][y] == EL_CUSTOM_START + 123)
1247 printf("::: crumble [%d] THE CHAOS ENGINE (%d, %d): %d, %d\n",
1248 i, Feld[x][y], element,
1249 GFX_CRUMBLED(element), IS_MOVING(x, y));
1252 if (i == 1 || i == 2)
1254 width = crumbled_border_size;
1256 cx = (i == 2 ? TILEX - crumbled_border_size : 0);
1262 height = crumbled_border_size;
1264 cy = (i == 3 ? TILEY - crumbled_border_size : 0);
1267 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1268 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
1271 MarkTileDirty(sx, sy);
1273 else /* crumble neighbour fields */
1276 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1279 for (i = 0; i < 4; i++)
1281 int xx = x + xy[i][0];
1282 int yy = y + xy[i][1];
1283 int sxx = sx + xy[i][0];
1284 int syy = sy + xy[i][1];
1286 if (!IN_LEV_FIELD(xx, yy) ||
1287 !IN_SCR_FIELD(sxx, syy) ||
1288 !GFX_CRUMBLED(Feld[xx][yy]) ||
1293 graphic = el_act2crm(Feld[xx][yy], ACTION_DEFAULT);
1294 crumbled_border_size = graphic_info[graphic].border_size;
1296 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1299 if (i == 1 || i == 2)
1301 width = crumbled_border_size;
1303 cx = (i == 1 ? TILEX - crumbled_border_size : 0);
1309 height = crumbled_border_size;
1311 cy = (i == 0 ? TILEY - crumbled_border_size : 0);
1314 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1315 width, height, FX + sxx * TILEX + cx, FY + syy * TILEY + cy);
1317 MarkTileDirty(sxx, syy);
1322 void DrawLevelFieldCrumbledSand(int x, int y)
1327 if (!IN_LEV_FIELD(x, y))
1330 graphic = el_act2crm(Feld[x][y], ACTION_DEFAULT);
1332 DrawLevelFieldCrumbledSandExt(x, y, graphic, 0);
1334 DrawLevelFieldCrumbledSandExt(x, y, IMG_SAND_CRUMBLED, 0);
1338 void DrawLevelFieldCrumbledSandDigging(int x, int y, int direction,
1342 int graphic1 = el_act_dir2img(GfxElement[x][y], ACTION_DIGGING, direction);
1343 int graphic2 = el_act_dir2crm(GfxElement[x][y], ACTION_DIGGING, direction);
1345 int graphic1 = el_act_dir2img(EL_SAND, ACTION_DIGGING, direction);
1346 int graphic2 = el_act_dir2img(EL_SAND_CRUMBLED, ACTION_DIGGING, direction);
1348 int frame1 = getGraphicAnimationFrame(graphic1, step_frame);
1349 int frame2 = getGraphicAnimationFrame(graphic2, step_frame);
1350 int sx = SCREENX(x), sy = SCREENY(y);
1352 DrawGraphic(sx, sy, graphic1, frame1);
1353 DrawLevelFieldCrumbledSandExt(x, y, graphic2, frame2);
1356 void DrawLevelFieldCrumbledSandNeighbours(int x, int y)
1358 int sx = SCREENX(x), sy = SCREENY(y);
1359 static int xy[4][2] =
1368 for (i = 0; i < 4; i++)
1370 int xx = x + xy[i][0];
1371 int yy = y + xy[i][1];
1372 int sxx = sx + xy[i][0];
1373 int syy = sy + xy[i][1];
1375 if (!IN_LEV_FIELD(xx, yy) ||
1376 !IN_SCR_FIELD(sxx, syy) ||
1377 !GFX_CRUMBLED(Feld[xx][yy]) ||
1381 DrawLevelField(xx, yy);
1385 static int getBorderElement(int x, int y)
1389 { EL_STEELWALL_TOPLEFT, EL_INVISIBLE_STEELWALL_TOPLEFT },
1390 { EL_STEELWALL_TOPRIGHT, EL_INVISIBLE_STEELWALL_TOPRIGHT },
1391 { EL_STEELWALL_BOTTOMLEFT, EL_INVISIBLE_STEELWALL_BOTTOMLEFT },
1392 { EL_STEELWALL_BOTTOMRIGHT, EL_INVISIBLE_STEELWALL_BOTTOMRIGHT },
1393 { EL_STEELWALL_VERTICAL, EL_INVISIBLE_STEELWALL_VERTICAL },
1394 { EL_STEELWALL_HORIZONTAL, EL_INVISIBLE_STEELWALL_HORIZONTAL },
1395 { EL_STEELWALL, EL_INVISIBLE_STEELWALL }
1397 int steel_type = (BorderElement == EL_STEELWALL ? 0 : 1);
1398 int steel_position = (x == -1 && y == -1 ? 0 :
1399 x == lev_fieldx && y == -1 ? 1 :
1400 x == -1 && y == lev_fieldy ? 2 :
1401 x == lev_fieldx && y == lev_fieldy ? 3 :
1402 x == -1 || x == lev_fieldx ? 4 :
1403 y == -1 || y == lev_fieldy ? 5 : 6);
1405 return border[steel_position][steel_type];
1408 void DrawScreenElement(int x, int y, int element)
1410 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
1411 DrawLevelFieldCrumbledSand(LEVELX(x), LEVELY(y));
1414 void DrawLevelElement(int x, int y, int element)
1416 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1417 DrawScreenElement(SCREENX(x), SCREENY(y), element);
1420 void DrawScreenField(int x, int y)
1422 int lx = LEVELX(x), ly = LEVELY(y);
1423 int element, content;
1425 if (!IN_LEV_FIELD(lx, ly))
1427 if (lx < -1 || lx > lev_fieldx || ly < -1 || ly > lev_fieldy)
1430 element = getBorderElement(lx, ly);
1432 DrawScreenElement(x, y, element);
1436 element = Feld[lx][ly];
1437 content = Store[lx][ly];
1439 if (IS_MOVING(lx, ly))
1441 int horiz_move = (MovDir[lx][ly] == MV_LEFT || MovDir[lx][ly] == MV_RIGHT);
1442 boolean cut_mode = NO_CUTTING;
1444 if (element == EL_QUICKSAND_EMPTYING ||
1445 element == EL_MAGIC_WALL_EMPTYING ||
1446 element == EL_BD_MAGIC_WALL_EMPTYING ||
1447 element == EL_AMOEBA_DROPPING)
1448 cut_mode = CUT_ABOVE;
1449 else if (element == EL_QUICKSAND_FILLING ||
1450 element == EL_MAGIC_WALL_FILLING ||
1451 element == EL_BD_MAGIC_WALL_FILLING)
1452 cut_mode = CUT_BELOW;
1454 if (cut_mode == CUT_ABOVE)
1455 DrawScreenElementShifted(x, y, 0, 0, element, NO_CUTTING);
1457 DrawScreenElement(x, y, EL_EMPTY);
1460 DrawScreenElementShifted(x, y, MovPos[lx][ly], 0, element, NO_CUTTING);
1461 else if (cut_mode == NO_CUTTING)
1462 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], element, cut_mode);
1464 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], content, cut_mode);
1466 if (content == EL_ACID)
1467 DrawLevelElementThruMask(lx, ly + 1, EL_ACID);
1469 else if (IS_BLOCKED(lx, ly))
1474 boolean cut_mode = NO_CUTTING;
1475 int element_old, content_old;
1477 Blocked2Moving(lx, ly, &oldx, &oldy);
1480 horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
1481 MovDir[oldx][oldy] == MV_RIGHT);
1483 element_old = Feld[oldx][oldy];
1484 content_old = Store[oldx][oldy];
1486 if (element_old == EL_QUICKSAND_EMPTYING ||
1487 element_old == EL_MAGIC_WALL_EMPTYING ||
1488 element_old == EL_BD_MAGIC_WALL_EMPTYING ||
1489 element_old == EL_AMOEBA_DROPPING)
1490 cut_mode = CUT_ABOVE;
1492 DrawScreenElement(x, y, EL_EMPTY);
1495 DrawScreenElementShifted(sx, sy, MovPos[oldx][oldy], 0, element_old,
1497 else if (cut_mode == NO_CUTTING)
1498 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], element_old,
1501 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], content_old,
1504 else if (IS_DRAWABLE(element))
1505 DrawScreenElement(x, y, element);
1507 DrawScreenElement(x, y, EL_EMPTY);
1510 void DrawLevelField(int x, int y)
1512 if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1513 DrawScreenField(SCREENX(x), SCREENY(y));
1514 else if (IS_MOVING(x, y))
1518 Moving2Blocked(x, y, &newx, &newy);
1519 if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
1520 DrawScreenField(SCREENX(newx), SCREENY(newy));
1522 else if (IS_BLOCKED(x, y))
1526 Blocked2Moving(x, y, &oldx, &oldy);
1527 if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
1528 DrawScreenField(SCREENX(oldx), SCREENY(oldy));
1532 void DrawMiniElement(int x, int y, int element)
1536 graphic = el2edimg(element);
1537 DrawMiniGraphic(x, y, graphic);
1540 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
1542 int x = sx + scroll_x, y = sy + scroll_y;
1544 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
1545 DrawMiniElement(sx, sy, EL_EMPTY);
1546 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
1547 DrawMiniElement(sx, sy, Feld[x][y]);
1549 DrawMiniGraphic(sx, sy, el2edimg(getBorderElement(x, y)));
1552 void DrawEnvelopeBackground(int envelope_nr, int startx, int starty,
1553 int x, int y, int xsize, int ysize, int font_nr)
1555 int font_width = getFontWidth(font_nr);
1556 int font_height = getFontHeight(font_nr);
1557 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1560 int dst_x = SX + startx + x * font_width;
1561 int dst_y = SY + starty + y * font_height;
1562 int width = graphic_info[graphic].width;
1563 int height = graphic_info[graphic].height;
1564 int inner_width = MAX(width - 2 * font_width, font_width);
1565 int inner_height = MAX(height - 2 * font_height, font_height);
1566 int inner_sx = (width >= 3 * font_width ? font_width : 0);
1567 int inner_sy = (height >= 3 * font_height ? font_height : 0);
1568 boolean draw_masked = graphic_info[graphic].draw_masked;
1570 getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
1572 if (src_bitmap == NULL || width < font_width || height < font_height)
1574 ClearRectangle(drawto, dst_x, dst_y, font_width, font_height);
1578 src_x += (x == 0 ? 0 : x == xsize - 1 ? width - font_width :
1579 inner_sx + (x - 1) * font_width % inner_width);
1580 src_y += (y == 0 ? 0 : y == ysize - 1 ? height - font_height :
1581 inner_sy + (y - 1) * font_height % inner_height);
1585 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1586 dst_x - src_x, dst_y - src_y);
1587 BlitBitmapMasked(src_bitmap, drawto, src_x, src_y, font_width, font_height,
1591 BlitBitmap(src_bitmap, drawto, src_x, src_y, font_width, font_height,
1595 void AnimateEnvelope(int envelope_nr, int anim_mode, int action)
1597 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1598 boolean draw_masked = graphic_info[graphic].draw_masked;
1599 int mask_mode = (draw_masked ? BLIT_MASKED : BLIT_ON_BACKGROUND);
1600 boolean ffwd_delay = (tape.playing && tape.fast_forward);
1601 unsigned long anim_delay = 0;
1602 int anim_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
1603 int font_nr = FONT_ENVELOPE_1 + envelope_nr;
1604 int font_width = getFontWidth(font_nr);
1605 int font_height = getFontHeight(font_nr);
1606 int max_xsize = level.envelope_xsize[envelope_nr];
1607 int max_ysize = level.envelope_ysize[envelope_nr];
1608 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize : 0);
1609 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize : 0);
1610 int xend = max_xsize;
1611 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize : 0);
1612 int xstep = (xstart < xend ? 1 : 0);
1613 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
1616 for (x = xstart, y = ystart; x <= xend && y <= yend; x += xstep, y += ystep)
1618 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
1619 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
1620 int sx = (SXSIZE - xsize * font_width) / 2;
1621 int sy = (SYSIZE - ysize * font_height) / 2;
1624 SetDrawtoField(DRAW_BUFFERED);
1626 BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
1628 SetDrawtoField(DRAW_BACKBUFFER);
1630 for (yy = 0; yy < ysize; yy++) for (xx = 0; xx < xsize; xx++)
1631 DrawEnvelopeBackground(envelope_nr, sx,sy, xx,yy, xsize, ysize, font_nr);
1633 DrawTextToTextArea(SX + sx + font_width, SY + sy + font_height,
1634 level.envelope_text[envelope_nr], font_nr, max_xsize,
1635 xsize - 2, ysize - 2, mask_mode);
1637 redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
1640 WaitUntilDelayReached(&anim_delay, anim_delay_value / 2);
1644 void ShowEnvelope(int envelope_nr)
1646 int element = EL_ENVELOPE_1 + envelope_nr;
1647 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1648 int sound_opening = element_info[element].sound[ACTION_OPENING];
1649 int sound_closing = element_info[element].sound[ACTION_CLOSING];
1650 boolean ffwd_delay = (tape.playing && tape.fast_forward);
1651 int wait_delay_value = (ffwd_delay ? 500 : 1000);
1652 int anim_mode = graphic_info[graphic].anim_mode;
1653 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
1654 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
1656 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
1658 PlaySoundStereo(sound_opening, SOUND_MIDDLE);
1660 if (anim_mode == ANIM_DEFAULT)
1661 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_OPENING);
1663 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_OPENING);
1666 Delay(wait_delay_value);
1668 WaitForEventToContinue();
1670 PlaySoundStereo(sound_closing, SOUND_MIDDLE);
1672 if (anim_mode != ANIM_NONE)
1673 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_CLOSING);
1675 if (anim_mode == ANIM_DEFAULT)
1676 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_CLOSING);
1678 game.envelope_active = FALSE;
1680 SetDrawtoField(DRAW_BUFFERED);
1682 redraw_mask |= REDRAW_FIELD;
1686 void getMicroGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
1688 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
1689 int mini_startx = src_bitmap->width * 3 / 4;
1690 int mini_starty = src_bitmap->height * 2 / 3;
1691 int src_x = mini_startx + graphic_info[graphic].src_x / 8;
1692 int src_y = mini_starty + graphic_info[graphic].src_y / 8;
1694 *bitmap = src_bitmap;
1699 void DrawMicroElement(int xpos, int ypos, int element)
1703 int graphic = el2preimg(element);
1705 getMicroGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
1706 BlitBitmap(src_bitmap, drawto, src_x, src_y, MICRO_TILEX, MICRO_TILEY,
1714 SetDrawBackgroundMask(REDRAW_NONE);
1717 for (x = BX1; x <= BX2; x++)
1718 for (y = BY1; y <= BY2; y++)
1719 DrawScreenField(x, y);
1721 redraw_mask |= REDRAW_FIELD;
1724 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
1728 for (x = 0; x < size_x; x++)
1729 for (y = 0; y < size_y; y++)
1730 DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
1732 redraw_mask |= REDRAW_FIELD;
1735 static void DrawMicroLevelExt(int xpos, int ypos, int from_x, int from_y)
1739 DrawBackground(xpos, ypos, MICROLEV_XSIZE, MICROLEV_YSIZE);
1741 if (lev_fieldx < STD_LEV_FIELDX)
1742 xpos += (STD_LEV_FIELDX - lev_fieldx) / 2 * MICRO_TILEX;
1743 if (lev_fieldy < STD_LEV_FIELDY)
1744 ypos += (STD_LEV_FIELDY - lev_fieldy) / 2 * MICRO_TILEY;
1746 xpos += MICRO_TILEX;
1747 ypos += MICRO_TILEY;
1749 for (x = -1; x <= STD_LEV_FIELDX; x++)
1751 for (y = -1; y <= STD_LEV_FIELDY; y++)
1753 int lx = from_x + x, ly = from_y + y;
1755 if (lx >= 0 && lx < lev_fieldx && ly >= 0 && ly < lev_fieldy)
1756 DrawMicroElement(xpos + x * MICRO_TILEX, ypos + y * MICRO_TILEY,
1757 level.field[lx][ly]);
1758 else if (lx >= -1 && lx < lev_fieldx+1 && ly >= -1 && ly < lev_fieldy+1
1759 && BorderElement != EL_EMPTY)
1760 DrawMicroElement(xpos + x * MICRO_TILEX, ypos + y * MICRO_TILEY,
1761 getBorderElement(lx, ly));
1765 redraw_mask |= REDRAW_MICROLEVEL;
1768 #define MICROLABEL_EMPTY 0
1769 #define MICROLABEL_LEVEL_NAME 1
1770 #define MICROLABEL_CREATED_BY 2
1771 #define MICROLABEL_LEVEL_AUTHOR 3
1772 #define MICROLABEL_IMPORTED_FROM 4
1773 #define MICROLABEL_LEVEL_IMPORT_INFO 5
1775 static void DrawMicroLevelLabelExt(int mode)
1777 char label_text[MAX_OUTPUT_LINESIZE + 1];
1778 int max_len_label_text;
1779 int font_nr = FONT_TEXT_2;
1781 if (mode == MICROLABEL_CREATED_BY || mode == MICROLABEL_IMPORTED_FROM)
1782 font_nr = FONT_TEXT_3;
1784 max_len_label_text = SXSIZE / getFontWidth(font_nr);
1786 DrawBackground(SX, MICROLABEL_YPOS, SXSIZE, getFontHeight(font_nr));
1788 strncpy(label_text, (mode == MICROLABEL_LEVEL_NAME ? level.name :
1789 mode == MICROLABEL_CREATED_BY ? "created by" :
1790 mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
1791 mode == MICROLABEL_IMPORTED_FROM ? "imported from" :
1792 mode == MICROLABEL_LEVEL_IMPORT_INFO ?
1793 leveldir_current->imported_from : ""),
1794 max_len_label_text);
1795 label_text[max_len_label_text] = '\0';
1797 if (strlen(label_text) > 0)
1799 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
1800 int lypos = MICROLABEL_YPOS;
1802 DrawText(lxpos, lypos, label_text, font_nr);
1805 redraw_mask |= REDRAW_MICROLEVEL;
1808 void DrawMicroLevel(int xpos, int ypos, boolean restart)
1810 static unsigned long scroll_delay = 0;
1811 static unsigned long label_delay = 0;
1812 static int from_x, from_y, scroll_direction;
1813 static int label_state, label_counter;
1814 int last_game_status = game_status; /* save current game status */
1816 /* force PREVIEW font on preview level */
1817 game_status = GAME_MODE_PSEUDO_PREVIEW;
1821 from_x = from_y = 0;
1822 scroll_direction = MV_RIGHT;
1826 DrawMicroLevelExt(xpos, ypos, from_x, from_y);
1827 DrawMicroLevelLabelExt(label_state);
1829 /* initialize delay counters */
1830 DelayReached(&scroll_delay, 0);
1831 DelayReached(&label_delay, 0);
1833 if (leveldir_current->name)
1835 int text_width = getTextWidth(leveldir_current->name, FONT_TEXT_1);
1836 int lxpos = SX + (SXSIZE - text_width) / 2;
1837 int lypos = SY + 352;
1839 DrawText(lxpos, lypos, leveldir_current->name, FONT_TEXT_1);
1842 game_status = last_game_status; /* restore current game status */
1847 /* scroll micro level, if needed */
1848 if ((lev_fieldx > STD_LEV_FIELDX || lev_fieldy > STD_LEV_FIELDY) &&
1849 DelayReached(&scroll_delay, MICROLEVEL_SCROLL_DELAY))
1851 switch (scroll_direction)
1857 scroll_direction = MV_UP;
1861 if (from_x < lev_fieldx - STD_LEV_FIELDX)
1864 scroll_direction = MV_DOWN;
1871 scroll_direction = MV_RIGHT;
1875 if (from_y < lev_fieldy - STD_LEV_FIELDY)
1878 scroll_direction = MV_LEFT;
1885 DrawMicroLevelExt(xpos, ypos, from_x, from_y);
1888 /* redraw micro level label, if needed */
1889 if (strcmp(level.name, NAMELESS_LEVEL_NAME) != 0 &&
1890 strcmp(level.author, ANONYMOUS_NAME) != 0 &&
1891 strcmp(level.author, leveldir_current->name) != 0 &&
1892 DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
1894 int max_label_counter = 23;
1896 if (leveldir_current->imported_from != NULL)
1897 max_label_counter += 14;
1899 label_counter = (label_counter + 1) % max_label_counter;
1900 label_state = (label_counter >= 0 && label_counter <= 7 ?
1901 MICROLABEL_LEVEL_NAME :
1902 label_counter >= 9 && label_counter <= 12 ?
1903 MICROLABEL_CREATED_BY :
1904 label_counter >= 14 && label_counter <= 21 ?
1905 MICROLABEL_LEVEL_AUTHOR :
1906 label_counter >= 23 && label_counter <= 26 ?
1907 MICROLABEL_IMPORTED_FROM :
1908 label_counter >= 28 && label_counter <= 35 ?
1909 MICROLABEL_LEVEL_IMPORT_INFO : MICROLABEL_EMPTY);
1910 DrawMicroLevelLabelExt(label_state);
1913 game_status = last_game_status; /* restore current game status */
1916 void WaitForEventToContinue()
1918 boolean still_wait = TRUE;
1920 /* simulate releasing mouse button over last gadget, if still pressed */
1922 HandleGadgets(-1, -1, 0);
1924 button_status = MB_RELEASED;
1936 case EVENT_BUTTONPRESS:
1937 case EVENT_KEYPRESS:
1941 case EVENT_KEYRELEASE:
1942 ClearPlayerAction();
1946 HandleOtherEvents(&event);
1950 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
1957 /* don't eat all CPU time */
1962 #define MAX_REQUEST_LINES 13
1963 #define MAX_REQUEST_LINE_FONT1_LEN 7
1964 #define MAX_REQUEST_LINE_FONT2_LEN 10
1966 boolean Request(char *text, unsigned int req_state)
1968 int mx, my, ty, result = -1;
1969 unsigned int old_door_state;
1970 int last_game_status = game_status; /* save current game status */
1971 int max_request_line_len = MAX_REQUEST_LINE_FONT1_LEN;
1972 int font_nr = FONT_TEXT_2;
1973 int max_word_len = 0;
1976 for (text_ptr = text; *text_ptr; text_ptr++)
1978 max_word_len = (*text_ptr != ' ' ? max_word_len + 1 : 0);
1980 if (max_word_len > MAX_REQUEST_LINE_FONT1_LEN)
1982 max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
1983 font_nr = FONT_LEVEL_NUMBER;
1990 SetMouseCursor(CURSOR_DEFAULT);
1993 #if defined(PLATFORM_UNIX)
1994 /* pause network game while waiting for request to answer */
1995 if (options.network &&
1996 game_status == GAME_MODE_PLAYING &&
1997 req_state & REQUEST_WAIT_FOR)
1998 SendToServer_PausePlaying();
2001 old_door_state = GetDoorState();
2003 /* simulate releasing mouse button over last gadget, if still pressed */
2005 HandleGadgets(-1, -1, 0);
2009 CloseDoor(DOOR_CLOSE_1);
2011 /* save old door content */
2012 BlitBitmap(bitmap_db_door, bitmap_db_door,
2013 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
2014 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
2016 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
2018 /* clear door drawing field */
2019 DrawBackground(DX, DY, DXSIZE, DYSIZE);
2021 /* force DOOR font on preview level */
2022 game_status = GAME_MODE_PSEUDO_DOOR;
2024 /* write text for request */
2025 for (ty = 0; ty < MAX_REQUEST_LINES; ty++)
2027 char text_line[max_request_line_len + 1];
2033 for (tl = 0, tx = 0; tx < max_request_line_len; tl++, tx++)
2036 if (!tc || tc == ' ')
2047 strncpy(text_line, text, tl);
2050 DrawText(DX + (DXSIZE - tl * getFontWidth(font_nr)) / 2,
2051 DY + 8 + ty * (getFontHeight(font_nr) + 2),
2052 text_line, font_nr);
2054 text += tl + (tc == ' ' ? 1 : 0);
2057 game_status = last_game_status; /* restore current game status */
2059 if (req_state & REQ_ASK)
2061 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
2062 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
2064 else if (req_state & REQ_CONFIRM)
2066 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
2068 else if (req_state & REQ_PLAYER)
2070 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
2071 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
2072 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
2073 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
2076 /* copy request gadgets to door backbuffer */
2077 BlitBitmap(drawto, bitmap_db_door,
2078 DX, DY, DXSIZE, DYSIZE,
2079 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2081 OpenDoor(DOOR_OPEN_1);
2087 if (!(req_state & REQUEST_WAIT_FOR))
2089 SetDrawBackgroundMask(REDRAW_FIELD);
2094 if (game_status != GAME_MODE_MAIN)
2097 button_status = MB_RELEASED;
2099 request_gadget_id = -1;
2101 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
2104 SetMouseCursor(CURSOR_DEFAULT);
2117 case EVENT_BUTTONPRESS:
2118 case EVENT_BUTTONRELEASE:
2119 case EVENT_MOTIONNOTIFY:
2121 if (event.type == EVENT_MOTIONNOTIFY)
2123 if (!PointerInWindow(window))
2124 continue; /* window and pointer are on different screens */
2129 motion_status = TRUE;
2130 mx = ((MotionEvent *) &event)->x;
2131 my = ((MotionEvent *) &event)->y;
2135 motion_status = FALSE;
2136 mx = ((ButtonEvent *) &event)->x;
2137 my = ((ButtonEvent *) &event)->y;
2138 if (event.type == EVENT_BUTTONPRESS)
2139 button_status = ((ButtonEvent *) &event)->button;
2141 button_status = MB_RELEASED;
2144 /* this sets 'request_gadget_id' */
2145 HandleGadgets(mx, my, button_status);
2147 switch(request_gadget_id)
2149 case TOOL_CTRL_ID_YES:
2152 case TOOL_CTRL_ID_NO:
2155 case TOOL_CTRL_ID_CONFIRM:
2156 result = TRUE | FALSE;
2159 case TOOL_CTRL_ID_PLAYER_1:
2162 case TOOL_CTRL_ID_PLAYER_2:
2165 case TOOL_CTRL_ID_PLAYER_3:
2168 case TOOL_CTRL_ID_PLAYER_4:
2179 case EVENT_KEYPRESS:
2180 switch(GetEventKey((KeyEvent *)&event, TRUE))
2193 if (req_state & REQ_PLAYER)
2197 case EVENT_KEYRELEASE:
2198 ClearPlayerAction();
2202 HandleOtherEvents(&event);
2206 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
2208 int joy = AnyJoystick();
2210 if (joy & JOY_BUTTON_1)
2212 else if (joy & JOY_BUTTON_2)
2218 /* don't eat all CPU time */
2222 if (game_status != GAME_MODE_MAIN)
2227 if (!(req_state & REQ_STAY_OPEN))
2229 CloseDoor(DOOR_CLOSE_1);
2231 if (!(req_state & REQ_STAY_CLOSED) && (old_door_state & DOOR_OPEN_1))
2233 BlitBitmap(bitmap_db_door, bitmap_db_door,
2234 DOOR_GFX_PAGEX2,DOOR_GFX_PAGEY1, DXSIZE,DYSIZE,
2235 DOOR_GFX_PAGEX1,DOOR_GFX_PAGEY1);
2236 OpenDoor(DOOR_OPEN_1);
2242 SetDrawBackgroundMask(REDRAW_FIELD);
2244 #if defined(PLATFORM_UNIX)
2245 /* continue network game after request */
2246 if (options.network &&
2247 game_status == GAME_MODE_PLAYING &&
2248 req_state & REQUEST_WAIT_FOR)
2249 SendToServer_ContinuePlaying();
2255 unsigned int OpenDoor(unsigned int door_state)
2257 unsigned int new_door_state;
2259 if (door_state & DOOR_COPY_BACK)
2261 BlitBitmap(bitmap_db_door, bitmap_db_door,
2262 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE + VYSIZE,
2263 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2264 door_state &= ~DOOR_COPY_BACK;
2267 new_door_state = MoveDoor(door_state);
2269 return(new_door_state);
2272 unsigned int CloseDoor(unsigned int door_state)
2274 unsigned int new_door_state;
2276 BlitBitmap(backbuffer, bitmap_db_door,
2277 DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2278 BlitBitmap(backbuffer, bitmap_db_door,
2279 VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
2281 new_door_state = MoveDoor(door_state);
2283 return(new_door_state);
2286 unsigned int GetDoorState()
2288 return MoveDoor(DOOR_GET_STATE);
2291 unsigned int SetDoorState(unsigned int door_state)
2293 return MoveDoor(door_state | DOOR_SET_STATE);
2296 unsigned int MoveDoor(unsigned int door_state)
2298 static int door1 = DOOR_OPEN_1;
2299 static int door2 = DOOR_CLOSE_2;
2300 unsigned long door_delay = 0;
2301 unsigned long door_delay_value;
2304 if (door_state == DOOR_GET_STATE)
2305 return(door1 | door2);
2307 if (door_state & DOOR_SET_STATE)
2309 if (door_state & DOOR_ACTION_1)
2310 door1 = door_state & DOOR_ACTION_1;
2311 if (door_state & DOOR_ACTION_2)
2312 door2 = door_state & DOOR_ACTION_2;
2314 return(door1 | door2);
2317 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
2318 door_state &= ~DOOR_OPEN_1;
2319 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
2320 door_state &= ~DOOR_CLOSE_1;
2321 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
2322 door_state &= ~DOOR_OPEN_2;
2323 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
2324 door_state &= ~DOOR_CLOSE_2;
2326 door_delay_value = (door_state & DOOR_ACTION_1 ? door_1.step_delay :
2329 if (setup.quick_doors)
2331 stepsize = 20; /* must be choosen to always draw last frame */
2332 door_delay_value = 0;
2334 StopSound(SND_DOOR_OPENING);
2335 StopSound(SND_DOOR_CLOSING);
2338 if (global.autoplay_leveldir)
2340 door_state |= DOOR_NO_DELAY;
2341 door_state &= ~DOOR_CLOSE_ALL;
2344 if (door_state & DOOR_ACTION)
2346 boolean door_1_done = !(door_state & DOOR_ACTION_1);
2347 boolean door_2_done = !(door_state & DOOR_ACTION_2);
2348 int start = ((door_state & DOOR_NO_DELAY) ? DXSIZE : 0);
2349 int end = (door_state & DOOR_ACTION_1 &&
2350 door_1.anim_mode == ANIM_VERTICAL ? DYSIZE : DXSIZE);
2353 if (!(door_state & DOOR_NO_DELAY))
2355 /* opening door sound has priority over simultaneously closing door */
2356 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
2357 PlaySoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
2358 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
2359 PlaySoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
2362 for (x = start; x <= end && !(door_1_done && door_2_done); x += stepsize)
2364 Bitmap *bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
2365 GC gc = bitmap->stored_clip_gc;
2367 if (door_state & DOOR_ACTION_1)
2369 int a = MIN(x * door_1.step_offset, end);
2370 int i = (door_state & DOOR_OPEN_1 ? end - a : a);
2374 BlitBitmap(bitmap_db_door, drawto,
2375 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + i / 2,
2376 DXSIZE,DYSIZE - i / 2, DX, DY);
2378 ClearRectangle(drawto, DX, DY + DYSIZE - i / 2, DXSIZE, i / 2);
2381 if (door_1.anim_mode == ANIM_HORIZONTAL && x <= DXSIZE)
2383 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
2384 int dst1_x = DX + DXSIZE - i, dst1_y = DY;
2385 int src2_x = DXSIZE - i, src2_y = DOOR_GFX_PAGEY1;
2386 int dst2_x = DX, dst2_y = DY;
2387 int width = i, height = DYSIZE;
2389 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2390 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2393 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2394 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2397 else if (door_1.anim_mode == ANIM_VERTICAL && x <= DYSIZE)
2399 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
2400 int dst1_x = DX, dst1_y = DY + DYSIZE - i;
2401 int src2_x = 0, src2_y = DOOR_GFX_PAGEY1 + DYSIZE - i;
2402 int dst2_x = DX, dst2_y = DY;
2403 int width = DXSIZE, height = i;
2405 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2406 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2409 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2410 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2413 else if (x <= DXSIZE) /* ANIM_DEFAULT */
2415 int j = (door_1.anim_mode == ANIM_DEFAULT ? (DXSIZE - i) / 3 : 0);
2417 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2418 BlitBitmapMasked(bitmap, drawto,
2419 DXSIZE, DOOR_GFX_PAGEY1, i, 77,
2420 DX + DXSIZE - i, DY + j);
2421 BlitBitmapMasked(bitmap, drawto,
2422 DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63,
2423 DX + DXSIZE - i, DY + 140 + j);
2424 SetClipOrigin(bitmap, gc, DX - DXSIZE + i,
2425 DY - (DOOR_GFX_PAGEY1 + j));
2426 BlitBitmapMasked(bitmap, drawto,
2427 DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j,
2429 BlitBitmapMasked(bitmap, drawto,
2430 DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63,
2433 BlitBitmapMasked(bitmap, drawto,
2434 DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
2436 BlitBitmapMasked(bitmap, drawto,
2437 DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
2439 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2440 BlitBitmapMasked(bitmap, drawto,
2441 DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
2442 DX + DXSIZE - i, DY + 77 + j);
2443 BlitBitmapMasked(bitmap, drawto,
2444 DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
2445 DX + DXSIZE - i, DY + 203 + j);
2448 redraw_mask |= REDRAW_DOOR_1;
2449 door_1_done = (a == end);
2452 if (door_state & DOOR_ACTION_2)
2454 int a = MIN(x * door_2.step_offset, VXSIZE);
2455 int i = (door_state & DOOR_OPEN_2 ? VXSIZE - a : a);
2459 BlitBitmap(bitmap_db_door, drawto,
2460 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + i / 2,
2461 VXSIZE, VYSIZE - i / 2, VX, VY);
2463 ClearRectangle(drawto, VX, VY + VYSIZE - i / 2, VXSIZE, i / 2);
2466 if (door_2.anim_mode == ANIM_HORIZONTAL && x <= VXSIZE)
2468 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
2469 int dst1_x = VX + VXSIZE - i, dst1_y = VY;
2470 int src2_x = VXSIZE - i, src2_y = DOOR_GFX_PAGEY2;
2471 int dst2_x = VX, dst2_y = VY;
2472 int width = i, height = VYSIZE;
2474 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2475 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2478 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2479 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2482 else if (door_2.anim_mode == ANIM_VERTICAL && x <= VYSIZE)
2484 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
2485 int dst1_x = VX, dst1_y = VY + VYSIZE - i;
2486 int src2_x = 0, src2_y = DOOR_GFX_PAGEY2 + VYSIZE - i;
2487 int dst2_x = VX, dst2_y = VY;
2488 int width = VXSIZE, height = i;
2490 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2491 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2494 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2495 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2498 else if (x <= VXSIZE) /* ANIM_DEFAULT */
2500 int j = (door_2.anim_mode == ANIM_DEFAULT ? (VXSIZE - i) / 3 : 0);
2502 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2503 BlitBitmapMasked(bitmap, drawto,
2504 VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2,
2505 VX + VXSIZE - i, VY + j);
2506 SetClipOrigin(bitmap, gc,
2507 VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
2508 BlitBitmapMasked(bitmap, drawto,
2509 VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j,
2512 BlitBitmapMasked(bitmap, drawto,
2513 VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2,
2514 i, VYSIZE / 2, VX, VY + VYSIZE / 2 - j);
2515 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2516 BlitBitmapMasked(bitmap, drawto,
2517 VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2,
2519 VX + VXSIZE - i, VY + VYSIZE / 2 + j);
2522 redraw_mask |= REDRAW_DOOR_2;
2523 door_2_done = (a == VXSIZE);
2528 if (game_status == GAME_MODE_MAIN)
2531 if (!(door_state & DOOR_NO_DELAY))
2532 WaitUntilDelayReached(&door_delay, door_delay_value);
2536 if (setup.quick_doors)
2538 StopSound(SND_DOOR_OPENING);
2539 StopSound(SND_DOOR_CLOSING);
2542 if (door_state & DOOR_ACTION_1)
2543 door1 = door_state & DOOR_ACTION_1;
2544 if (door_state & DOOR_ACTION_2)
2545 door2 = door_state & DOOR_ACTION_2;
2547 return (door1 | door2);
2550 void DrawSpecialEditorDoor()
2552 /* draw bigger toolbox window */
2553 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
2554 DOOR_GFX_PAGEX7, 0, EXSIZE + 8, 8,
2556 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
2557 EX - 4, VY - 4, EXSIZE + 8, EYSIZE - VYSIZE + 4,
2560 redraw_mask |= REDRAW_ALL;
2563 void UndrawSpecialEditorDoor()
2565 /* draw normal tape recorder window */
2566 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
2567 EX - 4, EY - 12, EXSIZE + 8, EYSIZE - VYSIZE + 12,
2570 redraw_mask |= REDRAW_ALL;
2574 /* ---------- new tool button stuff ---------------------------------------- */
2576 /* graphic position values for tool buttons */
2577 #define TOOL_BUTTON_YES_XPOS 2
2578 #define TOOL_BUTTON_YES_YPOS 250
2579 #define TOOL_BUTTON_YES_GFX_YPOS 0
2580 #define TOOL_BUTTON_YES_XSIZE 46
2581 #define TOOL_BUTTON_YES_YSIZE 28
2582 #define TOOL_BUTTON_NO_XPOS 52
2583 #define TOOL_BUTTON_NO_YPOS TOOL_BUTTON_YES_YPOS
2584 #define TOOL_BUTTON_NO_GFX_YPOS TOOL_BUTTON_YES_GFX_YPOS
2585 #define TOOL_BUTTON_NO_XSIZE TOOL_BUTTON_YES_XSIZE
2586 #define TOOL_BUTTON_NO_YSIZE TOOL_BUTTON_YES_YSIZE
2587 #define TOOL_BUTTON_CONFIRM_XPOS TOOL_BUTTON_YES_XPOS
2588 #define TOOL_BUTTON_CONFIRM_YPOS TOOL_BUTTON_YES_YPOS
2589 #define TOOL_BUTTON_CONFIRM_GFX_YPOS 30
2590 #define TOOL_BUTTON_CONFIRM_XSIZE 96
2591 #define TOOL_BUTTON_CONFIRM_YSIZE TOOL_BUTTON_YES_YSIZE
2592 #define TOOL_BUTTON_PLAYER_XSIZE 30
2593 #define TOOL_BUTTON_PLAYER_YSIZE 30
2594 #define TOOL_BUTTON_PLAYER_GFX_XPOS 5
2595 #define TOOL_BUTTON_PLAYER_GFX_YPOS 185
2596 #define TOOL_BUTTON_PLAYER_XPOS (5 + TOOL_BUTTON_PLAYER_XSIZE / 2)
2597 #define TOOL_BUTTON_PLAYER_YPOS (215 - TOOL_BUTTON_PLAYER_YSIZE / 2)
2598 #define TOOL_BUTTON_PLAYER1_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2599 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2600 #define TOOL_BUTTON_PLAYER2_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2601 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2602 #define TOOL_BUTTON_PLAYER3_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2603 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2604 #define TOOL_BUTTON_PLAYER4_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2605 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2606 #define TOOL_BUTTON_PLAYER1_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2607 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2608 #define TOOL_BUTTON_PLAYER2_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2609 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2610 #define TOOL_BUTTON_PLAYER3_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2611 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2612 #define TOOL_BUTTON_PLAYER4_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2613 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2622 } toolbutton_info[NUM_TOOL_BUTTONS] =
2625 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_GFX_YPOS,
2626 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_YPOS,
2627 TOOL_BUTTON_YES_XSIZE, TOOL_BUTTON_YES_YSIZE,
2632 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_GFX_YPOS,
2633 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_YPOS,
2634 TOOL_BUTTON_NO_XSIZE, TOOL_BUTTON_NO_YSIZE,
2639 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_GFX_YPOS,
2640 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_YPOS,
2641 TOOL_BUTTON_CONFIRM_XSIZE, TOOL_BUTTON_CONFIRM_YSIZE,
2642 TOOL_CTRL_ID_CONFIRM,
2646 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2647 TOOL_BUTTON_PLAYER1_XPOS, TOOL_BUTTON_PLAYER1_YPOS,
2648 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2649 TOOL_CTRL_ID_PLAYER_1,
2653 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2654 TOOL_BUTTON_PLAYER2_XPOS, TOOL_BUTTON_PLAYER2_YPOS,
2655 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2656 TOOL_CTRL_ID_PLAYER_2,
2660 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2661 TOOL_BUTTON_PLAYER3_XPOS, TOOL_BUTTON_PLAYER3_YPOS,
2662 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2663 TOOL_CTRL_ID_PLAYER_3,
2667 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2668 TOOL_BUTTON_PLAYER4_XPOS, TOOL_BUTTON_PLAYER4_YPOS,
2669 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2670 TOOL_CTRL_ID_PLAYER_4,
2675 void CreateToolButtons()
2679 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
2681 Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
2682 Bitmap *deco_bitmap = None;
2683 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
2684 struct GadgetInfo *gi;
2685 unsigned long event_mask;
2686 int gd_xoffset, gd_yoffset;
2687 int gd_x1, gd_x2, gd_y;
2690 event_mask = GD_EVENT_RELEASED;
2692 gd_xoffset = toolbutton_info[i].xpos;
2693 gd_yoffset = toolbutton_info[i].ypos;
2694 gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
2695 gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
2696 gd_y = DOOR_GFX_PAGEY1 + gd_yoffset;
2698 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
2700 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
2702 getMiniGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr),
2703 &deco_bitmap, &deco_x, &deco_y);
2704 deco_xpos = (toolbutton_info[i].width - MINI_TILEX) / 2;
2705 deco_ypos = (toolbutton_info[i].height - MINI_TILEY) / 2;
2708 gi = CreateGadget(GDI_CUSTOM_ID, id,
2709 GDI_INFO_TEXT, toolbutton_info[i].infotext,
2710 GDI_X, DX + toolbutton_info[i].x,
2711 GDI_Y, DY + toolbutton_info[i].y,
2712 GDI_WIDTH, toolbutton_info[i].width,
2713 GDI_HEIGHT, toolbutton_info[i].height,
2714 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
2715 GDI_STATE, GD_BUTTON_UNPRESSED,
2716 GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
2717 GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
2718 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
2719 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
2720 GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
2721 GDI_DECORATION_SHIFTING, 1, 1,
2722 GDI_EVENT_MASK, event_mask,
2723 GDI_CALLBACK_ACTION, HandleToolButtons,
2727 Error(ERR_EXIT, "cannot create gadget");
2729 tool_gadget[id] = gi;
2733 void FreeToolButtons()
2737 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
2738 FreeGadget(tool_gadget[i]);
2741 static void UnmapToolButtons()
2745 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
2746 UnmapGadget(tool_gadget[i]);
2749 static void HandleToolButtons(struct GadgetInfo *gi)
2751 request_gadget_id = gi->custom_id;
2754 int get_next_element(int element)
2758 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
2759 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
2760 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
2761 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
2762 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
2763 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
2764 case EL_AMOEBA_DROPPING: return EL_AMOEBA_WET;
2766 default: return element;
2770 int el_act_dir2img(int element, int action, int direction)
2772 element = GFX_ELEMENT(element);
2773 direction = MV_DIR_BIT(direction);
2775 return element_info[element].direction_graphic[action][direction];
2778 static int el_act_dir2crm(int element, int action, int direction)
2780 element = GFX_ELEMENT(element);
2781 direction = MV_DIR_BIT(direction);
2783 return element_info[element].direction_crumbled[action][direction];
2786 int el_act2img(int element, int action)
2788 element = GFX_ELEMENT(element);
2790 return element_info[element].graphic[action];
2793 int el_act2crm(int element, int action)
2795 element = GFX_ELEMENT(element);
2797 return element_info[element].crumbled[action];
2800 int el_dir2img(int element, int direction)
2802 element = GFX_ELEMENT(element);
2804 return el_act_dir2img(element, ACTION_DEFAULT, direction);
2807 int el2img(int element)
2809 element = GFX_ELEMENT(element);
2811 return element_info[element].graphic[ACTION_DEFAULT];
2814 int el2edimg(int element)
2816 element = GFX_ELEMENT(element);
2818 return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
2821 int el2preimg(int element)
2823 element = GFX_ELEMENT(element);
2825 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];