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)
633 action = GetPlayerAction(player, move_dir);
637 action = (player->is_pushing ? ACTION_PUSHING :
638 player->is_digging ? ACTION_DIGGING :
639 player->is_collecting ? ACTION_COLLECTING :
640 player->is_moving ? ACTION_MOVING :
641 player->is_snapping ? ACTION_SNAPPING :
642 player->is_sleeping ? ACTION_SLEEPING :
643 player->is_bored ? ACTION_BORING :
644 player->is_waiting ? ACTION_WAITING : ACTION_DEFAULT);
646 if (player->is_bored && player->num_special_action_bored > 0)
648 if (player->anim_delay_counter == 0 && player->post_delay_counter == 0)
652 action = ACTION_BORING_1 + SimpleRND(player->num_special_action_bored);
653 special_graphic = el_act_dir2img(EL_SP_MURPHY, action, move_dir);
655 player->anim_delay_counter =
656 graphic_info[special_graphic].anim_delay_fixed +
657 SimpleRND(graphic_info[special_graphic].anim_delay_random);
658 player->post_delay_counter =
659 graphic_info[special_graphic].post_delay_fixed +
660 SimpleRND(graphic_info[special_graphic].post_delay_random);
661 player->special_action_bored = action;
664 if (player->anim_delay_counter > 0)
666 action = player->special_action_bored;
667 player->anim_delay_counter--;
670 if (player->post_delay_counter > 0)
672 player->post_delay_counter--;
678 printf("::: '%s'\n", element_action_info[action].suffix);
681 InitPlayerGfxAnimation(player, action, move_dir);
683 /* ----------------------------------------------------------------------- */
684 /* draw things in the field the player is leaving, if needed */
685 /* ----------------------------------------------------------------------- */
688 if (player->is_moving)
690 if (player_is_moving)
693 if (Back[last_jx][last_jy] && IS_DRAWABLE(last_element))
695 DrawLevelElement(last_jx, last_jy, Back[last_jx][last_jy]);
697 if (last_element == EL_DYNAMITE_ACTIVE ||
698 last_element == EL_SP_DISK_RED_ACTIVE)
699 DrawDynamite(last_jx, last_jy);
701 DrawLevelFieldThruMask(last_jx, last_jy);
703 else if (last_element == EL_DYNAMITE_ACTIVE ||
704 last_element == EL_SP_DISK_RED_ACTIVE)
705 DrawDynamite(last_jx, last_jy);
707 DrawLevelField(last_jx, last_jy);
709 if (player->is_pushing && IN_SCR_FIELD(SCREENX(next_jx), SCREENY(next_jy)))
710 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
713 if (!IN_SCR_FIELD(sx, sy))
716 if (setup.direct_draw)
717 SetDrawtoField(DRAW_BUFFERED);
719 /* ----------------------------------------------------------------------- */
720 /* draw things behind the player, if needed */
721 /* ----------------------------------------------------------------------- */
724 DrawLevelElement(jx, jy, Back[jx][jy]);
725 else if (IS_ACTIVE_BOMB(element))
726 DrawLevelElement(jx, jy, EL_EMPTY);
729 if (player_is_moving && GfxElement[jx][jy] != EL_UNDEFINED)
731 if (GFX_CRUMBLED(GfxElement[jx][jy]))
732 DrawLevelFieldCrumbledSandDigging(jx, jy, move_dir, player->StepFrame);
735 int old_element = GfxElement[jx][jy];
736 int old_graphic = el_act_dir2img(old_element, action, move_dir);
737 int frame = getGraphicAnimationFrame(old_graphic, player->StepFrame);
739 DrawGraphic(sx, sy, old_graphic, frame);
744 GfxElement[jx][jy] = EL_UNDEFINED;
746 DrawLevelField(jx, jy);
750 /* ----------------------------------------------------------------------- */
751 /* draw player himself */
752 /* ----------------------------------------------------------------------- */
756 graphic = getPlayerGraphic(player, move_dir);
758 /* in the case of changed player action or direction, prevent the current
759 animation frame from being restarted for identical animations */
760 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
761 player->Frame = last_player_frame;
765 if (player->use_murphy_graphic)
767 static int last_horizontal_dir = MV_LEFT;
769 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
770 last_horizontal_dir = move_dir;
772 graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, move_dir);
774 if (graphic == IMG_SP_MURPHY) /* undefined => use special graphic */
776 int direction = (player->is_snapping ? move_dir : last_horizontal_dir);
778 graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, direction);
782 graphic = el_act_dir2img(player->element_nr, player->GfxAction, move_dir);
786 frame = getGraphicAnimationFrame(graphic, player->Frame);
790 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
791 sxx = player->GfxPos;
793 syy = player->GfxPos;
796 if (!setup.soft_scrolling && ScreenMovPos)
799 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
801 if (SHIELD_ON(player))
803 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
804 IMG_SHIELD_NORMAL_ACTIVE);
805 int frame = getGraphicAnimationFrame(graphic, -1);
807 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
810 /* ----------------------------------------------------------------------- */
811 /* draw things the player is pushing, if needed */
812 /* ----------------------------------------------------------------------- */
815 printf("::: %d, %d [%d, %d] [%d]\n",
816 player->is_pushing, player_is_moving, player->GfxAction,
817 player->is_moving, player_is_moving);
821 if (player->is_pushing && player->is_moving)
823 if (player->is_pushing && player_is_moving)
826 int px = SCREENX(next_jx), py = SCREENY(next_jy);
828 if (Back[next_jx][next_jy])
829 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
831 if ((sxx || syy) && element == EL_SOKOBAN_OBJECT)
832 DrawGraphicShiftedThruMask(px, py, sxx, syy, IMG_SOKOBAN_OBJECT, 0,
836 int element = MovingOrBlocked2Element(next_jx, next_jy);
837 int graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
839 int frame = getGraphicAnimationFrame(graphic, player->StepFrame);
841 int frame = getGraphicAnimationFrame(graphic, player->Frame);
844 DrawGraphicShifted(px, py, sxx, syy, graphic, frame,
845 NO_CUTTING, NO_MASKING);
849 /* ----------------------------------------------------------------------- */
850 /* draw things in front of player (active dynamite or dynabombs) */
851 /* ----------------------------------------------------------------------- */
853 if (IS_ACTIVE_BOMB(element))
855 graphic = el2img(element);
856 frame = getGraphicAnimationFrame(graphic, GfxFrame[jx][jy]);
858 if (game.emulation == EMU_SUPAPLEX)
859 DrawGraphic(sx, sy, IMG_SP_DISK_RED, frame);
861 DrawGraphicThruMask(sx, sy, graphic, frame);
864 if (player_is_moving && last_element == EL_EXPLOSION)
866 int graphic = el_act2img(GfxElement[last_jx][last_jy], ACTION_EXPLODING);
867 int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
868 int phase = ExplodePhase[last_jx][last_jy] - 1;
869 int frame = getGraphicAnimationFrame(graphic, phase - delay);
872 DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy), graphic, frame);
875 /* ----------------------------------------------------------------------- */
876 /* draw elements the player is just walking/passing through/under */
877 /* ----------------------------------------------------------------------- */
879 /* handle the field the player is leaving ... */
880 if (player_is_moving && IS_ACCESSIBLE_INSIDE(last_element))
881 DrawLevelField(last_jx, last_jy);
882 else if (player_is_moving && IS_ACCESSIBLE_UNDER(last_element))
883 DrawLevelFieldThruMask(last_jx, last_jy);
885 /* ... and the field the player is entering */
886 if (IS_ACCESSIBLE_INSIDE(element))
887 DrawLevelField(jx, jy);
888 else if (IS_ACCESSIBLE_UNDER(element))
889 DrawLevelFieldThruMask(jx, jy);
891 if (setup.direct_draw)
893 int dest_x = SX + SCREENX(MIN(jx, last_jx)) * TILEX;
894 int dest_y = SY + SCREENY(MIN(jy, last_jy)) * TILEY;
895 int x_size = TILEX * (1 + ABS(jx - last_jx));
896 int y_size = TILEY * (1 + ABS(jy - last_jy));
898 BlitBitmap(drawto_field, window,
899 dest_x, dest_y, x_size, y_size, dest_x, dest_y);
900 SetDrawtoField(DRAW_DIRECT);
903 MarkTileDirty(sx,sy);
906 void getGraphicSource(int graphic, int frame, Bitmap **bitmap, int *x, int *y)
908 struct GraphicInfo *g = &graphic_info[graphic];
912 if (g->offset_y == 0) /* frames are ordered horizontally */
914 int max_width = g->anim_frames_per_line * g->width;
916 *x = (g->src_x + frame * g->offset_x) % max_width;
917 *y = g->src_y + (g->src_x + frame * g->offset_x) / max_width * g->height;
919 else if (g->offset_x == 0) /* frames are ordered vertically */
921 int max_height = g->anim_frames_per_line * g->height;
923 *x = g->src_x + (g->src_y + frame * g->offset_y) / max_height * g->width;
924 *y = (g->src_y + frame * g->offset_y) % max_height;
926 else /* frames are ordered diagonally */
928 *x = g->src_x + frame * g->offset_x;
929 *y = g->src_y + frame * g->offset_y;
933 void DrawGraphic(int x, int y, int graphic, int frame)
936 if (!IN_SCR_FIELD(x, y))
938 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
939 printf("DrawGraphic(): This should never happen!\n");
944 DrawGraphicExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic, frame);
948 void DrawGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
954 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
955 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
958 void DrawGraphicThruMask(int x, int y, int graphic, int frame)
961 if (!IN_SCR_FIELD(x, y))
963 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
964 printf("DrawGraphicThruMask(): This should never happen!\n");
969 DrawGraphicThruMaskExt(drawto_field, FX + x * TILEX, FY + y *TILEY, graphic,
974 void DrawGraphicThruMaskExt(DrawBuffer *d, int dest_x, int dest_y, int graphic,
982 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
983 drawing_gc = src_bitmap->stored_clip_gc;
985 GC drawing_gc = src_bitmap->stored_clip_gc;
986 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
987 int src_x = graphic_info[graphic].src_x;
988 int src_y = graphic_info[graphic].src_y;
989 int offset_x = graphic_info[graphic].offset_x;
990 int offset_y = graphic_info[graphic].offset_y;
992 src_x += frame * offset_x;
993 src_y += frame * offset_y;
997 SetClipOrigin(src_bitmap, drawing_gc, dest_x - src_x, dest_y - src_y);
998 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX, TILEY, dest_x, dest_y);
1001 void DrawMiniGraphic(int x, int y, int graphic)
1003 DrawMiniGraphicExt(drawto, SX + x * MINI_TILEX,SY + y * MINI_TILEY, graphic);
1004 MarkTileDirty(x / 2, y / 2);
1007 void getMiniGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
1009 struct GraphicInfo *g = &graphic_info[graphic];
1010 int mini_startx = 0;
1011 int mini_starty = g->bitmap->height * 2 / 3;
1013 *bitmap = g->bitmap;
1014 *x = mini_startx + g->src_x / 2;
1015 *y = mini_starty + g->src_y / 2;
1018 void DrawMiniGraphicExt(DrawBuffer *d, int x, int y, int graphic)
1023 getMiniGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
1024 BlitBitmap(src_bitmap, d, src_x, src_y, MINI_TILEX, MINI_TILEY, x, y);
1027 void DrawGraphicShifted(int x,int y, int dx,int dy, int graphic, int frame,
1028 int cut_mode, int mask_mode)
1033 int width = TILEX, height = TILEY;
1039 DrawGraphic(x, y, graphic, frame);
1043 if (dx || dy) /* shifted graphic */
1045 if (x < BX1) /* object enters playfield from the left */
1052 else if (x > BX2) /* object enters playfield from the right */
1058 else if (x==BX1 && dx < 0) /* object leaves playfield to the left */
1064 else if (x==BX2 && dx > 0) /* object leaves playfield to the right */
1066 else if (dx) /* general horizontal movement */
1067 MarkTileDirty(x + SIGN(dx), y);
1069 if (y < BY1) /* object enters playfield from the top */
1071 if (cut_mode==CUT_BELOW) /* object completely above top border */
1079 else if (y > BY2) /* object enters playfield from the bottom */
1085 else if (y==BY1 && dy < 0) /* object leaves playfield to the top */
1091 else if (dy > 0 && cut_mode == CUT_ABOVE)
1093 if (y == BY2) /* object completely above bottom border */
1099 MarkTileDirty(x, y + 1);
1100 } /* object leaves playfield to the bottom */
1101 else if (dy > 0 && (y == BY2 || cut_mode == CUT_BELOW))
1103 else if (dy) /* general vertical movement */
1104 MarkTileDirty(x, y + SIGN(dy));
1108 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1110 src_bitmap = graphic_info[graphic].bitmap;
1111 src_x = graphic_info[graphic].src_x;
1112 src_y = graphic_info[graphic].src_y;
1113 offset_x = graphic_info[graphic].offset_x;
1114 offset_y = graphic_info[graphic].offset_y;
1116 src_x += frame * offset_x;
1117 src_y += frame * offset_y;
1120 drawing_gc = src_bitmap->stored_clip_gc;
1125 dest_x = FX + x * TILEX + dx;
1126 dest_y = FY + y * TILEY + dy;
1129 if (!IN_SCR_FIELD(x,y))
1131 printf("DrawGraphicShifted(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
1132 printf("DrawGraphicShifted(): This should never happen!\n");
1137 if (mask_mode == USE_MASKING)
1139 SetClipOrigin(src_bitmap, drawing_gc, dest_x - src_x, dest_y - src_y);
1140 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1144 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1150 void DrawGraphicShiftedThruMask(int x, int y, int dx, int dy, int graphic,
1151 int frame, int cut_mode)
1153 DrawGraphicShifted(x,y, dx,dy, graphic, frame, cut_mode, USE_MASKING);
1156 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
1157 int cut_mode, int mask_mode)
1159 int lx = LEVELX(x), ly = LEVELY(y);
1163 if (IN_LEV_FIELD(lx, ly))
1165 SetRandomAnimationValue(lx, ly);
1167 graphic = el_act_dir2img(element, GfxAction[lx][ly], GfxDir[lx][ly]);
1168 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1170 else /* border element */
1172 graphic = el2img(element);
1173 frame = getGraphicAnimationFrame(graphic, -1);
1176 if (element == EL_EXPANDABLE_WALL)
1178 boolean left_stopped = FALSE, right_stopped = FALSE;
1180 if (!IN_LEV_FIELD(lx - 1, ly) || IS_WALL(Feld[lx - 1][ly]))
1181 left_stopped = TRUE;
1182 if (!IN_LEV_FIELD(lx + 1, ly) || IS_WALL(Feld[lx + 1][ly]))
1183 right_stopped = TRUE;
1185 if (left_stopped && right_stopped)
1187 else if (left_stopped)
1189 graphic = IMG_EXPANDABLE_WALL_GROWING_RIGHT;
1190 frame = graphic_info[graphic].anim_frames - 1;
1192 else if (right_stopped)
1194 graphic = IMG_EXPANDABLE_WALL_GROWING_LEFT;
1195 frame = graphic_info[graphic].anim_frames - 1;
1200 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, mask_mode);
1201 else if (mask_mode == USE_MASKING)
1202 DrawGraphicThruMask(x, y, graphic, frame);
1204 DrawGraphic(x, y, graphic, frame);
1207 void DrawLevelElementExt(int x, int y, int dx, int dy, int element,
1208 int cut_mode, int mask_mode)
1210 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1211 DrawScreenElementExt(SCREENX(x), SCREENY(y), dx, dy, element,
1212 cut_mode, mask_mode);
1215 void DrawScreenElementShifted(int x, int y, int dx, int dy, int element,
1218 DrawScreenElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1221 void DrawLevelElementShifted(int x, int y, int dx, int dy, int element,
1224 DrawLevelElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1227 void DrawLevelElementThruMask(int x, int y, int element)
1229 DrawLevelElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1232 void DrawLevelFieldThruMask(int x, int y)
1234 DrawLevelElementExt(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
1237 static void DrawLevelFieldCrumbledSandExt(int x, int y, int graphic, int frame)
1241 int sx = SCREENX(x), sy = SCREENY(y);
1243 int width, height, cx, cy, i;
1245 int crumbled_border_size = graphic_info[graphic].border_size;
1247 int snip = TILEX / 8; /* number of border pixels from "crumbled graphic" */
1249 static int xy[4][2] =
1258 if (x == 0 && y == 7)
1259 printf("::: %d, %d [%d]\n", GfxElement[x][y], Feld[x][y],
1260 crumbled_border_size);
1263 if (!IN_LEV_FIELD(x, y))
1266 element = (GfxElement[x][y] != EL_UNDEFINED && Feld[x][y] != EL_EXPLOSION ?
1267 GfxElement[x][y] : Feld[x][y]);
1269 /* crumble field itself */
1270 if (GFX_CRUMBLED(element) && !IS_MOVING(x, y))
1272 if (!IN_SCR_FIELD(sx, sy))
1275 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1277 for (i = 0; i < 4; i++)
1279 int xx = x + xy[i][0];
1280 int yy = y + xy[i][1];
1282 element = (IN_LEV_FIELD(xx, yy) ? Feld[xx][yy] : BorderElement);
1284 /* check if neighbour field is of same type */
1285 if (GFX_CRUMBLED(element) && !IS_MOVING(xx, yy))
1289 if (Feld[x][y] == EL_CUSTOM_START + 123)
1290 printf("::: crumble [%d] THE CHAOS ENGINE (%d, %d): %d, %d\n",
1291 i, Feld[x][y], element,
1292 GFX_CRUMBLED(element), IS_MOVING(x, y));
1295 if (i == 1 || i == 2)
1297 width = crumbled_border_size;
1299 cx = (i == 2 ? TILEX - crumbled_border_size : 0);
1305 height = crumbled_border_size;
1307 cy = (i == 3 ? TILEY - crumbled_border_size : 0);
1310 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1311 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
1314 MarkTileDirty(sx, sy);
1316 else /* crumble neighbour fields */
1319 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1322 for (i = 0; i < 4; i++)
1324 int xx = x + xy[i][0];
1325 int yy = y + xy[i][1];
1326 int sxx = sx + xy[i][0];
1327 int syy = sy + xy[i][1];
1329 if (!IN_LEV_FIELD(xx, yy) ||
1330 !IN_SCR_FIELD(sxx, syy) ||
1331 !GFX_CRUMBLED(Feld[xx][yy]) ||
1336 graphic = el_act2crm(Feld[xx][yy], ACTION_DEFAULT);
1337 crumbled_border_size = graphic_info[graphic].border_size;
1339 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1342 if (i == 1 || i == 2)
1344 width = crumbled_border_size;
1346 cx = (i == 1 ? TILEX - crumbled_border_size : 0);
1352 height = crumbled_border_size;
1354 cy = (i == 0 ? TILEY - crumbled_border_size : 0);
1357 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1358 width, height, FX + sxx * TILEX + cx, FY + syy * TILEY + cy);
1360 MarkTileDirty(sxx, syy);
1365 void DrawLevelFieldCrumbledSand(int x, int y)
1370 if (!IN_LEV_FIELD(x, y))
1373 graphic = el_act2crm(Feld[x][y], ACTION_DEFAULT);
1375 DrawLevelFieldCrumbledSandExt(x, y, graphic, 0);
1377 DrawLevelFieldCrumbledSandExt(x, y, IMG_SAND_CRUMBLED, 0);
1381 void DrawLevelFieldCrumbledSandDigging(int x, int y, int direction,
1385 int graphic1 = el_act_dir2img(GfxElement[x][y], ACTION_DIGGING, direction);
1386 int graphic2 = el_act_dir2crm(GfxElement[x][y], ACTION_DIGGING, direction);
1388 int graphic1 = el_act_dir2img(EL_SAND, ACTION_DIGGING, direction);
1389 int graphic2 = el_act_dir2img(EL_SAND_CRUMBLED, ACTION_DIGGING, direction);
1391 int frame1 = getGraphicAnimationFrame(graphic1, step_frame);
1392 int frame2 = getGraphicAnimationFrame(graphic2, step_frame);
1393 int sx = SCREENX(x), sy = SCREENY(y);
1395 DrawGraphic(sx, sy, graphic1, frame1);
1396 DrawLevelFieldCrumbledSandExt(x, y, graphic2, frame2);
1399 void DrawLevelFieldCrumbledSandNeighbours(int x, int y)
1401 int sx = SCREENX(x), sy = SCREENY(y);
1402 static int xy[4][2] =
1411 for (i = 0; i < 4; i++)
1413 int xx = x + xy[i][0];
1414 int yy = y + xy[i][1];
1415 int sxx = sx + xy[i][0];
1416 int syy = sy + xy[i][1];
1418 if (!IN_LEV_FIELD(xx, yy) ||
1419 !IN_SCR_FIELD(sxx, syy) ||
1420 !GFX_CRUMBLED(Feld[xx][yy]) ||
1424 DrawLevelField(xx, yy);
1428 static int getBorderElement(int x, int y)
1432 { EL_STEELWALL_TOPLEFT, EL_INVISIBLE_STEELWALL_TOPLEFT },
1433 { EL_STEELWALL_TOPRIGHT, EL_INVISIBLE_STEELWALL_TOPRIGHT },
1434 { EL_STEELWALL_BOTTOMLEFT, EL_INVISIBLE_STEELWALL_BOTTOMLEFT },
1435 { EL_STEELWALL_BOTTOMRIGHT, EL_INVISIBLE_STEELWALL_BOTTOMRIGHT },
1436 { EL_STEELWALL_VERTICAL, EL_INVISIBLE_STEELWALL_VERTICAL },
1437 { EL_STEELWALL_HORIZONTAL, EL_INVISIBLE_STEELWALL_HORIZONTAL },
1438 { EL_STEELWALL, EL_INVISIBLE_STEELWALL }
1440 int steel_type = (BorderElement == EL_STEELWALL ? 0 : 1);
1441 int steel_position = (x == -1 && y == -1 ? 0 :
1442 x == lev_fieldx && y == -1 ? 1 :
1443 x == -1 && y == lev_fieldy ? 2 :
1444 x == lev_fieldx && y == lev_fieldy ? 3 :
1445 x == -1 || x == lev_fieldx ? 4 :
1446 y == -1 || y == lev_fieldy ? 5 : 6);
1448 return border[steel_position][steel_type];
1451 void DrawScreenElement(int x, int y, int element)
1453 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
1454 DrawLevelFieldCrumbledSand(LEVELX(x), LEVELY(y));
1457 void DrawLevelElement(int x, int y, int element)
1459 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1460 DrawScreenElement(SCREENX(x), SCREENY(y), element);
1463 void DrawScreenField(int x, int y)
1465 int lx = LEVELX(x), ly = LEVELY(y);
1466 int element, content;
1468 if (!IN_LEV_FIELD(lx, ly))
1470 if (lx < -1 || lx > lev_fieldx || ly < -1 || ly > lev_fieldy)
1473 element = getBorderElement(lx, ly);
1475 DrawScreenElement(x, y, element);
1479 element = Feld[lx][ly];
1480 content = Store[lx][ly];
1482 if (IS_MOVING(lx, ly))
1484 int horiz_move = (MovDir[lx][ly] == MV_LEFT || MovDir[lx][ly] == MV_RIGHT);
1485 boolean cut_mode = NO_CUTTING;
1487 if (element == EL_QUICKSAND_EMPTYING ||
1488 element == EL_MAGIC_WALL_EMPTYING ||
1489 element == EL_BD_MAGIC_WALL_EMPTYING ||
1490 element == EL_AMOEBA_DROPPING)
1491 cut_mode = CUT_ABOVE;
1492 else if (element == EL_QUICKSAND_FILLING ||
1493 element == EL_MAGIC_WALL_FILLING ||
1494 element == EL_BD_MAGIC_WALL_FILLING)
1495 cut_mode = CUT_BELOW;
1497 if (cut_mode == CUT_ABOVE)
1498 DrawScreenElementShifted(x, y, 0, 0, element, NO_CUTTING);
1500 DrawScreenElement(x, y, EL_EMPTY);
1503 DrawScreenElementShifted(x, y, MovPos[lx][ly], 0, element, NO_CUTTING);
1504 else if (cut_mode == NO_CUTTING)
1505 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], element, cut_mode);
1507 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], content, cut_mode);
1509 if (content == EL_ACID)
1510 DrawLevelElementThruMask(lx, ly + 1, EL_ACID);
1512 else if (IS_BLOCKED(lx, ly))
1517 boolean cut_mode = NO_CUTTING;
1518 int element_old, content_old;
1520 Blocked2Moving(lx, ly, &oldx, &oldy);
1523 horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
1524 MovDir[oldx][oldy] == MV_RIGHT);
1526 element_old = Feld[oldx][oldy];
1527 content_old = Store[oldx][oldy];
1529 if (element_old == EL_QUICKSAND_EMPTYING ||
1530 element_old == EL_MAGIC_WALL_EMPTYING ||
1531 element_old == EL_BD_MAGIC_WALL_EMPTYING ||
1532 element_old == EL_AMOEBA_DROPPING)
1533 cut_mode = CUT_ABOVE;
1535 DrawScreenElement(x, y, EL_EMPTY);
1538 DrawScreenElementShifted(sx, sy, MovPos[oldx][oldy], 0, element_old,
1540 else if (cut_mode == NO_CUTTING)
1541 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], element_old,
1544 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], content_old,
1547 else if (IS_DRAWABLE(element))
1548 DrawScreenElement(x, y, element);
1550 DrawScreenElement(x, y, EL_EMPTY);
1553 void DrawLevelField(int x, int y)
1555 if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1556 DrawScreenField(SCREENX(x), SCREENY(y));
1557 else if (IS_MOVING(x, y))
1561 Moving2Blocked(x, y, &newx, &newy);
1562 if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
1563 DrawScreenField(SCREENX(newx), SCREENY(newy));
1565 else if (IS_BLOCKED(x, y))
1569 Blocked2Moving(x, y, &oldx, &oldy);
1570 if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
1571 DrawScreenField(SCREENX(oldx), SCREENY(oldy));
1575 void DrawMiniElement(int x, int y, int element)
1579 graphic = el2edimg(element);
1580 DrawMiniGraphic(x, y, graphic);
1583 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
1585 int x = sx + scroll_x, y = sy + scroll_y;
1587 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
1588 DrawMiniElement(sx, sy, EL_EMPTY);
1589 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
1590 DrawMiniElement(sx, sy, Feld[x][y]);
1592 DrawMiniGraphic(sx, sy, el2edimg(getBorderElement(x, y)));
1595 void DrawEnvelopeBackground(int envelope_nr, int startx, int starty,
1596 int x, int y, int xsize, int ysize, int font_nr)
1598 int font_width = getFontWidth(font_nr);
1599 int font_height = getFontHeight(font_nr);
1600 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1603 int dst_x = SX + startx + x * font_width;
1604 int dst_y = SY + starty + y * font_height;
1605 int width = graphic_info[graphic].width;
1606 int height = graphic_info[graphic].height;
1607 int inner_width = MAX(width - 2 * font_width, font_width);
1608 int inner_height = MAX(height - 2 * font_height, font_height);
1609 int inner_sx = (width >= 3 * font_width ? font_width : 0);
1610 int inner_sy = (height >= 3 * font_height ? font_height : 0);
1611 boolean draw_masked = graphic_info[graphic].draw_masked;
1613 getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
1615 if (src_bitmap == NULL || width < font_width || height < font_height)
1617 ClearRectangle(drawto, dst_x, dst_y, font_width, font_height);
1621 src_x += (x == 0 ? 0 : x == xsize - 1 ? width - font_width :
1622 inner_sx + (x - 1) * font_width % inner_width);
1623 src_y += (y == 0 ? 0 : y == ysize - 1 ? height - font_height :
1624 inner_sy + (y - 1) * font_height % inner_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,
1638 void AnimateEnvelope(int envelope_nr, int anim_mode, int action)
1640 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1641 boolean draw_masked = graphic_info[graphic].draw_masked;
1642 int mask_mode = (draw_masked ? BLIT_MASKED : BLIT_ON_BACKGROUND);
1643 boolean ffwd_delay = (tape.playing && tape.fast_forward);
1644 unsigned long anim_delay = 0;
1645 int anim_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
1646 int font_nr = FONT_ENVELOPE_1 + envelope_nr;
1647 int font_width = getFontWidth(font_nr);
1648 int font_height = getFontHeight(font_nr);
1649 int max_xsize = level.envelope_xsize[envelope_nr];
1650 int max_ysize = level.envelope_ysize[envelope_nr];
1651 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize : 0);
1652 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize : 0);
1653 int xend = max_xsize;
1654 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize : 0);
1655 int xstep = (xstart < xend ? 1 : 0);
1656 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
1659 for (x = xstart, y = ystart; x <= xend && y <= yend; x += xstep, y += ystep)
1661 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
1662 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
1663 int sx = (SXSIZE - xsize * font_width) / 2;
1664 int sy = (SYSIZE - ysize * font_height) / 2;
1667 SetDrawtoField(DRAW_BUFFERED);
1669 BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
1671 SetDrawtoField(DRAW_BACKBUFFER);
1673 for (yy = 0; yy < ysize; yy++) for (xx = 0; xx < xsize; xx++)
1674 DrawEnvelopeBackground(envelope_nr, sx,sy, xx,yy, xsize, ysize, font_nr);
1676 DrawTextToTextArea(SX + sx + font_width, SY + sy + font_height,
1677 level.envelope_text[envelope_nr], font_nr, max_xsize,
1678 xsize - 2, ysize - 2, mask_mode);
1680 redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
1683 WaitUntilDelayReached(&anim_delay, anim_delay_value / 2);
1687 void ShowEnvelope(int envelope_nr)
1689 int element = EL_ENVELOPE_1 + envelope_nr;
1690 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1691 int sound_opening = element_info[element].sound[ACTION_OPENING];
1692 int sound_closing = element_info[element].sound[ACTION_CLOSING];
1693 boolean ffwd_delay = (tape.playing && tape.fast_forward);
1694 int wait_delay_value = (ffwd_delay ? 500 : 1000);
1695 int anim_mode = graphic_info[graphic].anim_mode;
1696 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
1697 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
1699 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
1701 PlaySoundStereo(sound_opening, SOUND_MIDDLE);
1703 if (anim_mode == ANIM_DEFAULT)
1704 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_OPENING);
1706 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_OPENING);
1709 Delay(wait_delay_value);
1711 WaitForEventToContinue();
1713 PlaySoundStereo(sound_closing, SOUND_MIDDLE);
1715 if (anim_mode != ANIM_NONE)
1716 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_CLOSING);
1718 if (anim_mode == ANIM_DEFAULT)
1719 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_CLOSING);
1721 game.envelope_active = FALSE;
1723 SetDrawtoField(DRAW_BUFFERED);
1725 redraw_mask |= REDRAW_FIELD;
1729 void getMicroGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
1731 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
1732 int mini_startx = src_bitmap->width * 3 / 4;
1733 int mini_starty = src_bitmap->height * 2 / 3;
1734 int src_x = mini_startx + graphic_info[graphic].src_x / 8;
1735 int src_y = mini_starty + graphic_info[graphic].src_y / 8;
1737 *bitmap = src_bitmap;
1742 void DrawMicroElement(int xpos, int ypos, int element)
1746 int graphic = el2preimg(element);
1748 getMicroGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
1749 BlitBitmap(src_bitmap, drawto, src_x, src_y, MICRO_TILEX, MICRO_TILEY,
1757 SetDrawBackgroundMask(REDRAW_NONE);
1760 for (x = BX1; x <= BX2; x++)
1761 for (y = BY1; y <= BY2; y++)
1762 DrawScreenField(x, y);
1764 redraw_mask |= REDRAW_FIELD;
1767 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
1771 for (x = 0; x < size_x; x++)
1772 for (y = 0; y < size_y; y++)
1773 DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
1775 redraw_mask |= REDRAW_FIELD;
1778 static void DrawMicroLevelExt(int xpos, int ypos, int from_x, int from_y)
1782 DrawBackground(xpos, ypos, MICROLEV_XSIZE, MICROLEV_YSIZE);
1784 if (lev_fieldx < STD_LEV_FIELDX)
1785 xpos += (STD_LEV_FIELDX - lev_fieldx) / 2 * MICRO_TILEX;
1786 if (lev_fieldy < STD_LEV_FIELDY)
1787 ypos += (STD_LEV_FIELDY - lev_fieldy) / 2 * MICRO_TILEY;
1789 xpos += MICRO_TILEX;
1790 ypos += MICRO_TILEY;
1792 for (x = -1; x <= STD_LEV_FIELDX; x++)
1794 for (y = -1; y <= STD_LEV_FIELDY; y++)
1796 int lx = from_x + x, ly = from_y + y;
1798 if (lx >= 0 && lx < lev_fieldx && ly >= 0 && ly < lev_fieldy)
1799 DrawMicroElement(xpos + x * MICRO_TILEX, ypos + y * MICRO_TILEY,
1800 level.field[lx][ly]);
1801 else if (lx >= -1 && lx < lev_fieldx+1 && ly >= -1 && ly < lev_fieldy+1
1802 && BorderElement != EL_EMPTY)
1803 DrawMicroElement(xpos + x * MICRO_TILEX, ypos + y * MICRO_TILEY,
1804 getBorderElement(lx, ly));
1808 redraw_mask |= REDRAW_MICROLEVEL;
1811 #define MICROLABEL_EMPTY 0
1812 #define MICROLABEL_LEVEL_NAME 1
1813 #define MICROLABEL_CREATED_BY 2
1814 #define MICROLABEL_LEVEL_AUTHOR 3
1815 #define MICROLABEL_IMPORTED_FROM 4
1816 #define MICROLABEL_LEVEL_IMPORT_INFO 5
1818 static void DrawMicroLevelLabelExt(int mode)
1820 char label_text[MAX_OUTPUT_LINESIZE + 1];
1821 int max_len_label_text;
1822 int font_nr = FONT_TEXT_2;
1824 if (mode == MICROLABEL_CREATED_BY || mode == MICROLABEL_IMPORTED_FROM)
1825 font_nr = FONT_TEXT_3;
1827 max_len_label_text = SXSIZE / getFontWidth(font_nr);
1829 DrawBackground(SX, MICROLABEL_YPOS, SXSIZE, getFontHeight(font_nr));
1831 strncpy(label_text, (mode == MICROLABEL_LEVEL_NAME ? level.name :
1832 mode == MICROLABEL_CREATED_BY ? "created by" :
1833 mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
1834 mode == MICROLABEL_IMPORTED_FROM ? "imported from" :
1835 mode == MICROLABEL_LEVEL_IMPORT_INFO ?
1836 leveldir_current->imported_from : ""),
1837 max_len_label_text);
1838 label_text[max_len_label_text] = '\0';
1840 if (strlen(label_text) > 0)
1842 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
1843 int lypos = MICROLABEL_YPOS;
1845 DrawText(lxpos, lypos, label_text, font_nr);
1848 redraw_mask |= REDRAW_MICROLEVEL;
1851 void DrawMicroLevel(int xpos, int ypos, boolean restart)
1853 static unsigned long scroll_delay = 0;
1854 static unsigned long label_delay = 0;
1855 static int from_x, from_y, scroll_direction;
1856 static int label_state, label_counter;
1857 int last_game_status = game_status; /* save current game status */
1859 /* force PREVIEW font on preview level */
1860 game_status = GAME_MODE_PSEUDO_PREVIEW;
1864 from_x = from_y = 0;
1865 scroll_direction = MV_RIGHT;
1869 DrawMicroLevelExt(xpos, ypos, from_x, from_y);
1870 DrawMicroLevelLabelExt(label_state);
1872 /* initialize delay counters */
1873 DelayReached(&scroll_delay, 0);
1874 DelayReached(&label_delay, 0);
1876 if (leveldir_current->name)
1878 int text_width = getTextWidth(leveldir_current->name, FONT_TEXT_1);
1879 int lxpos = SX + (SXSIZE - text_width) / 2;
1880 int lypos = SY + 352;
1882 DrawText(lxpos, lypos, leveldir_current->name, FONT_TEXT_1);
1885 game_status = last_game_status; /* restore current game status */
1890 /* scroll micro level, if needed */
1891 if ((lev_fieldx > STD_LEV_FIELDX || lev_fieldy > STD_LEV_FIELDY) &&
1892 DelayReached(&scroll_delay, MICROLEVEL_SCROLL_DELAY))
1894 switch (scroll_direction)
1900 scroll_direction = MV_UP;
1904 if (from_x < lev_fieldx - STD_LEV_FIELDX)
1907 scroll_direction = MV_DOWN;
1914 scroll_direction = MV_RIGHT;
1918 if (from_y < lev_fieldy - STD_LEV_FIELDY)
1921 scroll_direction = MV_LEFT;
1928 DrawMicroLevelExt(xpos, ypos, from_x, from_y);
1931 /* redraw micro level label, if needed */
1932 if (strcmp(level.name, NAMELESS_LEVEL_NAME) != 0 &&
1933 strcmp(level.author, ANONYMOUS_NAME) != 0 &&
1934 strcmp(level.author, leveldir_current->name) != 0 &&
1935 DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
1937 int max_label_counter = 23;
1939 if (leveldir_current->imported_from != NULL)
1940 max_label_counter += 14;
1942 label_counter = (label_counter + 1) % max_label_counter;
1943 label_state = (label_counter >= 0 && label_counter <= 7 ?
1944 MICROLABEL_LEVEL_NAME :
1945 label_counter >= 9 && label_counter <= 12 ?
1946 MICROLABEL_CREATED_BY :
1947 label_counter >= 14 && label_counter <= 21 ?
1948 MICROLABEL_LEVEL_AUTHOR :
1949 label_counter >= 23 && label_counter <= 26 ?
1950 MICROLABEL_IMPORTED_FROM :
1951 label_counter >= 28 && label_counter <= 35 ?
1952 MICROLABEL_LEVEL_IMPORT_INFO : MICROLABEL_EMPTY);
1953 DrawMicroLevelLabelExt(label_state);
1956 game_status = last_game_status; /* restore current game status */
1959 void WaitForEventToContinue()
1961 boolean still_wait = TRUE;
1963 /* simulate releasing mouse button over last gadget, if still pressed */
1965 HandleGadgets(-1, -1, 0);
1967 button_status = MB_RELEASED;
1979 case EVENT_BUTTONPRESS:
1980 case EVENT_KEYPRESS:
1984 case EVENT_KEYRELEASE:
1985 ClearPlayerAction();
1989 HandleOtherEvents(&event);
1993 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
2000 /* don't eat all CPU time */
2005 #define MAX_REQUEST_LINES 13
2006 #define MAX_REQUEST_LINE_LEN 7
2008 boolean Request(char *text, unsigned int req_state)
2010 int mx, my, ty, result = -1;
2011 unsigned int old_door_state;
2012 int last_game_status = game_status; /* save current game status */
2015 SetMouseCursor(CURSOR_DEFAULT);
2018 #if defined(PLATFORM_UNIX)
2019 /* pause network game while waiting for request to answer */
2020 if (options.network &&
2021 game_status == GAME_MODE_PLAYING &&
2022 req_state & REQUEST_WAIT_FOR)
2023 SendToServer_PausePlaying();
2026 old_door_state = GetDoorState();
2028 /* simulate releasing mouse button over last gadget, if still pressed */
2030 HandleGadgets(-1, -1, 0);
2034 CloseDoor(DOOR_CLOSE_1);
2036 /* save old door content */
2037 BlitBitmap(bitmap_db_door, bitmap_db_door,
2038 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
2039 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
2041 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
2043 /* clear door drawing field */
2044 DrawBackground(DX, DY, DXSIZE, DYSIZE);
2046 /* force DOOR font on preview level */
2047 game_status = GAME_MODE_PSEUDO_DOOR;
2049 /* write text for request */
2050 for (ty = 0; ty < MAX_REQUEST_LINES; ty++)
2052 char text_line[MAX_REQUEST_LINE_LEN + 1];
2058 for (tl = 0, tx = 0; tx < MAX_REQUEST_LINE_LEN; tl++, tx++)
2061 if (!tc || tc == ' ')
2072 strncpy(text_line, text, tl);
2075 DrawText(DX + (DXSIZE - tl * getFontWidth(FONT_TEXT_2)) / 2,
2076 DY + 8 + ty * (getFontHeight(FONT_TEXT_2) + 2),
2077 text_line, FONT_TEXT_2);
2079 text += tl + (tc == ' ' ? 1 : 0);
2082 game_status = last_game_status; /* restore current game status */
2084 if (req_state & REQ_ASK)
2086 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
2087 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
2089 else if (req_state & REQ_CONFIRM)
2091 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
2093 else if (req_state & REQ_PLAYER)
2095 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
2096 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
2097 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
2098 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
2101 /* copy request gadgets to door backbuffer */
2102 BlitBitmap(drawto, bitmap_db_door,
2103 DX, DY, DXSIZE, DYSIZE,
2104 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2106 OpenDoor(DOOR_OPEN_1);
2112 if (!(req_state & REQUEST_WAIT_FOR))
2114 SetDrawBackgroundMask(REDRAW_FIELD);
2119 if (game_status != GAME_MODE_MAIN)
2122 button_status = MB_RELEASED;
2124 request_gadget_id = -1;
2126 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
2129 SetMouseCursor(CURSOR_DEFAULT);
2142 case EVENT_BUTTONPRESS:
2143 case EVENT_BUTTONRELEASE:
2144 case EVENT_MOTIONNOTIFY:
2146 if (event.type == EVENT_MOTIONNOTIFY)
2148 if (!PointerInWindow(window))
2149 continue; /* window and pointer are on different screens */
2154 motion_status = TRUE;
2155 mx = ((MotionEvent *) &event)->x;
2156 my = ((MotionEvent *) &event)->y;
2160 motion_status = FALSE;
2161 mx = ((ButtonEvent *) &event)->x;
2162 my = ((ButtonEvent *) &event)->y;
2163 if (event.type == EVENT_BUTTONPRESS)
2164 button_status = ((ButtonEvent *) &event)->button;
2166 button_status = MB_RELEASED;
2169 /* this sets 'request_gadget_id' */
2170 HandleGadgets(mx, my, button_status);
2172 switch(request_gadget_id)
2174 case TOOL_CTRL_ID_YES:
2177 case TOOL_CTRL_ID_NO:
2180 case TOOL_CTRL_ID_CONFIRM:
2181 result = TRUE | FALSE;
2184 case TOOL_CTRL_ID_PLAYER_1:
2187 case TOOL_CTRL_ID_PLAYER_2:
2190 case TOOL_CTRL_ID_PLAYER_3:
2193 case TOOL_CTRL_ID_PLAYER_4:
2204 case EVENT_KEYPRESS:
2205 switch(GetEventKey((KeyEvent *)&event, TRUE))
2218 if (req_state & REQ_PLAYER)
2222 case EVENT_KEYRELEASE:
2223 ClearPlayerAction();
2227 HandleOtherEvents(&event);
2231 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
2233 int joy = AnyJoystick();
2235 if (joy & JOY_BUTTON_1)
2237 else if (joy & JOY_BUTTON_2)
2243 /* don't eat all CPU time */
2247 if (game_status != GAME_MODE_MAIN)
2252 if (!(req_state & REQ_STAY_OPEN))
2254 CloseDoor(DOOR_CLOSE_1);
2256 if (!(req_state & REQ_STAY_CLOSED) && (old_door_state & DOOR_OPEN_1))
2258 BlitBitmap(bitmap_db_door, bitmap_db_door,
2259 DOOR_GFX_PAGEX2,DOOR_GFX_PAGEY1, DXSIZE,DYSIZE,
2260 DOOR_GFX_PAGEX1,DOOR_GFX_PAGEY1);
2261 OpenDoor(DOOR_OPEN_1);
2267 SetDrawBackgroundMask(REDRAW_FIELD);
2269 #if defined(PLATFORM_UNIX)
2270 /* continue network game after request */
2271 if (options.network &&
2272 game_status == GAME_MODE_PLAYING &&
2273 req_state & REQUEST_WAIT_FOR)
2274 SendToServer_ContinuePlaying();
2280 unsigned int OpenDoor(unsigned int door_state)
2282 unsigned int new_door_state;
2284 if (door_state & DOOR_COPY_BACK)
2286 BlitBitmap(bitmap_db_door, bitmap_db_door,
2287 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE + VYSIZE,
2288 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2289 door_state &= ~DOOR_COPY_BACK;
2292 new_door_state = MoveDoor(door_state);
2294 return(new_door_state);
2297 unsigned int CloseDoor(unsigned int door_state)
2299 unsigned int new_door_state;
2301 BlitBitmap(backbuffer, bitmap_db_door,
2302 DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2303 BlitBitmap(backbuffer, bitmap_db_door,
2304 VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
2306 new_door_state = MoveDoor(door_state);
2308 return(new_door_state);
2311 unsigned int GetDoorState()
2313 return MoveDoor(DOOR_GET_STATE);
2316 unsigned int SetDoorState(unsigned int door_state)
2318 return MoveDoor(door_state | DOOR_SET_STATE);
2321 unsigned int MoveDoor(unsigned int door_state)
2323 static int door1 = DOOR_OPEN_1;
2324 static int door2 = DOOR_CLOSE_2;
2325 unsigned long door_delay = 0;
2326 unsigned long door_delay_value;
2329 if (door_state == DOOR_GET_STATE)
2330 return(door1 | door2);
2332 if (door_state & DOOR_SET_STATE)
2334 if (door_state & DOOR_ACTION_1)
2335 door1 = door_state & DOOR_ACTION_1;
2336 if (door_state & DOOR_ACTION_2)
2337 door2 = door_state & DOOR_ACTION_2;
2339 return(door1 | door2);
2342 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
2343 door_state &= ~DOOR_OPEN_1;
2344 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
2345 door_state &= ~DOOR_CLOSE_1;
2346 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
2347 door_state &= ~DOOR_OPEN_2;
2348 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
2349 door_state &= ~DOOR_CLOSE_2;
2351 door_delay_value = (door_state & DOOR_ACTION_1 ? door_1.step_delay :
2354 if (setup.quick_doors)
2356 stepsize = 20; /* must be choosen to always draw last frame */
2357 door_delay_value = 0;
2359 StopSound(SND_DOOR_OPENING);
2360 StopSound(SND_DOOR_CLOSING);
2363 if (global.autoplay_leveldir)
2365 door_state |= DOOR_NO_DELAY;
2366 door_state &= ~DOOR_CLOSE_ALL;
2369 if (door_state & DOOR_ACTION)
2371 boolean door_1_done = !(door_state & DOOR_ACTION_1);
2372 boolean door_2_done = !(door_state & DOOR_ACTION_2);
2373 int start = ((door_state & DOOR_NO_DELAY) ? DXSIZE : 0);
2374 int end = (door_state & DOOR_ACTION_1 &&
2375 door_1.anim_mode == ANIM_VERTICAL ? DYSIZE : DXSIZE);
2378 if (!(door_state & DOOR_NO_DELAY))
2380 /* opening door sound has priority over simultaneously closing door */
2381 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
2382 PlaySoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
2383 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
2384 PlaySoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
2387 for (x = start; x <= end && !(door_1_done && door_2_done); x += stepsize)
2389 Bitmap *bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
2390 GC gc = bitmap->stored_clip_gc;
2392 if (door_state & DOOR_ACTION_1)
2394 int a = MIN(x * door_1.step_offset, end);
2395 int i = (door_state & DOOR_OPEN_1 ? end - a : a);
2399 BlitBitmap(bitmap_db_door, drawto,
2400 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + i / 2,
2401 DXSIZE,DYSIZE - i / 2, DX, DY);
2403 ClearRectangle(drawto, DX, DY + DYSIZE - i / 2, DXSIZE, i / 2);
2406 if (door_1.anim_mode == ANIM_HORIZONTAL && x <= DXSIZE)
2408 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
2409 int dst1_x = DX + DXSIZE - i, dst1_y = DY;
2410 int src2_x = DXSIZE - i, src2_y = DOOR_GFX_PAGEY1;
2411 int dst2_x = DX, dst2_y = DY;
2412 int width = i, height = DYSIZE;
2414 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2415 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2418 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2419 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2422 else if (door_1.anim_mode == ANIM_VERTICAL && x <= DYSIZE)
2424 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
2425 int dst1_x = DX, dst1_y = DY + DYSIZE - i;
2426 int src2_x = 0, src2_y = DOOR_GFX_PAGEY1 + DYSIZE - i;
2427 int dst2_x = DX, dst2_y = DY;
2428 int width = DXSIZE, height = i;
2430 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2431 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2434 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2435 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2438 else if (x <= DXSIZE) /* ANIM_DEFAULT */
2440 int j = (door_1.anim_mode == ANIM_DEFAULT ? (DXSIZE - i) / 3 : 0);
2442 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2443 BlitBitmapMasked(bitmap, drawto,
2444 DXSIZE, DOOR_GFX_PAGEY1, i, 77,
2445 DX + DXSIZE - i, DY + j);
2446 BlitBitmapMasked(bitmap, drawto,
2447 DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63,
2448 DX + DXSIZE - i, DY + 140 + j);
2449 SetClipOrigin(bitmap, gc, DX - DXSIZE + i,
2450 DY - (DOOR_GFX_PAGEY1 + j));
2451 BlitBitmapMasked(bitmap, drawto,
2452 DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j,
2454 BlitBitmapMasked(bitmap, drawto,
2455 DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63,
2458 BlitBitmapMasked(bitmap, drawto,
2459 DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
2461 BlitBitmapMasked(bitmap, drawto,
2462 DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
2464 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2465 BlitBitmapMasked(bitmap, drawto,
2466 DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
2467 DX + DXSIZE - i, DY + 77 + j);
2468 BlitBitmapMasked(bitmap, drawto,
2469 DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
2470 DX + DXSIZE - i, DY + 203 + j);
2473 redraw_mask |= REDRAW_DOOR_1;
2474 door_1_done = (a == end);
2477 if (door_state & DOOR_ACTION_2)
2479 int a = MIN(x * door_2.step_offset, VXSIZE);
2480 int i = (door_state & DOOR_OPEN_2 ? VXSIZE - a : a);
2484 BlitBitmap(bitmap_db_door, drawto,
2485 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + i / 2,
2486 VXSIZE, VYSIZE - i / 2, VX, VY);
2488 ClearRectangle(drawto, VX, VY + VYSIZE - i / 2, VXSIZE, i / 2);
2491 if (door_2.anim_mode == ANIM_HORIZONTAL && x <= VXSIZE)
2493 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
2494 int dst1_x = VX + VXSIZE - i, dst1_y = VY;
2495 int src2_x = VXSIZE - i, src2_y = DOOR_GFX_PAGEY2;
2496 int dst2_x = VX, dst2_y = VY;
2497 int width = i, height = VYSIZE;
2499 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2500 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2503 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2504 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2507 else if (door_2.anim_mode == ANIM_VERTICAL && x <= VYSIZE)
2509 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
2510 int dst1_x = VX, dst1_y = VY + VYSIZE - i;
2511 int src2_x = 0, src2_y = DOOR_GFX_PAGEY2 + VYSIZE - i;
2512 int dst2_x = VX, dst2_y = VY;
2513 int width = VXSIZE, height = i;
2515 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2516 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2519 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2520 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2523 else if (x <= VXSIZE) /* ANIM_DEFAULT */
2525 int j = (door_2.anim_mode == ANIM_DEFAULT ? (VXSIZE - i) / 3 : 0);
2527 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2528 BlitBitmapMasked(bitmap, drawto,
2529 VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2,
2530 VX + VXSIZE - i, VY + j);
2531 SetClipOrigin(bitmap, gc,
2532 VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
2533 BlitBitmapMasked(bitmap, drawto,
2534 VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j,
2537 BlitBitmapMasked(bitmap, drawto,
2538 VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2,
2539 i, VYSIZE / 2, VX, VY + VYSIZE / 2 - j);
2540 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2541 BlitBitmapMasked(bitmap, drawto,
2542 VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2,
2544 VX + VXSIZE - i, VY + VYSIZE / 2 + j);
2547 redraw_mask |= REDRAW_DOOR_2;
2548 door_2_done = (a == VXSIZE);
2553 if (game_status == GAME_MODE_MAIN)
2556 if (!(door_state & DOOR_NO_DELAY))
2557 WaitUntilDelayReached(&door_delay, door_delay_value);
2561 if (setup.quick_doors)
2563 StopSound(SND_DOOR_OPENING);
2564 StopSound(SND_DOOR_CLOSING);
2567 if (door_state & DOOR_ACTION_1)
2568 door1 = door_state & DOOR_ACTION_1;
2569 if (door_state & DOOR_ACTION_2)
2570 door2 = door_state & DOOR_ACTION_2;
2572 return (door1 | door2);
2575 void DrawSpecialEditorDoor()
2577 /* draw bigger toolbox window */
2578 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
2579 DOOR_GFX_PAGEX7, 0, EXSIZE + 8, 8,
2581 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
2582 EX - 4, VY - 4, EXSIZE + 8, EYSIZE - VYSIZE + 4,
2585 redraw_mask |= REDRAW_ALL;
2588 void UndrawSpecialEditorDoor()
2590 /* draw normal tape recorder window */
2591 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
2592 EX - 4, EY - 12, EXSIZE + 8, EYSIZE - VYSIZE + 12,
2595 redraw_mask |= REDRAW_ALL;
2599 /* ---------- new tool button stuff ---------------------------------------- */
2601 /* graphic position values for tool buttons */
2602 #define TOOL_BUTTON_YES_XPOS 2
2603 #define TOOL_BUTTON_YES_YPOS 250
2604 #define TOOL_BUTTON_YES_GFX_YPOS 0
2605 #define TOOL_BUTTON_YES_XSIZE 46
2606 #define TOOL_BUTTON_YES_YSIZE 28
2607 #define TOOL_BUTTON_NO_XPOS 52
2608 #define TOOL_BUTTON_NO_YPOS TOOL_BUTTON_YES_YPOS
2609 #define TOOL_BUTTON_NO_GFX_YPOS TOOL_BUTTON_YES_GFX_YPOS
2610 #define TOOL_BUTTON_NO_XSIZE TOOL_BUTTON_YES_XSIZE
2611 #define TOOL_BUTTON_NO_YSIZE TOOL_BUTTON_YES_YSIZE
2612 #define TOOL_BUTTON_CONFIRM_XPOS TOOL_BUTTON_YES_XPOS
2613 #define TOOL_BUTTON_CONFIRM_YPOS TOOL_BUTTON_YES_YPOS
2614 #define TOOL_BUTTON_CONFIRM_GFX_YPOS 30
2615 #define TOOL_BUTTON_CONFIRM_XSIZE 96
2616 #define TOOL_BUTTON_CONFIRM_YSIZE TOOL_BUTTON_YES_YSIZE
2617 #define TOOL_BUTTON_PLAYER_XSIZE 30
2618 #define TOOL_BUTTON_PLAYER_YSIZE 30
2619 #define TOOL_BUTTON_PLAYER_GFX_XPOS 5
2620 #define TOOL_BUTTON_PLAYER_GFX_YPOS 185
2621 #define TOOL_BUTTON_PLAYER_XPOS (5 + TOOL_BUTTON_PLAYER_XSIZE / 2)
2622 #define TOOL_BUTTON_PLAYER_YPOS (215 - TOOL_BUTTON_PLAYER_YSIZE / 2)
2623 #define TOOL_BUTTON_PLAYER1_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2624 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2625 #define TOOL_BUTTON_PLAYER2_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2626 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2627 #define TOOL_BUTTON_PLAYER3_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2628 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2629 #define TOOL_BUTTON_PLAYER4_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2630 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2631 #define TOOL_BUTTON_PLAYER1_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2632 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2633 #define TOOL_BUTTON_PLAYER2_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2634 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2635 #define TOOL_BUTTON_PLAYER3_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2636 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2637 #define TOOL_BUTTON_PLAYER4_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2638 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2647 } toolbutton_info[NUM_TOOL_BUTTONS] =
2650 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_GFX_YPOS,
2651 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_YPOS,
2652 TOOL_BUTTON_YES_XSIZE, TOOL_BUTTON_YES_YSIZE,
2657 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_GFX_YPOS,
2658 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_YPOS,
2659 TOOL_BUTTON_NO_XSIZE, TOOL_BUTTON_NO_YSIZE,
2664 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_GFX_YPOS,
2665 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_YPOS,
2666 TOOL_BUTTON_CONFIRM_XSIZE, TOOL_BUTTON_CONFIRM_YSIZE,
2667 TOOL_CTRL_ID_CONFIRM,
2671 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2672 TOOL_BUTTON_PLAYER1_XPOS, TOOL_BUTTON_PLAYER1_YPOS,
2673 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2674 TOOL_CTRL_ID_PLAYER_1,
2678 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2679 TOOL_BUTTON_PLAYER2_XPOS, TOOL_BUTTON_PLAYER2_YPOS,
2680 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2681 TOOL_CTRL_ID_PLAYER_2,
2685 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2686 TOOL_BUTTON_PLAYER3_XPOS, TOOL_BUTTON_PLAYER3_YPOS,
2687 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2688 TOOL_CTRL_ID_PLAYER_3,
2692 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2693 TOOL_BUTTON_PLAYER4_XPOS, TOOL_BUTTON_PLAYER4_YPOS,
2694 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2695 TOOL_CTRL_ID_PLAYER_4,
2700 void CreateToolButtons()
2704 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
2706 Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
2707 Bitmap *deco_bitmap = None;
2708 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
2709 struct GadgetInfo *gi;
2710 unsigned long event_mask;
2711 int gd_xoffset, gd_yoffset;
2712 int gd_x1, gd_x2, gd_y;
2715 event_mask = GD_EVENT_RELEASED;
2717 gd_xoffset = toolbutton_info[i].xpos;
2718 gd_yoffset = toolbutton_info[i].ypos;
2719 gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
2720 gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
2721 gd_y = DOOR_GFX_PAGEY1 + gd_yoffset;
2723 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
2725 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
2727 getMiniGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr),
2728 &deco_bitmap, &deco_x, &deco_y);
2729 deco_xpos = (toolbutton_info[i].width - MINI_TILEX) / 2;
2730 deco_ypos = (toolbutton_info[i].height - MINI_TILEY) / 2;
2733 gi = CreateGadget(GDI_CUSTOM_ID, id,
2734 GDI_INFO_TEXT, toolbutton_info[i].infotext,
2735 GDI_X, DX + toolbutton_info[i].x,
2736 GDI_Y, DY + toolbutton_info[i].y,
2737 GDI_WIDTH, toolbutton_info[i].width,
2738 GDI_HEIGHT, toolbutton_info[i].height,
2739 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
2740 GDI_STATE, GD_BUTTON_UNPRESSED,
2741 GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
2742 GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
2743 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
2744 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
2745 GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
2746 GDI_DECORATION_SHIFTING, 1, 1,
2747 GDI_EVENT_MASK, event_mask,
2748 GDI_CALLBACK_ACTION, HandleToolButtons,
2752 Error(ERR_EXIT, "cannot create gadget");
2754 tool_gadget[id] = gi;
2758 void FreeToolButtons()
2762 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
2763 FreeGadget(tool_gadget[i]);
2766 static void UnmapToolButtons()
2770 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
2771 UnmapGadget(tool_gadget[i]);
2774 static void HandleToolButtons(struct GadgetInfo *gi)
2776 request_gadget_id = gi->custom_id;
2779 int get_next_element(int element)
2783 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
2784 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
2785 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
2786 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
2787 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
2788 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
2789 case EL_AMOEBA_DROPPING: return EL_AMOEBA_WET;
2791 default: return element;
2795 int el_act_dir2img(int element, int action, int direction)
2797 element = GFX_ELEMENT(element);
2798 direction = MV_DIR_BIT(direction);
2800 return element_info[element].direction_graphic[action][direction];
2803 static int el_act_dir2crm(int element, int action, int direction)
2805 element = GFX_ELEMENT(element);
2806 direction = MV_DIR_BIT(direction);
2808 return element_info[element].direction_crumbled[action][direction];
2811 int el_act2img(int element, int action)
2813 element = GFX_ELEMENT(element);
2815 return element_info[element].graphic[action];
2818 int el_act2crm(int element, int action)
2820 element = GFX_ELEMENT(element);
2822 return element_info[element].crumbled[action];
2825 int el_dir2img(int element, int direction)
2827 element = GFX_ELEMENT(element);
2829 return el_act_dir2img(element, ACTION_DEFAULT, direction);
2832 int el2img(int element)
2834 element = GFX_ELEMENT(element);
2836 return element_info[element].graphic[ACTION_DEFAULT];
2839 int el2edimg(int element)
2841 element = GFX_ELEMENT(element);
2843 return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
2846 int el2preimg(int element)
2848 element = GFX_ELEMENT(element);
2850 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];