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_FONT1_LEN 7
2007 #define MAX_REQUEST_LINE_FONT2_LEN 10
2009 boolean Request(char *text, unsigned int req_state)
2011 int mx, my, ty, result = -1;
2012 unsigned int old_door_state;
2013 int last_game_status = game_status; /* save current game status */
2014 int max_request_line_len = MAX_REQUEST_LINE_FONT1_LEN;
2015 int font_nr = FONT_TEXT_2;
2016 int max_word_len = 0;
2019 for (text_ptr = text; *text_ptr; text_ptr++)
2021 max_word_len = (*text_ptr != ' ' ? max_word_len + 1 : 0);
2023 if (max_word_len > MAX_REQUEST_LINE_FONT1_LEN)
2025 max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
2026 font_nr = FONT_LEVEL_NUMBER;
2033 SetMouseCursor(CURSOR_DEFAULT);
2036 #if defined(PLATFORM_UNIX)
2037 /* pause network game while waiting for request to answer */
2038 if (options.network &&
2039 game_status == GAME_MODE_PLAYING &&
2040 req_state & REQUEST_WAIT_FOR)
2041 SendToServer_PausePlaying();
2044 old_door_state = GetDoorState();
2046 /* simulate releasing mouse button over last gadget, if still pressed */
2048 HandleGadgets(-1, -1, 0);
2052 CloseDoor(DOOR_CLOSE_1);
2054 /* save old door content */
2055 BlitBitmap(bitmap_db_door, bitmap_db_door,
2056 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
2057 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
2059 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
2061 /* clear door drawing field */
2062 DrawBackground(DX, DY, DXSIZE, DYSIZE);
2064 /* force DOOR font on preview level */
2065 game_status = GAME_MODE_PSEUDO_DOOR;
2067 /* write text for request */
2068 for (ty = 0; ty < MAX_REQUEST_LINES; ty++)
2070 char text_line[max_request_line_len + 1];
2076 for (tl = 0, tx = 0; tx < max_request_line_len; tl++, tx++)
2079 if (!tc || tc == ' ')
2090 strncpy(text_line, text, tl);
2093 DrawText(DX + (DXSIZE - tl * getFontWidth(font_nr)) / 2,
2094 DY + 8 + ty * (getFontHeight(font_nr) + 2),
2095 text_line, font_nr);
2097 text += tl + (tc == ' ' ? 1 : 0);
2100 game_status = last_game_status; /* restore current game status */
2102 if (req_state & REQ_ASK)
2104 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
2105 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
2107 else if (req_state & REQ_CONFIRM)
2109 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
2111 else if (req_state & REQ_PLAYER)
2113 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
2114 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
2115 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
2116 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
2119 /* copy request gadgets to door backbuffer */
2120 BlitBitmap(drawto, bitmap_db_door,
2121 DX, DY, DXSIZE, DYSIZE,
2122 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2124 OpenDoor(DOOR_OPEN_1);
2130 if (!(req_state & REQUEST_WAIT_FOR))
2132 SetDrawBackgroundMask(REDRAW_FIELD);
2137 if (game_status != GAME_MODE_MAIN)
2140 button_status = MB_RELEASED;
2142 request_gadget_id = -1;
2144 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
2147 SetMouseCursor(CURSOR_DEFAULT);
2160 case EVENT_BUTTONPRESS:
2161 case EVENT_BUTTONRELEASE:
2162 case EVENT_MOTIONNOTIFY:
2164 if (event.type == EVENT_MOTIONNOTIFY)
2166 if (!PointerInWindow(window))
2167 continue; /* window and pointer are on different screens */
2172 motion_status = TRUE;
2173 mx = ((MotionEvent *) &event)->x;
2174 my = ((MotionEvent *) &event)->y;
2178 motion_status = FALSE;
2179 mx = ((ButtonEvent *) &event)->x;
2180 my = ((ButtonEvent *) &event)->y;
2181 if (event.type == EVENT_BUTTONPRESS)
2182 button_status = ((ButtonEvent *) &event)->button;
2184 button_status = MB_RELEASED;
2187 /* this sets 'request_gadget_id' */
2188 HandleGadgets(mx, my, button_status);
2190 switch(request_gadget_id)
2192 case TOOL_CTRL_ID_YES:
2195 case TOOL_CTRL_ID_NO:
2198 case TOOL_CTRL_ID_CONFIRM:
2199 result = TRUE | FALSE;
2202 case TOOL_CTRL_ID_PLAYER_1:
2205 case TOOL_CTRL_ID_PLAYER_2:
2208 case TOOL_CTRL_ID_PLAYER_3:
2211 case TOOL_CTRL_ID_PLAYER_4:
2222 case EVENT_KEYPRESS:
2223 switch(GetEventKey((KeyEvent *)&event, TRUE))
2236 if (req_state & REQ_PLAYER)
2240 case EVENT_KEYRELEASE:
2241 ClearPlayerAction();
2245 HandleOtherEvents(&event);
2249 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
2251 int joy = AnyJoystick();
2253 if (joy & JOY_BUTTON_1)
2255 else if (joy & JOY_BUTTON_2)
2261 /* don't eat all CPU time */
2265 if (game_status != GAME_MODE_MAIN)
2270 if (!(req_state & REQ_STAY_OPEN))
2272 CloseDoor(DOOR_CLOSE_1);
2274 if (!(req_state & REQ_STAY_CLOSED) && (old_door_state & DOOR_OPEN_1))
2276 BlitBitmap(bitmap_db_door, bitmap_db_door,
2277 DOOR_GFX_PAGEX2,DOOR_GFX_PAGEY1, DXSIZE,DYSIZE,
2278 DOOR_GFX_PAGEX1,DOOR_GFX_PAGEY1);
2279 OpenDoor(DOOR_OPEN_1);
2285 SetDrawBackgroundMask(REDRAW_FIELD);
2287 #if defined(PLATFORM_UNIX)
2288 /* continue network game after request */
2289 if (options.network &&
2290 game_status == GAME_MODE_PLAYING &&
2291 req_state & REQUEST_WAIT_FOR)
2292 SendToServer_ContinuePlaying();
2298 unsigned int OpenDoor(unsigned int door_state)
2300 unsigned int new_door_state;
2302 if (door_state & DOOR_COPY_BACK)
2304 BlitBitmap(bitmap_db_door, bitmap_db_door,
2305 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE + VYSIZE,
2306 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2307 door_state &= ~DOOR_COPY_BACK;
2310 new_door_state = MoveDoor(door_state);
2312 return(new_door_state);
2315 unsigned int CloseDoor(unsigned int door_state)
2317 unsigned int new_door_state;
2319 BlitBitmap(backbuffer, bitmap_db_door,
2320 DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2321 BlitBitmap(backbuffer, bitmap_db_door,
2322 VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
2324 new_door_state = MoveDoor(door_state);
2326 return(new_door_state);
2329 unsigned int GetDoorState()
2331 return MoveDoor(DOOR_GET_STATE);
2334 unsigned int SetDoorState(unsigned int door_state)
2336 return MoveDoor(door_state | DOOR_SET_STATE);
2339 unsigned int MoveDoor(unsigned int door_state)
2341 static int door1 = DOOR_OPEN_1;
2342 static int door2 = DOOR_CLOSE_2;
2343 unsigned long door_delay = 0;
2344 unsigned long door_delay_value;
2347 if (door_state == DOOR_GET_STATE)
2348 return(door1 | door2);
2350 if (door_state & DOOR_SET_STATE)
2352 if (door_state & DOOR_ACTION_1)
2353 door1 = door_state & DOOR_ACTION_1;
2354 if (door_state & DOOR_ACTION_2)
2355 door2 = door_state & DOOR_ACTION_2;
2357 return(door1 | door2);
2360 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
2361 door_state &= ~DOOR_OPEN_1;
2362 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
2363 door_state &= ~DOOR_CLOSE_1;
2364 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
2365 door_state &= ~DOOR_OPEN_2;
2366 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
2367 door_state &= ~DOOR_CLOSE_2;
2369 door_delay_value = (door_state & DOOR_ACTION_1 ? door_1.step_delay :
2372 if (setup.quick_doors)
2374 stepsize = 20; /* must be choosen to always draw last frame */
2375 door_delay_value = 0;
2377 StopSound(SND_DOOR_OPENING);
2378 StopSound(SND_DOOR_CLOSING);
2381 if (global.autoplay_leveldir)
2383 door_state |= DOOR_NO_DELAY;
2384 door_state &= ~DOOR_CLOSE_ALL;
2387 if (door_state & DOOR_ACTION)
2389 boolean door_1_done = !(door_state & DOOR_ACTION_1);
2390 boolean door_2_done = !(door_state & DOOR_ACTION_2);
2391 int start = ((door_state & DOOR_NO_DELAY) ? DXSIZE : 0);
2392 int end = (door_state & DOOR_ACTION_1 &&
2393 door_1.anim_mode == ANIM_VERTICAL ? DYSIZE : DXSIZE);
2396 if (!(door_state & DOOR_NO_DELAY))
2398 /* opening door sound has priority over simultaneously closing door */
2399 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
2400 PlaySoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
2401 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
2402 PlaySoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
2405 for (x = start; x <= end && !(door_1_done && door_2_done); x += stepsize)
2407 Bitmap *bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
2408 GC gc = bitmap->stored_clip_gc;
2410 if (door_state & DOOR_ACTION_1)
2412 int a = MIN(x * door_1.step_offset, end);
2413 int i = (door_state & DOOR_OPEN_1 ? end - a : a);
2417 BlitBitmap(bitmap_db_door, drawto,
2418 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + i / 2,
2419 DXSIZE,DYSIZE - i / 2, DX, DY);
2421 ClearRectangle(drawto, DX, DY + DYSIZE - i / 2, DXSIZE, i / 2);
2424 if (door_1.anim_mode == ANIM_HORIZONTAL && x <= DXSIZE)
2426 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
2427 int dst1_x = DX + DXSIZE - i, dst1_y = DY;
2428 int src2_x = DXSIZE - i, src2_y = DOOR_GFX_PAGEY1;
2429 int dst2_x = DX, dst2_y = DY;
2430 int width = i, height = DYSIZE;
2432 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2433 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2436 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2437 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2440 else if (door_1.anim_mode == ANIM_VERTICAL && x <= DYSIZE)
2442 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
2443 int dst1_x = DX, dst1_y = DY + DYSIZE - i;
2444 int src2_x = 0, src2_y = DOOR_GFX_PAGEY1 + DYSIZE - i;
2445 int dst2_x = DX, dst2_y = DY;
2446 int width = DXSIZE, height = i;
2448 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2449 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2452 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2453 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2456 else if (x <= DXSIZE) /* ANIM_DEFAULT */
2458 int j = (door_1.anim_mode == ANIM_DEFAULT ? (DXSIZE - i) / 3 : 0);
2460 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2461 BlitBitmapMasked(bitmap, drawto,
2462 DXSIZE, DOOR_GFX_PAGEY1, i, 77,
2463 DX + DXSIZE - i, DY + j);
2464 BlitBitmapMasked(bitmap, drawto,
2465 DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63,
2466 DX + DXSIZE - i, DY + 140 + j);
2467 SetClipOrigin(bitmap, gc, DX - DXSIZE + i,
2468 DY - (DOOR_GFX_PAGEY1 + j));
2469 BlitBitmapMasked(bitmap, drawto,
2470 DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j,
2472 BlitBitmapMasked(bitmap, drawto,
2473 DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63,
2476 BlitBitmapMasked(bitmap, drawto,
2477 DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
2479 BlitBitmapMasked(bitmap, drawto,
2480 DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
2482 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2483 BlitBitmapMasked(bitmap, drawto,
2484 DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
2485 DX + DXSIZE - i, DY + 77 + j);
2486 BlitBitmapMasked(bitmap, drawto,
2487 DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
2488 DX + DXSIZE - i, DY + 203 + j);
2491 redraw_mask |= REDRAW_DOOR_1;
2492 door_1_done = (a == end);
2495 if (door_state & DOOR_ACTION_2)
2497 int a = MIN(x * door_2.step_offset, VXSIZE);
2498 int i = (door_state & DOOR_OPEN_2 ? VXSIZE - a : a);
2502 BlitBitmap(bitmap_db_door, drawto,
2503 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + i / 2,
2504 VXSIZE, VYSIZE - i / 2, VX, VY);
2506 ClearRectangle(drawto, VX, VY + VYSIZE - i / 2, VXSIZE, i / 2);
2509 if (door_2.anim_mode == ANIM_HORIZONTAL && x <= VXSIZE)
2511 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
2512 int dst1_x = VX + VXSIZE - i, dst1_y = VY;
2513 int src2_x = VXSIZE - i, src2_y = DOOR_GFX_PAGEY2;
2514 int dst2_x = VX, dst2_y = VY;
2515 int width = i, height = VYSIZE;
2517 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2518 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2521 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2522 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2525 else if (door_2.anim_mode == ANIM_VERTICAL && x <= VYSIZE)
2527 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
2528 int dst1_x = VX, dst1_y = VY + VYSIZE - i;
2529 int src2_x = 0, src2_y = DOOR_GFX_PAGEY2 + VYSIZE - i;
2530 int dst2_x = VX, dst2_y = VY;
2531 int width = VXSIZE, height = i;
2533 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2534 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2537 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2538 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2541 else if (x <= VXSIZE) /* ANIM_DEFAULT */
2543 int j = (door_2.anim_mode == ANIM_DEFAULT ? (VXSIZE - i) / 3 : 0);
2545 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2546 BlitBitmapMasked(bitmap, drawto,
2547 VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2,
2548 VX + VXSIZE - i, VY + j);
2549 SetClipOrigin(bitmap, gc,
2550 VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
2551 BlitBitmapMasked(bitmap, drawto,
2552 VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j,
2555 BlitBitmapMasked(bitmap, drawto,
2556 VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2,
2557 i, VYSIZE / 2, VX, VY + VYSIZE / 2 - j);
2558 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2559 BlitBitmapMasked(bitmap, drawto,
2560 VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2,
2562 VX + VXSIZE - i, VY + VYSIZE / 2 + j);
2565 redraw_mask |= REDRAW_DOOR_2;
2566 door_2_done = (a == VXSIZE);
2571 if (game_status == GAME_MODE_MAIN)
2574 if (!(door_state & DOOR_NO_DELAY))
2575 WaitUntilDelayReached(&door_delay, door_delay_value);
2579 if (setup.quick_doors)
2581 StopSound(SND_DOOR_OPENING);
2582 StopSound(SND_DOOR_CLOSING);
2585 if (door_state & DOOR_ACTION_1)
2586 door1 = door_state & DOOR_ACTION_1;
2587 if (door_state & DOOR_ACTION_2)
2588 door2 = door_state & DOOR_ACTION_2;
2590 return (door1 | door2);
2593 void DrawSpecialEditorDoor()
2595 /* draw bigger toolbox window */
2596 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
2597 DOOR_GFX_PAGEX7, 0, EXSIZE + 8, 8,
2599 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
2600 EX - 4, VY - 4, EXSIZE + 8, EYSIZE - VYSIZE + 4,
2603 redraw_mask |= REDRAW_ALL;
2606 void UndrawSpecialEditorDoor()
2608 /* draw normal tape recorder window */
2609 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
2610 EX - 4, EY - 12, EXSIZE + 8, EYSIZE - VYSIZE + 12,
2613 redraw_mask |= REDRAW_ALL;
2617 /* ---------- new tool button stuff ---------------------------------------- */
2619 /* graphic position values for tool buttons */
2620 #define TOOL_BUTTON_YES_XPOS 2
2621 #define TOOL_BUTTON_YES_YPOS 250
2622 #define TOOL_BUTTON_YES_GFX_YPOS 0
2623 #define TOOL_BUTTON_YES_XSIZE 46
2624 #define TOOL_BUTTON_YES_YSIZE 28
2625 #define TOOL_BUTTON_NO_XPOS 52
2626 #define TOOL_BUTTON_NO_YPOS TOOL_BUTTON_YES_YPOS
2627 #define TOOL_BUTTON_NO_GFX_YPOS TOOL_BUTTON_YES_GFX_YPOS
2628 #define TOOL_BUTTON_NO_XSIZE TOOL_BUTTON_YES_XSIZE
2629 #define TOOL_BUTTON_NO_YSIZE TOOL_BUTTON_YES_YSIZE
2630 #define TOOL_BUTTON_CONFIRM_XPOS TOOL_BUTTON_YES_XPOS
2631 #define TOOL_BUTTON_CONFIRM_YPOS TOOL_BUTTON_YES_YPOS
2632 #define TOOL_BUTTON_CONFIRM_GFX_YPOS 30
2633 #define TOOL_BUTTON_CONFIRM_XSIZE 96
2634 #define TOOL_BUTTON_CONFIRM_YSIZE TOOL_BUTTON_YES_YSIZE
2635 #define TOOL_BUTTON_PLAYER_XSIZE 30
2636 #define TOOL_BUTTON_PLAYER_YSIZE 30
2637 #define TOOL_BUTTON_PLAYER_GFX_XPOS 5
2638 #define TOOL_BUTTON_PLAYER_GFX_YPOS 185
2639 #define TOOL_BUTTON_PLAYER_XPOS (5 + TOOL_BUTTON_PLAYER_XSIZE / 2)
2640 #define TOOL_BUTTON_PLAYER_YPOS (215 - TOOL_BUTTON_PLAYER_YSIZE / 2)
2641 #define TOOL_BUTTON_PLAYER1_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2642 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2643 #define TOOL_BUTTON_PLAYER2_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2644 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2645 #define TOOL_BUTTON_PLAYER3_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2646 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2647 #define TOOL_BUTTON_PLAYER4_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2648 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2649 #define TOOL_BUTTON_PLAYER1_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2650 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2651 #define TOOL_BUTTON_PLAYER2_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2652 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2653 #define TOOL_BUTTON_PLAYER3_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2654 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2655 #define TOOL_BUTTON_PLAYER4_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2656 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2665 } toolbutton_info[NUM_TOOL_BUTTONS] =
2668 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_GFX_YPOS,
2669 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_YPOS,
2670 TOOL_BUTTON_YES_XSIZE, TOOL_BUTTON_YES_YSIZE,
2675 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_GFX_YPOS,
2676 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_YPOS,
2677 TOOL_BUTTON_NO_XSIZE, TOOL_BUTTON_NO_YSIZE,
2682 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_GFX_YPOS,
2683 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_YPOS,
2684 TOOL_BUTTON_CONFIRM_XSIZE, TOOL_BUTTON_CONFIRM_YSIZE,
2685 TOOL_CTRL_ID_CONFIRM,
2689 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2690 TOOL_BUTTON_PLAYER1_XPOS, TOOL_BUTTON_PLAYER1_YPOS,
2691 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2692 TOOL_CTRL_ID_PLAYER_1,
2696 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2697 TOOL_BUTTON_PLAYER2_XPOS, TOOL_BUTTON_PLAYER2_YPOS,
2698 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2699 TOOL_CTRL_ID_PLAYER_2,
2703 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2704 TOOL_BUTTON_PLAYER3_XPOS, TOOL_BUTTON_PLAYER3_YPOS,
2705 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2706 TOOL_CTRL_ID_PLAYER_3,
2710 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2711 TOOL_BUTTON_PLAYER4_XPOS, TOOL_BUTTON_PLAYER4_YPOS,
2712 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2713 TOOL_CTRL_ID_PLAYER_4,
2718 void CreateToolButtons()
2722 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
2724 Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
2725 Bitmap *deco_bitmap = None;
2726 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
2727 struct GadgetInfo *gi;
2728 unsigned long event_mask;
2729 int gd_xoffset, gd_yoffset;
2730 int gd_x1, gd_x2, gd_y;
2733 event_mask = GD_EVENT_RELEASED;
2735 gd_xoffset = toolbutton_info[i].xpos;
2736 gd_yoffset = toolbutton_info[i].ypos;
2737 gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
2738 gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
2739 gd_y = DOOR_GFX_PAGEY1 + gd_yoffset;
2741 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
2743 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
2745 getMiniGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr),
2746 &deco_bitmap, &deco_x, &deco_y);
2747 deco_xpos = (toolbutton_info[i].width - MINI_TILEX) / 2;
2748 deco_ypos = (toolbutton_info[i].height - MINI_TILEY) / 2;
2751 gi = CreateGadget(GDI_CUSTOM_ID, id,
2752 GDI_INFO_TEXT, toolbutton_info[i].infotext,
2753 GDI_X, DX + toolbutton_info[i].x,
2754 GDI_Y, DY + toolbutton_info[i].y,
2755 GDI_WIDTH, toolbutton_info[i].width,
2756 GDI_HEIGHT, toolbutton_info[i].height,
2757 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
2758 GDI_STATE, GD_BUTTON_UNPRESSED,
2759 GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
2760 GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
2761 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
2762 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
2763 GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
2764 GDI_DECORATION_SHIFTING, 1, 1,
2765 GDI_EVENT_MASK, event_mask,
2766 GDI_CALLBACK_ACTION, HandleToolButtons,
2770 Error(ERR_EXIT, "cannot create gadget");
2772 tool_gadget[id] = gi;
2776 void FreeToolButtons()
2780 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
2781 FreeGadget(tool_gadget[i]);
2784 static void UnmapToolButtons()
2788 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
2789 UnmapGadget(tool_gadget[i]);
2792 static void HandleToolButtons(struct GadgetInfo *gi)
2794 request_gadget_id = gi->custom_id;
2797 int get_next_element(int element)
2801 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
2802 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
2803 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
2804 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
2805 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
2806 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
2807 case EL_AMOEBA_DROPPING: return EL_AMOEBA_WET;
2809 default: return element;
2813 int el_act_dir2img(int element, int action, int direction)
2815 element = GFX_ELEMENT(element);
2816 direction = MV_DIR_BIT(direction);
2818 return element_info[element].direction_graphic[action][direction];
2821 static int el_act_dir2crm(int element, int action, int direction)
2823 element = GFX_ELEMENT(element);
2824 direction = MV_DIR_BIT(direction);
2826 return element_info[element].direction_crumbled[action][direction];
2829 int el_act2img(int element, int action)
2831 element = GFX_ELEMENT(element);
2833 return element_info[element].graphic[action];
2836 int el_act2crm(int element, int action)
2838 element = GFX_ELEMENT(element);
2840 return element_info[element].crumbled[action];
2843 int el_dir2img(int element, int direction)
2845 element = GFX_ELEMENT(element);
2847 return el_act_dir2img(element, ACTION_DEFAULT, direction);
2850 int el2img(int element)
2852 element = GFX_ELEMENT(element);
2854 return element_info[element].graphic[ACTION_DEFAULT];
2857 int el2edimg(int element)
2859 element = GFX_ELEMENT(element);
2861 return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
2864 int el2preimg(int element)
2866 element = GFX_ELEMENT(element);
2868 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];