1 /***********************************************************
2 * Rocks'n'Diamonds -- McDuffin Strikes Back! *
3 *----------------------------------------------------------*
4 * (c) 1995-2002 Artsoft Entertainment *
6 * Detmolder Strasse 189 *
9 * e-mail: info@artsoft.org *
10 *----------------------------------------------------------*
12 ***********************************************************/
14 #include "libgame/libgame.h"
23 /* tool button identifiers */
24 #define TOOL_CTRL_ID_YES 0
25 #define TOOL_CTRL_ID_NO 1
26 #define TOOL_CTRL_ID_CONFIRM 2
27 #define TOOL_CTRL_ID_PLAYER_1 3
28 #define TOOL_CTRL_ID_PLAYER_2 4
29 #define TOOL_CTRL_ID_PLAYER_3 5
30 #define TOOL_CTRL_ID_PLAYER_4 6
32 #define NUM_TOOL_BUTTONS 7
34 /* forward declaration for internal use */
35 static void UnmapToolButtons();
36 static void HandleToolButtons(struct GadgetInfo *);
37 static int el_act_dir2crm(int, int, int);
38 static int el_act2crm(int, int);
40 static struct GadgetInfo *tool_gadget[NUM_TOOL_BUTTONS];
41 static int request_gadget_id = -1;
43 void SetDrawtoField(int mode)
45 if (mode == DRAW_BUFFERED && setup.soft_scrolling)
56 drawto_field = fieldbuffer;
58 else /* DRAW_DIRECT, DRAW_BACKBUFFER */
69 drawto_field = (mode == DRAW_DIRECT ? window : backbuffer);
73 void RedrawPlayfield(boolean force_redraw, int x, int y, int width, int height)
75 if (game_status == GAME_MODE_PLAYING && !game.envelope_active)
81 width = gfx.sxsize + 2 * TILEX;
82 height = gfx.sysize + 2 * TILEY;
85 if (force_redraw || setup.direct_draw)
88 int x1 = (x - SX) / TILEX, y1 = (y - SY) / TILEY;
89 int x2 = (x - SX + width) / TILEX, y2 = (y - SY + height) / TILEY;
91 if (setup.direct_draw)
92 SetDrawtoField(DRAW_BACKBUFFER);
94 for (xx = BX1; xx <= BX2; xx++)
95 for (yy = BY1; yy <= BY2; yy++)
96 if (xx >= x1 && xx <= x2 && yy >= y1 && yy <= y2)
97 DrawScreenField(xx, yy);
100 if (setup.direct_draw)
101 SetDrawtoField(DRAW_DIRECT);
104 if (setup.soft_scrolling)
106 int fx = FX, fy = FY;
108 fx += (ScreenMovDir & (MV_LEFT|MV_RIGHT) ? ScreenGfxPos : 0);
109 fy += (ScreenMovDir & (MV_UP|MV_DOWN) ? ScreenGfxPos : 0);
111 BlitBitmap(fieldbuffer, backbuffer, fx,fy, SXSIZE,SYSIZE, SX,SY);
115 BlitBitmap(drawto, window, x, y, width, height, x, y);
121 DrawBuffer *buffer = (drawto_field == window ? backbuffer : drawto_field);
123 if (setup.direct_draw && game_status == GAME_MODE_PLAYING)
124 redraw_mask &= ~REDRAW_MAIN;
126 if (redraw_mask & REDRAW_TILES && redraw_tiles > REDRAWTILES_THRESHOLD)
127 redraw_mask |= REDRAW_FIELD;
129 if (redraw_mask & REDRAW_FIELD)
130 redraw_mask &= ~REDRAW_TILES;
132 if (redraw_mask == REDRAW_NONE)
135 if (global.fps_slowdown && game_status == GAME_MODE_PLAYING)
137 static boolean last_frame_skipped = FALSE;
138 boolean skip_even_when_not_scrolling = TRUE;
139 boolean just_scrolling = (ScreenMovDir != 0);
140 boolean verbose = FALSE;
142 if (global.fps_slowdown_factor > 1 &&
143 (FrameCounter % global.fps_slowdown_factor) &&
144 (just_scrolling || skip_even_when_not_scrolling))
146 redraw_mask &= ~REDRAW_MAIN;
148 last_frame_skipped = TRUE;
151 printf("FRAME SKIPPED\n");
155 if (last_frame_skipped)
156 redraw_mask |= REDRAW_FIELD;
158 last_frame_skipped = FALSE;
161 printf("frame not skipped\n");
165 /* synchronize X11 graphics at this point; if we would synchronize the
166 display immediately after the buffer switching (after the XFlush),
167 this could mean that we have to wait for the graphics to complete,
168 although we could go on doing calculations for the next frame */
172 if (redraw_mask & REDRAW_ALL)
174 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
178 if (redraw_mask & REDRAW_FIELD)
180 if (game_status != GAME_MODE_PLAYING ||
181 redraw_mask & REDRAW_FROM_BACKBUFFER)
183 BlitBitmap(backbuffer, window,
184 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE, REAL_SX, REAL_SY);
188 int fx = FX, fy = FY;
190 if (setup.soft_scrolling)
192 fx += (ScreenMovDir & (MV_LEFT | MV_RIGHT) ? ScreenGfxPos : 0);
193 fy += (ScreenMovDir & (MV_UP | MV_DOWN) ? ScreenGfxPos : 0);
196 if (setup.soft_scrolling ||
197 ABS(ScreenMovPos) + ScrollStepSize == TILEX ||
198 ABS(ScreenMovPos) == ScrollStepSize ||
199 redraw_tiles > REDRAWTILES_THRESHOLD)
201 BlitBitmap(buffer, window, fx, fy, SXSIZE, SYSIZE, SX, SY);
205 printf("redrawing all (ScreenGfxPos == %d) because %s\n",
207 (setup.soft_scrolling ?
208 "setup.soft_scrolling" :
209 ABS(ScreenGfxPos) + ScrollStepSize == TILEX ?
210 "ABS(ScreenGfxPos) + ScrollStepSize == TILEX" :
211 ABS(ScreenGfxPos) == ScrollStepSize ?
212 "ABS(ScreenGfxPos) == ScrollStepSize" :
213 "redraw_tiles > REDRAWTILES_THRESHOLD"));
219 redraw_mask &= ~REDRAW_MAIN;
222 if (redraw_mask & REDRAW_DOORS)
224 if (redraw_mask & REDRAW_DOOR_1)
225 BlitBitmap(backbuffer, window, DX, DY, DXSIZE, DYSIZE, DX, DY);
226 if (redraw_mask & REDRAW_DOOR_2)
228 if ((redraw_mask & REDRAW_DOOR_2) == REDRAW_DOOR_2)
229 BlitBitmap(backbuffer, window, VX,VY, VXSIZE,VYSIZE, VX,VY);
232 if (redraw_mask & REDRAW_VIDEO_1)
233 BlitBitmap(backbuffer, window,
234 VX+VIDEO_DISPLAY1_XPOS,VY+VIDEO_DISPLAY1_YPOS,
235 VIDEO_DISPLAY_XSIZE,VIDEO_DISPLAY_YSIZE,
236 VX+VIDEO_DISPLAY1_XPOS,VY+VIDEO_DISPLAY1_YPOS);
237 if (redraw_mask & REDRAW_VIDEO_2)
238 BlitBitmap(backbuffer, window,
239 VX+VIDEO_DISPLAY2_XPOS,VY+VIDEO_DISPLAY2_YPOS,
240 VIDEO_DISPLAY_XSIZE,VIDEO_DISPLAY_YSIZE,
241 VX+VIDEO_DISPLAY2_XPOS,VY+VIDEO_DISPLAY2_YPOS);
242 if (redraw_mask & REDRAW_VIDEO_3)
243 BlitBitmap(backbuffer, window,
244 VX+VIDEO_CONTROL_XPOS,VY+VIDEO_CONTROL_YPOS,
245 VIDEO_CONTROL_XSIZE,VIDEO_CONTROL_YSIZE,
246 VX+VIDEO_CONTROL_XPOS,VY+VIDEO_CONTROL_YPOS);
250 if (redraw_mask & REDRAW_DOOR_3)
251 BlitBitmap(backbuffer, window, EX, EY, EXSIZE, EYSIZE, EX, EY);
253 redraw_mask &= ~REDRAW_DOORS;
256 if (redraw_mask & REDRAW_MICROLEVEL)
258 BlitBitmap(backbuffer, window, SX, SY + 10 * TILEY, SXSIZE, 7 * TILEY,
259 SX, SY + 10 * TILEY);
261 redraw_mask &= ~REDRAW_MICROLEVEL;
264 if (redraw_mask & REDRAW_TILES)
266 for (x = 0; x < SCR_FIELDX; x++)
267 for (y =0 ; y < SCR_FIELDY; y++)
268 if (redraw[redraw_x1 + x][redraw_y1 + y])
269 BlitBitmap(buffer, window,
270 FX + x * TILEX, FX + y * TILEY, TILEX, TILEY,
271 SX + x * TILEX, SY + y * TILEY);
274 if (redraw_mask & REDRAW_FPS) /* display frames per second */
279 sprintf(info1, " (only every %d. frame)", global.fps_slowdown_factor);
280 if (!global.fps_slowdown)
283 sprintf(text, "%.1f fps%s", global.frames_per_second, info1);
284 DrawTextExt(window, SX, SY, text, FONT_TEXT_2, BLIT_OPAQUE);
289 for (x = 0; x < MAX_BUF_XSIZE; x++)
290 for (y = 0; y < MAX_BUF_YSIZE; y++)
293 redraw_mask = REDRAW_NONE;
299 long fading_delay = 300;
301 if (setup.fading && (redraw_mask & REDRAW_FIELD))
308 ClearRectangle(window, REAL_SX,REAL_SY,FULL_SXSIZE,FULL_SYSIZE);
311 for (i = 0; i < 2 * FULL_SYSIZE; i++)
313 for (y = 0; y < FULL_SYSIZE; y++)
315 BlitBitmap(backbuffer, window,
316 REAL_SX,REAL_SY+i, FULL_SXSIZE,1, REAL_SX,REAL_SY+i);
324 for (i = 1; i < FULL_SYSIZE; i+=2)
325 BlitBitmap(backbuffer, window,
326 REAL_SX,REAL_SY+i, FULL_SXSIZE,1, REAL_SX,REAL_SY+i);
332 SetClipOrigin(clip_gc[PIX_FADEMASK], 0, 0);
333 BlitBitmapMasked(backbuffer, window,
334 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
339 SetClipOrigin(clip_gc[PIX_FADEMASK], -1, -1);
340 BlitBitmapMasked(backbuffer, window,
341 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
346 SetClipOrigin(clip_gc[PIX_FADEMASK], 0, -1);
347 BlitBitmapMasked(backbuffer, window,
348 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
353 SetClipOrigin(clip_gc[PIX_FADEMASK], -1, 0);
354 BlitBitmapMasked(backbuffer, window,
355 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
360 redraw_mask &= ~REDRAW_MAIN;
367 void SetMainBackgroundImage(int graphic)
369 SetMainBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
370 graphic_info[graphic].bitmap ?
371 graphic_info[graphic].bitmap :
372 graphic_info[IMG_BACKGROUND].bitmap);
375 void SetDoorBackgroundImage(int graphic)
377 SetDoorBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
378 graphic_info[graphic].bitmap ?
379 graphic_info[graphic].bitmap :
380 graphic_info[IMG_BACKGROUND].bitmap);
383 void DrawBackground(int dest_x, int dest_y, int width, int height)
385 ClearRectangleOnBackground(backbuffer, dest_x, dest_y, width, height);
387 redraw_mask |= REDRAW_FIELD;
392 DrawBackground(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
394 if (setup.soft_scrolling && game_status == GAME_MODE_PLAYING)
396 ClearRectangle(fieldbuffer, 0, 0, FXSIZE, FYSIZE);
397 SetDrawtoField(DRAW_BUFFERED);
400 SetDrawtoField(DRAW_BACKBUFFER);
402 if (setup.direct_draw && game_status == GAME_MODE_PLAYING)
404 ClearRectangle(window, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
405 SetDrawtoField(DRAW_DIRECT);
409 void MarkTileDirty(int x, int y)
411 int xx = redraw_x1 + x;
412 int yy = redraw_y1 + y;
417 redraw[xx][yy] = TRUE;
418 redraw_mask |= REDRAW_TILES;
421 void SetBorderElement()
425 BorderElement = EL_EMPTY;
427 for (y = 0; y < lev_fieldy && BorderElement == EL_EMPTY; y++)
429 for (x = 0; x < lev_fieldx; x++)
431 if (!IS_INDESTRUCTIBLE(Feld[x][y]))
432 BorderElement = EL_STEELWALL;
434 if (y != 0 && y != lev_fieldy - 1 && x != lev_fieldx - 1)
440 void SetRandomAnimationValue(int x, int y)
442 gfx.anim_random_frame = GfxRandom[x][y];
445 inline int getGraphicAnimationFrame(int graphic, int sync_frame)
447 /* animation synchronized with global frame counter, not move position */
448 if (graphic_info[graphic].anim_global_sync || sync_frame < 0)
449 sync_frame = FrameCounter;
451 return getAnimationFrame(graphic_info[graphic].anim_frames,
452 graphic_info[graphic].anim_delay,
453 graphic_info[graphic].anim_mode,
454 graphic_info[graphic].anim_start_frame,
458 inline void DrawGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
459 int graphic, int sync_frame, int mask_mode)
461 int frame = getGraphicAnimationFrame(graphic, sync_frame);
463 if (mask_mode == USE_MASKING)
464 DrawGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
466 DrawGraphicExt(dst_bitmap, x, y, graphic, frame);
469 inline void DrawGraphicAnimation(int x, int y, int graphic)
471 int lx = LEVELX(x), ly = LEVELY(y);
473 if (!IN_SCR_FIELD(x, y))
476 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
477 graphic, GfxFrame[lx][ly], NO_MASKING);
481 void DrawLevelGraphicAnimation(int x, int y, int graphic)
483 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
486 void DrawLevelElementAnimation(int x, int y, int element)
489 int graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
491 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
493 DrawGraphicAnimation(SCREENX(x), SCREENY(y), el2img(element));
497 inline void DrawLevelGraphicAnimationIfNeeded(int x, int y, int graphic)
499 int sx = SCREENX(x), sy = SCREENY(y);
501 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
504 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
507 DrawGraphicAnimation(sx, sy, graphic);
509 if (GFX_CRUMBLED(Feld[x][y]))
510 DrawLevelFieldCrumbledSand(x, y);
513 void DrawLevelElementAnimationIfNeeded(int x, int y, int element)
515 int sx = SCREENX(x), sy = SCREENY(y);
518 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
521 graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
523 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
526 DrawGraphicAnimation(sx, sy, graphic);
528 if (GFX_CRUMBLED(element))
529 DrawLevelFieldCrumbledSand(x, y);
532 static int getPlayerGraphic(struct PlayerInfo *player, int move_dir)
534 if (player->use_murphy_graphic)
536 /* this works only because currently only one player can be "murphy" ... */
537 static int last_horizontal_dir = MV_LEFT;
538 int graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, move_dir);
540 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
541 last_horizontal_dir = move_dir;
543 if (graphic == IMG_SP_MURPHY) /* undefined => use special graphic */
545 int direction = (player->is_snapping ? move_dir : last_horizontal_dir);
547 graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, direction);
553 return el_act_dir2img(player->element_nr, player->GfxAction, move_dir);
556 static boolean equalGraphics(int graphic1, int graphic2)
558 struct GraphicInfo *g1 = &graphic_info[graphic1];
559 struct GraphicInfo *g2 = &graphic_info[graphic2];
561 return (g1->bitmap == g2->bitmap &&
562 g1->src_x == g2->src_x &&
563 g1->src_y == g2->src_y &&
564 g1->anim_frames == g2->anim_frames &&
565 g1->anim_delay == g2->anim_delay &&
566 g1->anim_mode == g2->anim_mode);
569 void DrawAllPlayers()
573 for (i = 0; i < MAX_PLAYERS; i++)
574 if (stored_player[i].active)
575 DrawPlayer(&stored_player[i]);
578 void DrawPlayerField(int x, int y)
580 if (!IS_PLAYER(x, y))
583 DrawPlayer(PLAYERINFO(x, y));
586 void DrawPlayer(struct PlayerInfo *player)
590 int move_dir = player->MovDir;
592 int last_jx = player->last_jx;
593 int last_jy = player->last_jy;
594 int next_jx = jx + (jx - last_jx);
595 int next_jy = jy + (jy - last_jy);
596 boolean player_is_moving = (last_jx != jx || last_jy != jy ? TRUE : FALSE);
598 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? +1 : 0);
599 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? +1 : 0);
600 int last_jx = (player->is_moving ? jx - dx : jx);
601 int last_jy = (player->is_moving ? jy - dy : jy);
602 int next_jx = jx + dx;
603 int next_jy = jy + dy;
604 boolean player_is_moving = (player->MovPos ? TRUE : FALSE);
606 int sx = SCREENX(jx), sy = SCREENY(jy);
607 int sxx = 0, syy = 0;
608 int element = Feld[jx][jy], last_element = Feld[last_jx][last_jy];
610 int action = ACTION_DEFAULT;
611 int last_player_graphic = getPlayerGraphic(player, move_dir);
612 int last_player_frame = player->Frame;
615 if (!player->active || !IN_SCR_FIELD(SCREENX(last_jx), SCREENY(last_jy)))
619 if (!IN_LEV_FIELD(jx, jy))
621 printf("DrawPlayerField(): x = %d, y = %d\n",jx,jy);
622 printf("DrawPlayerField(): sx = %d, sy = %d\n",sx,sy);
623 printf("DrawPlayerField(): This should never happen!\n");
628 if (element == EL_EXPLOSION)
631 action = (player->is_pushing ? ACTION_PUSHING :
632 player->is_digging ? ACTION_DIGGING :
633 player->is_collecting ? ACTION_COLLECTING :
634 player->is_moving ? ACTION_MOVING :
635 player->is_snapping ? ACTION_SNAPPING :
636 player->is_dropping ? ACTION_DROPPING :
637 player->is_waiting ? player->action_waiting : ACTION_DEFAULT);
639 InitPlayerGfxAnimation(player, action, move_dir);
641 /* ----------------------------------------------------------------------- */
642 /* draw things in the field the player is leaving, if needed */
643 /* ----------------------------------------------------------------------- */
646 if (player->is_moving)
648 if (player_is_moving)
651 if (Back[last_jx][last_jy] && IS_DRAWABLE(last_element))
653 DrawLevelElement(last_jx, last_jy, Back[last_jx][last_jy]);
655 if (last_element == EL_DYNAMITE_ACTIVE ||
656 last_element == EL_SP_DISK_RED_ACTIVE)
657 DrawDynamite(last_jx, last_jy);
659 DrawLevelFieldThruMask(last_jx, last_jy);
661 else if (last_element == EL_DYNAMITE_ACTIVE ||
662 last_element == EL_SP_DISK_RED_ACTIVE)
663 DrawDynamite(last_jx, last_jy);
665 DrawLevelField(last_jx, last_jy);
667 if (player->is_pushing && IN_SCR_FIELD(SCREENX(next_jx), SCREENY(next_jy)))
668 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
671 if (!IN_SCR_FIELD(sx, sy))
674 if (setup.direct_draw)
675 SetDrawtoField(DRAW_BUFFERED);
677 /* ----------------------------------------------------------------------- */
678 /* draw things behind the player, if needed */
679 /* ----------------------------------------------------------------------- */
682 DrawLevelElement(jx, jy, Back[jx][jy]);
683 else if (IS_ACTIVE_BOMB(element))
684 DrawLevelElement(jx, jy, EL_EMPTY);
687 if (player_is_moving && GfxElement[jx][jy] != EL_UNDEFINED)
689 if (GFX_CRUMBLED(GfxElement[jx][jy]))
690 DrawLevelFieldCrumbledSandDigging(jx, jy, move_dir, player->StepFrame);
693 int old_element = GfxElement[jx][jy];
694 int old_graphic = el_act_dir2img(old_element, action, move_dir);
695 int frame = getGraphicAnimationFrame(old_graphic, player->StepFrame);
697 DrawGraphic(sx, sy, old_graphic, frame);
702 GfxElement[jx][jy] = EL_UNDEFINED;
704 DrawLevelField(jx, jy);
708 /* ----------------------------------------------------------------------- */
709 /* draw player himself */
710 /* ----------------------------------------------------------------------- */
714 graphic = getPlayerGraphic(player, move_dir);
716 /* in the case of changed player action or direction, prevent the current
717 animation frame from being restarted for identical animations */
718 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
719 player->Frame = last_player_frame;
723 if (player->use_murphy_graphic)
725 static int last_horizontal_dir = MV_LEFT;
727 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
728 last_horizontal_dir = move_dir;
730 graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, move_dir);
732 if (graphic == IMG_SP_MURPHY) /* undefined => use special graphic */
734 int direction = (player->is_snapping ? move_dir : last_horizontal_dir);
736 graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, direction);
740 graphic = el_act_dir2img(player->element_nr, player->GfxAction, move_dir);
744 frame = getGraphicAnimationFrame(graphic, player->Frame);
748 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
749 sxx = player->GfxPos;
751 syy = player->GfxPos;
754 if (!setup.soft_scrolling && ScreenMovPos)
757 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
759 if (SHIELD_ON(player))
761 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
762 IMG_SHIELD_NORMAL_ACTIVE);
763 int frame = getGraphicAnimationFrame(graphic, -1);
765 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
768 /* ----------------------------------------------------------------------- */
769 /* draw things the player is pushing, if needed */
770 /* ----------------------------------------------------------------------- */
773 printf("::: %d, %d [%d, %d] [%d]\n",
774 player->is_pushing, player_is_moving, player->GfxAction,
775 player->is_moving, player_is_moving);
779 if (player->is_pushing && player->is_moving)
781 if (player->is_pushing && player_is_moving)
784 int px = SCREENX(next_jx), py = SCREENY(next_jy);
786 if (Back[next_jx][next_jy])
787 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
789 if ((sxx || syy) && element == EL_SOKOBAN_OBJECT)
790 DrawGraphicShiftedThruMask(px, py, sxx, syy, IMG_SOKOBAN_OBJECT, 0,
794 int element = MovingOrBlocked2Element(next_jx, next_jy);
795 int graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
797 int frame = getGraphicAnimationFrame(graphic, player->StepFrame);
799 int frame = getGraphicAnimationFrame(graphic, player->Frame);
802 DrawGraphicShifted(px, py, sxx, syy, graphic, frame,
803 NO_CUTTING, NO_MASKING);
807 /* ----------------------------------------------------------------------- */
808 /* draw things in front of player (active dynamite or dynabombs) */
809 /* ----------------------------------------------------------------------- */
811 if (IS_ACTIVE_BOMB(element))
813 graphic = el2img(element);
814 frame = getGraphicAnimationFrame(graphic, GfxFrame[jx][jy]);
816 if (game.emulation == EMU_SUPAPLEX)
817 DrawGraphic(sx, sy, IMG_SP_DISK_RED, frame);
819 DrawGraphicThruMask(sx, sy, graphic, frame);
822 if (player_is_moving && last_element == EL_EXPLOSION)
824 int graphic = el_act2img(GfxElement[last_jx][last_jy], ACTION_EXPLODING);
825 int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
826 int phase = ExplodePhase[last_jx][last_jy] - 1;
827 int frame = getGraphicAnimationFrame(graphic, phase - delay);
830 DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy), graphic, frame);
833 /* ----------------------------------------------------------------------- */
834 /* draw elements the player is just walking/passing through/under */
835 /* ----------------------------------------------------------------------- */
837 /* handle the field the player is leaving ... */
838 if (player_is_moving && IS_ACCESSIBLE_INSIDE(last_element))
839 DrawLevelField(last_jx, last_jy);
840 else if (player_is_moving && IS_ACCESSIBLE_UNDER(last_element))
841 DrawLevelFieldThruMask(last_jx, last_jy);
843 /* ... and the field the player is entering */
844 if (IS_ACCESSIBLE_INSIDE(element))
845 DrawLevelField(jx, jy);
846 else if (IS_ACCESSIBLE_UNDER(element))
847 DrawLevelFieldThruMask(jx, jy);
849 if (setup.direct_draw)
851 int dest_x = SX + SCREENX(MIN(jx, last_jx)) * TILEX;
852 int dest_y = SY + SCREENY(MIN(jy, last_jy)) * TILEY;
853 int x_size = TILEX * (1 + ABS(jx - last_jx));
854 int y_size = TILEY * (1 + ABS(jy - last_jy));
856 BlitBitmap(drawto_field, window,
857 dest_x, dest_y, x_size, y_size, dest_x, dest_y);
858 SetDrawtoField(DRAW_DIRECT);
861 MarkTileDirty(sx, sy);
864 void getGraphicSource(int graphic, int frame, Bitmap **bitmap, int *x, int *y)
866 struct GraphicInfo *g = &graphic_info[graphic];
870 if (g->offset_y == 0) /* frames are ordered horizontally */
872 int max_width = g->anim_frames_per_line * g->width;
874 *x = (g->src_x + frame * g->offset_x) % max_width;
875 *y = g->src_y + (g->src_x + frame * g->offset_x) / max_width * g->height;
877 else if (g->offset_x == 0) /* frames are ordered vertically */
879 int max_height = g->anim_frames_per_line * g->height;
881 *x = g->src_x + (g->src_y + frame * g->offset_y) / max_height * g->width;
882 *y = (g->src_y + frame * g->offset_y) % max_height;
884 else /* frames are ordered diagonally */
886 *x = g->src_x + frame * g->offset_x;
887 *y = g->src_y + frame * g->offset_y;
891 void DrawGraphic(int x, int y, int graphic, int frame)
894 if (!IN_SCR_FIELD(x, y))
896 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
897 printf("DrawGraphic(): This should never happen!\n");
902 DrawGraphicExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic, frame);
906 void DrawGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
912 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
913 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
916 void DrawGraphicThruMask(int x, int y, int graphic, int frame)
919 if (!IN_SCR_FIELD(x, y))
921 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
922 printf("DrawGraphicThruMask(): This should never happen!\n");
927 DrawGraphicThruMaskExt(drawto_field, FX + x * TILEX, FY + y *TILEY, graphic,
932 void DrawGraphicThruMaskExt(DrawBuffer *d, int dest_x, int dest_y, int graphic,
940 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
941 drawing_gc = src_bitmap->stored_clip_gc;
943 GC drawing_gc = src_bitmap->stored_clip_gc;
944 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
945 int src_x = graphic_info[graphic].src_x;
946 int src_y = graphic_info[graphic].src_y;
947 int offset_x = graphic_info[graphic].offset_x;
948 int offset_y = graphic_info[graphic].offset_y;
950 src_x += frame * offset_x;
951 src_y += frame * offset_y;
955 SetClipOrigin(src_bitmap, drawing_gc, dest_x - src_x, dest_y - src_y);
956 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX, TILEY, dest_x, dest_y);
959 void DrawMiniGraphic(int x, int y, int graphic)
961 DrawMiniGraphicExt(drawto, SX + x * MINI_TILEX,SY + y * MINI_TILEY, graphic);
962 MarkTileDirty(x / 2, y / 2);
965 void getMiniGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
967 struct GraphicInfo *g = &graphic_info[graphic];
969 int mini_starty = g->bitmap->height * 2 / 3;
972 *x = mini_startx + g->src_x / 2;
973 *y = mini_starty + g->src_y / 2;
976 void DrawMiniGraphicExt(DrawBuffer *d, int x, int y, int graphic)
981 getMiniGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
982 BlitBitmap(src_bitmap, d, src_x, src_y, MINI_TILEX, MINI_TILEY, x, y);
985 void DrawGraphicShifted(int x, int y, int dx, int dy, int graphic, int frame,
986 int cut_mode, int mask_mode)
991 int width = TILEX, height = TILEY;
997 DrawGraphic(x, y, graphic, frame);
1001 if (dx || dy) /* shifted graphic */
1003 if (x < BX1) /* object enters playfield from the left */
1010 else if (x > BX2) /* object enters playfield from the right */
1016 else if (x==BX1 && dx < 0) /* object leaves playfield to the left */
1022 else if (x==BX2 && dx > 0) /* object leaves playfield to the right */
1024 else if (dx) /* general horizontal movement */
1025 MarkTileDirty(x + SIGN(dx), y);
1027 if (y < BY1) /* object enters playfield from the top */
1029 if (cut_mode==CUT_BELOW) /* object completely above top border */
1037 else if (y > BY2) /* object enters playfield from the bottom */
1043 else if (y==BY1 && dy < 0) /* object leaves playfield to the top */
1049 else if (dy > 0 && cut_mode == CUT_ABOVE)
1051 if (y == BY2) /* object completely above bottom border */
1057 MarkTileDirty(x, y + 1);
1058 } /* object leaves playfield to the bottom */
1059 else if (dy > 0 && (y == BY2 || cut_mode == CUT_BELOW))
1061 else if (dy) /* general vertical movement */
1062 MarkTileDirty(x, y + SIGN(dy));
1066 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1068 src_bitmap = graphic_info[graphic].bitmap;
1069 src_x = graphic_info[graphic].src_x;
1070 src_y = graphic_info[graphic].src_y;
1071 offset_x = graphic_info[graphic].offset_x;
1072 offset_y = graphic_info[graphic].offset_y;
1074 src_x += frame * offset_x;
1075 src_y += frame * offset_y;
1078 drawing_gc = src_bitmap->stored_clip_gc;
1083 dest_x = FX + x * TILEX + dx;
1084 dest_y = FY + y * TILEY + dy;
1087 if (!IN_SCR_FIELD(x,y))
1089 printf("DrawGraphicShifted(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
1090 printf("DrawGraphicShifted(): This should never happen!\n");
1095 if (mask_mode == USE_MASKING)
1097 SetClipOrigin(src_bitmap, drawing_gc, dest_x - src_x, dest_y - src_y);
1098 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1102 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1105 MarkTileDirty(x, y);
1108 void DrawGraphicShiftedThruMask(int x, int y, int dx, int dy, int graphic,
1109 int frame, int cut_mode)
1111 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, USE_MASKING);
1114 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
1115 int cut_mode, int mask_mode)
1117 int lx = LEVELX(x), ly = LEVELY(y);
1121 if (IN_LEV_FIELD(lx, ly))
1123 SetRandomAnimationValue(lx, ly);
1125 graphic = el_act_dir2img(element, GfxAction[lx][ly], GfxDir[lx][ly]);
1126 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1128 else /* border element */
1130 graphic = el2img(element);
1131 frame = getGraphicAnimationFrame(graphic, -1);
1134 if (element == EL_EXPANDABLE_WALL)
1136 boolean left_stopped = FALSE, right_stopped = FALSE;
1138 if (!IN_LEV_FIELD(lx - 1, ly) || IS_WALL(Feld[lx - 1][ly]))
1139 left_stopped = TRUE;
1140 if (!IN_LEV_FIELD(lx + 1, ly) || IS_WALL(Feld[lx + 1][ly]))
1141 right_stopped = TRUE;
1143 if (left_stopped && right_stopped)
1145 else if (left_stopped)
1147 graphic = IMG_EXPANDABLE_WALL_GROWING_RIGHT;
1148 frame = graphic_info[graphic].anim_frames - 1;
1150 else if (right_stopped)
1152 graphic = IMG_EXPANDABLE_WALL_GROWING_LEFT;
1153 frame = graphic_info[graphic].anim_frames - 1;
1158 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, mask_mode);
1159 else if (mask_mode == USE_MASKING)
1160 DrawGraphicThruMask(x, y, graphic, frame);
1162 DrawGraphic(x, y, graphic, frame);
1165 void DrawLevelElementExt(int x, int y, int dx, int dy, int element,
1166 int cut_mode, int mask_mode)
1168 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1169 DrawScreenElementExt(SCREENX(x), SCREENY(y), dx, dy, element,
1170 cut_mode, mask_mode);
1173 void DrawScreenElementShifted(int x, int y, int dx, int dy, int element,
1176 DrawScreenElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1179 void DrawLevelElementShifted(int x, int y, int dx, int dy, int element,
1182 DrawLevelElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1185 void DrawLevelElementThruMask(int x, int y, int element)
1187 DrawLevelElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1190 void DrawLevelFieldThruMask(int x, int y)
1192 DrawLevelElementExt(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
1195 #define TILE_GFX_ELEMENT(x, y) \
1196 (GfxElement[x][y] != EL_UNDEFINED && Feld[x][y] != EL_EXPLOSION ? \
1197 GfxElement[x][y] : Feld[x][y])
1199 static void DrawLevelFieldCrumbledSandExt(int x, int y, int graphic, int frame)
1203 int sx = SCREENX(x), sy = SCREENY(y);
1205 int width, height, cx, cy, i;
1207 int crumbled_border_size = graphic_info[graphic].border_size;
1209 int snip = TILEX / 8; /* number of border pixels from "crumbled graphic" */
1211 static int xy[4][2] =
1220 if (x == 0 && y == 7)
1221 printf("::: %d, %d [%d]\n", GfxElement[x][y], Feld[x][y],
1222 crumbled_border_size);
1225 if (!IN_LEV_FIELD(x, y))
1228 element = TILE_GFX_ELEMENT(x, y);
1230 /* crumble field itself */
1231 if (GFX_CRUMBLED(element) && !IS_MOVING(x, y))
1233 if (!IN_SCR_FIELD(sx, sy))
1236 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1238 for (i = 0; i < 4; i++)
1240 int xx = x + xy[i][0];
1241 int yy = y + xy[i][1];
1244 element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1247 element = (IN_LEV_FIELD(xx, yy) ? Feld[xx][yy] : BorderElement);
1250 /* check if neighbour field is of same type */
1251 if (GFX_CRUMBLED(element) && !IS_MOVING(xx, yy))
1255 if (Feld[x][y] == EL_CUSTOM_START + 123)
1256 printf("::: crumble [%d] THE CHAOS ENGINE (%d, %d): %d, %d\n",
1257 i, Feld[x][y], element,
1258 GFX_CRUMBLED(element), IS_MOVING(x, y));
1261 if (i == 1 || i == 2)
1263 width = crumbled_border_size;
1265 cx = (i == 2 ? TILEX - crumbled_border_size : 0);
1271 height = crumbled_border_size;
1273 cy = (i == 3 ? TILEY - crumbled_border_size : 0);
1276 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1277 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
1280 MarkTileDirty(sx, sy);
1282 else /* crumble neighbour fields */
1285 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1288 for (i = 0; i < 4; i++)
1290 int xx = x + xy[i][0];
1291 int yy = y + xy[i][1];
1292 int sxx = sx + xy[i][0];
1293 int syy = sy + xy[i][1];
1296 if (!IN_LEV_FIELD(xx, yy) ||
1297 !IN_SCR_FIELD(sxx, syy) ||
1301 element = TILE_GFX_ELEMENT(xx, yy);
1303 if (!GFX_CRUMBLED(element))
1306 if (!IN_LEV_FIELD(xx, yy) ||
1307 !IN_SCR_FIELD(sxx, syy) ||
1308 !GFX_CRUMBLED(Feld[xx][yy]) ||
1314 graphic = el_act2crm(Feld[xx][yy], ACTION_DEFAULT);
1315 crumbled_border_size = graphic_info[graphic].border_size;
1317 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1320 if (i == 1 || i == 2)
1322 width = crumbled_border_size;
1324 cx = (i == 1 ? TILEX - crumbled_border_size : 0);
1330 height = crumbled_border_size;
1332 cy = (i == 0 ? TILEY - crumbled_border_size : 0);
1335 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1336 width, height, FX + sxx * TILEX + cx, FY + syy * TILEY + cy);
1338 MarkTileDirty(sxx, syy);
1343 void DrawLevelFieldCrumbledSand(int x, int y)
1348 if (!IN_LEV_FIELD(x, y))
1351 graphic = el_act2crm(Feld[x][y], ACTION_DEFAULT);
1353 DrawLevelFieldCrumbledSandExt(x, y, graphic, 0);
1355 DrawLevelFieldCrumbledSandExt(x, y, IMG_SAND_CRUMBLED, 0);
1359 void DrawLevelFieldCrumbledSandDigging(int x, int y, int direction,
1363 int graphic1 = el_act_dir2img(GfxElement[x][y], ACTION_DIGGING, direction);
1364 int graphic2 = el_act_dir2crm(GfxElement[x][y], ACTION_DIGGING, direction);
1366 int graphic1 = el_act_dir2img(EL_SAND, ACTION_DIGGING, direction);
1367 int graphic2 = el_act_dir2img(EL_SAND_CRUMBLED, ACTION_DIGGING, direction);
1369 int frame1 = getGraphicAnimationFrame(graphic1, step_frame);
1370 int frame2 = getGraphicAnimationFrame(graphic2, step_frame);
1371 int sx = SCREENX(x), sy = SCREENY(y);
1373 DrawGraphic(sx, sy, graphic1, frame1);
1374 DrawLevelFieldCrumbledSandExt(x, y, graphic2, frame2);
1377 void DrawLevelFieldCrumbledSandNeighbours(int x, int y)
1379 int sx = SCREENX(x), sy = SCREENY(y);
1380 static int xy[4][2] =
1389 for (i = 0; i < 4; i++)
1391 int xx = x + xy[i][0];
1392 int yy = y + xy[i][1];
1393 int sxx = sx + xy[i][0];
1394 int syy = sy + xy[i][1];
1396 if (!IN_LEV_FIELD(xx, yy) ||
1397 !IN_SCR_FIELD(sxx, syy) ||
1398 !GFX_CRUMBLED(Feld[xx][yy]) ||
1402 DrawLevelField(xx, yy);
1406 static int getBorderElement(int x, int y)
1410 { EL_STEELWALL_TOPLEFT, EL_INVISIBLE_STEELWALL_TOPLEFT },
1411 { EL_STEELWALL_TOPRIGHT, EL_INVISIBLE_STEELWALL_TOPRIGHT },
1412 { EL_STEELWALL_BOTTOMLEFT, EL_INVISIBLE_STEELWALL_BOTTOMLEFT },
1413 { EL_STEELWALL_BOTTOMRIGHT, EL_INVISIBLE_STEELWALL_BOTTOMRIGHT },
1414 { EL_STEELWALL_VERTICAL, EL_INVISIBLE_STEELWALL_VERTICAL },
1415 { EL_STEELWALL_HORIZONTAL, EL_INVISIBLE_STEELWALL_HORIZONTAL },
1416 { EL_STEELWALL, EL_INVISIBLE_STEELWALL }
1418 int steel_type = (BorderElement == EL_STEELWALL ? 0 : 1);
1419 int steel_position = (x == -1 && y == -1 ? 0 :
1420 x == lev_fieldx && y == -1 ? 1 :
1421 x == -1 && y == lev_fieldy ? 2 :
1422 x == lev_fieldx && y == lev_fieldy ? 3 :
1423 x == -1 || x == lev_fieldx ? 4 :
1424 y == -1 || y == lev_fieldy ? 5 : 6);
1426 return border[steel_position][steel_type];
1429 void DrawScreenElement(int x, int y, int element)
1431 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
1432 DrawLevelFieldCrumbledSand(LEVELX(x), LEVELY(y));
1435 void DrawLevelElement(int x, int y, int element)
1437 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1438 DrawScreenElement(SCREENX(x), SCREENY(y), element);
1441 void DrawScreenField(int x, int y)
1443 int lx = LEVELX(x), ly = LEVELY(y);
1444 int element, content;
1446 if (!IN_LEV_FIELD(lx, ly))
1448 if (lx < -1 || lx > lev_fieldx || ly < -1 || ly > lev_fieldy)
1451 element = getBorderElement(lx, ly);
1453 DrawScreenElement(x, y, element);
1457 element = Feld[lx][ly];
1458 content = Store[lx][ly];
1460 if (IS_MOVING(lx, ly))
1462 int horiz_move = (MovDir[lx][ly] == MV_LEFT || MovDir[lx][ly] == MV_RIGHT);
1463 boolean cut_mode = NO_CUTTING;
1465 if (element == EL_QUICKSAND_EMPTYING ||
1466 element == EL_MAGIC_WALL_EMPTYING ||
1467 element == EL_BD_MAGIC_WALL_EMPTYING ||
1468 element == EL_AMOEBA_DROPPING)
1469 cut_mode = CUT_ABOVE;
1470 else if (element == EL_QUICKSAND_FILLING ||
1471 element == EL_MAGIC_WALL_FILLING ||
1472 element == EL_BD_MAGIC_WALL_FILLING)
1473 cut_mode = CUT_BELOW;
1475 if (cut_mode == CUT_ABOVE)
1476 DrawScreenElementShifted(x, y, 0, 0, element, NO_CUTTING);
1478 DrawScreenElement(x, y, EL_EMPTY);
1481 DrawScreenElementShifted(x, y, MovPos[lx][ly], 0, element, NO_CUTTING);
1482 else if (cut_mode == NO_CUTTING)
1483 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], element, cut_mode);
1485 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], content, cut_mode);
1487 if (content == EL_ACID)
1488 DrawLevelElementThruMask(lx, ly + 1, EL_ACID);
1490 else if (IS_BLOCKED(lx, ly))
1495 boolean cut_mode = NO_CUTTING;
1496 int element_old, content_old;
1498 Blocked2Moving(lx, ly, &oldx, &oldy);
1501 horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
1502 MovDir[oldx][oldy] == MV_RIGHT);
1504 element_old = Feld[oldx][oldy];
1505 content_old = Store[oldx][oldy];
1507 if (element_old == EL_QUICKSAND_EMPTYING ||
1508 element_old == EL_MAGIC_WALL_EMPTYING ||
1509 element_old == EL_BD_MAGIC_WALL_EMPTYING ||
1510 element_old == EL_AMOEBA_DROPPING)
1511 cut_mode = CUT_ABOVE;
1513 DrawScreenElement(x, y, EL_EMPTY);
1516 DrawScreenElementShifted(sx, sy, MovPos[oldx][oldy], 0, element_old,
1518 else if (cut_mode == NO_CUTTING)
1519 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], element_old,
1522 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], content_old,
1525 else if (IS_DRAWABLE(element))
1526 DrawScreenElement(x, y, element);
1528 DrawScreenElement(x, y, EL_EMPTY);
1531 void DrawLevelField(int x, int y)
1533 if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1534 DrawScreenField(SCREENX(x), SCREENY(y));
1535 else if (IS_MOVING(x, y))
1539 Moving2Blocked(x, y, &newx, &newy);
1540 if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
1541 DrawScreenField(SCREENX(newx), SCREENY(newy));
1543 else if (IS_BLOCKED(x, y))
1547 Blocked2Moving(x, y, &oldx, &oldy);
1548 if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
1549 DrawScreenField(SCREENX(oldx), SCREENY(oldy));
1553 void DrawMiniElement(int x, int y, int element)
1557 graphic = el2edimg(element);
1558 DrawMiniGraphic(x, y, graphic);
1561 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
1563 int x = sx + scroll_x, y = sy + scroll_y;
1565 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
1566 DrawMiniElement(sx, sy, EL_EMPTY);
1567 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
1568 DrawMiniElement(sx, sy, Feld[x][y]);
1570 DrawMiniGraphic(sx, sy, el2edimg(getBorderElement(x, y)));
1573 void DrawEnvelopeBackground(int envelope_nr, int startx, int starty,
1574 int x, int y, int xsize, int ysize, int font_nr)
1576 int font_width = getFontWidth(font_nr);
1577 int font_height = getFontHeight(font_nr);
1578 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1581 int dst_x = SX + startx + x * font_width;
1582 int dst_y = SY + starty + y * font_height;
1583 int width = graphic_info[graphic].width;
1584 int height = graphic_info[graphic].height;
1585 int inner_width = MAX(width - 2 * font_width, font_width);
1586 int inner_height = MAX(height - 2 * font_height, font_height);
1587 int inner_sx = (width >= 3 * font_width ? font_width : 0);
1588 int inner_sy = (height >= 3 * font_height ? font_height : 0);
1589 boolean draw_masked = graphic_info[graphic].draw_masked;
1591 getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
1593 if (src_bitmap == NULL || width < font_width || height < font_height)
1595 ClearRectangle(drawto, dst_x, dst_y, font_width, font_height);
1599 src_x += (x == 0 ? 0 : x == xsize - 1 ? width - font_width :
1600 inner_sx + (x - 1) * font_width % inner_width);
1601 src_y += (y == 0 ? 0 : y == ysize - 1 ? height - font_height :
1602 inner_sy + (y - 1) * font_height % inner_height);
1606 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1607 dst_x - src_x, dst_y - src_y);
1608 BlitBitmapMasked(src_bitmap, drawto, src_x, src_y, font_width, font_height,
1612 BlitBitmap(src_bitmap, drawto, src_x, src_y, font_width, font_height,
1616 void AnimateEnvelope(int envelope_nr, int anim_mode, int action)
1618 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1619 boolean draw_masked = graphic_info[graphic].draw_masked;
1620 int mask_mode = (draw_masked ? BLIT_MASKED : BLIT_ON_BACKGROUND);
1621 boolean ffwd_delay = (tape.playing && tape.fast_forward);
1622 unsigned long anim_delay = 0;
1623 int anim_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
1624 int font_nr = FONT_ENVELOPE_1 + envelope_nr;
1625 int font_width = getFontWidth(font_nr);
1626 int font_height = getFontHeight(font_nr);
1627 int max_xsize = level.envelope_xsize[envelope_nr];
1628 int max_ysize = level.envelope_ysize[envelope_nr];
1629 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize : 0);
1630 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize : 0);
1631 int xend = max_xsize;
1632 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize : 0);
1633 int xstep = (xstart < xend ? 1 : 0);
1634 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
1637 for (x = xstart, y = ystart; x <= xend && y <= yend; x += xstep, y += ystep)
1639 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
1640 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
1641 int sx = (SXSIZE - xsize * font_width) / 2;
1642 int sy = (SYSIZE - ysize * font_height) / 2;
1645 SetDrawtoField(DRAW_BUFFERED);
1647 BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
1649 SetDrawtoField(DRAW_BACKBUFFER);
1651 for (yy = 0; yy < ysize; yy++) for (xx = 0; xx < xsize; xx++)
1652 DrawEnvelopeBackground(envelope_nr, sx,sy, xx,yy, xsize, ysize, font_nr);
1654 DrawTextToTextArea(SX + sx + font_width, SY + sy + font_height,
1655 level.envelope_text[envelope_nr], font_nr, max_xsize,
1656 xsize - 2, ysize - 2, mask_mode);
1658 redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
1661 WaitUntilDelayReached(&anim_delay, anim_delay_value / 2);
1665 void ShowEnvelope(int envelope_nr)
1667 int element = EL_ENVELOPE_1 + envelope_nr;
1668 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1669 int sound_opening = element_info[element].sound[ACTION_OPENING];
1670 int sound_closing = element_info[element].sound[ACTION_CLOSING];
1671 boolean ffwd_delay = (tape.playing && tape.fast_forward);
1672 int wait_delay_value = (ffwd_delay ? 500 : 1000);
1673 int anim_mode = graphic_info[graphic].anim_mode;
1674 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
1675 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
1677 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
1679 PlaySoundStereo(sound_opening, SOUND_MIDDLE);
1681 if (anim_mode == ANIM_DEFAULT)
1682 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_OPENING);
1684 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_OPENING);
1687 Delay(wait_delay_value);
1689 WaitForEventToContinue();
1691 PlaySoundStereo(sound_closing, SOUND_MIDDLE);
1693 if (anim_mode != ANIM_NONE)
1694 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_CLOSING);
1696 if (anim_mode == ANIM_DEFAULT)
1697 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_CLOSING);
1699 game.envelope_active = FALSE;
1701 SetDrawtoField(DRAW_BUFFERED);
1703 redraw_mask |= REDRAW_FIELD;
1707 void getMicroGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
1709 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
1710 int mini_startx = src_bitmap->width * 3 / 4;
1711 int mini_starty = src_bitmap->height * 2 / 3;
1712 int src_x = mini_startx + graphic_info[graphic].src_x / 8;
1713 int src_y = mini_starty + graphic_info[graphic].src_y / 8;
1715 *bitmap = src_bitmap;
1720 void DrawMicroElement(int xpos, int ypos, int element)
1724 int graphic = el2preimg(element);
1726 getMicroGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
1727 BlitBitmap(src_bitmap, drawto, src_x, src_y, MICRO_TILEX, MICRO_TILEY,
1735 SetDrawBackgroundMask(REDRAW_NONE);
1738 for (x = BX1; x <= BX2; x++)
1739 for (y = BY1; y <= BY2; y++)
1740 DrawScreenField(x, y);
1742 redraw_mask |= REDRAW_FIELD;
1745 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
1749 for (x = 0; x < size_x; x++)
1750 for (y = 0; y < size_y; y++)
1751 DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
1753 redraw_mask |= REDRAW_FIELD;
1756 static void DrawMicroLevelExt(int xpos, int ypos, int from_x, int from_y)
1760 DrawBackground(xpos, ypos, MICROLEV_XSIZE, MICROLEV_YSIZE);
1762 if (lev_fieldx < STD_LEV_FIELDX)
1763 xpos += (STD_LEV_FIELDX - lev_fieldx) / 2 * MICRO_TILEX;
1764 if (lev_fieldy < STD_LEV_FIELDY)
1765 ypos += (STD_LEV_FIELDY - lev_fieldy) / 2 * MICRO_TILEY;
1767 xpos += MICRO_TILEX;
1768 ypos += MICRO_TILEY;
1770 for (x = -1; x <= STD_LEV_FIELDX; x++)
1772 for (y = -1; y <= STD_LEV_FIELDY; y++)
1774 int lx = from_x + x, ly = from_y + y;
1776 if (lx >= 0 && lx < lev_fieldx && ly >= 0 && ly < lev_fieldy)
1777 DrawMicroElement(xpos + x * MICRO_TILEX, ypos + y * MICRO_TILEY,
1778 level.field[lx][ly]);
1779 else if (lx >= -1 && lx < lev_fieldx+1 && ly >= -1 && ly < lev_fieldy+1
1780 && BorderElement != EL_EMPTY)
1781 DrawMicroElement(xpos + x * MICRO_TILEX, ypos + y * MICRO_TILEY,
1782 getBorderElement(lx, ly));
1786 redraw_mask |= REDRAW_MICROLEVEL;
1789 #define MICROLABEL_EMPTY 0
1790 #define MICROLABEL_LEVEL_NAME 1
1791 #define MICROLABEL_CREATED_BY 2
1792 #define MICROLABEL_LEVEL_AUTHOR 3
1793 #define MICROLABEL_IMPORTED_FROM 4
1794 #define MICROLABEL_LEVEL_IMPORT_INFO 5
1796 static void DrawMicroLevelLabelExt(int mode)
1798 char label_text[MAX_OUTPUT_LINESIZE + 1];
1799 int max_len_label_text;
1800 int font_nr = FONT_TEXT_2;
1802 if (mode == MICROLABEL_CREATED_BY || mode == MICROLABEL_IMPORTED_FROM)
1803 font_nr = FONT_TEXT_3;
1805 max_len_label_text = SXSIZE / getFontWidth(font_nr);
1807 DrawBackground(SX, MICROLABEL_YPOS, SXSIZE, getFontHeight(font_nr));
1809 strncpy(label_text, (mode == MICROLABEL_LEVEL_NAME ? level.name :
1810 mode == MICROLABEL_CREATED_BY ? "created by" :
1811 mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
1812 mode == MICROLABEL_IMPORTED_FROM ? "imported from" :
1813 mode == MICROLABEL_LEVEL_IMPORT_INFO ?
1814 leveldir_current->imported_from : ""),
1815 max_len_label_text);
1816 label_text[max_len_label_text] = '\0';
1818 if (strlen(label_text) > 0)
1820 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
1821 int lypos = MICROLABEL_YPOS;
1823 DrawText(lxpos, lypos, label_text, font_nr);
1826 redraw_mask |= REDRAW_MICROLEVEL;
1829 void DrawMicroLevel(int xpos, int ypos, boolean restart)
1831 static unsigned long scroll_delay = 0;
1832 static unsigned long label_delay = 0;
1833 static int from_x, from_y, scroll_direction;
1834 static int label_state, label_counter;
1835 int last_game_status = game_status; /* save current game status */
1837 /* force PREVIEW font on preview level */
1838 game_status = GAME_MODE_PSEUDO_PREVIEW;
1842 from_x = from_y = 0;
1843 scroll_direction = MV_RIGHT;
1847 DrawMicroLevelExt(xpos, ypos, from_x, from_y);
1848 DrawMicroLevelLabelExt(label_state);
1850 /* initialize delay counters */
1851 DelayReached(&scroll_delay, 0);
1852 DelayReached(&label_delay, 0);
1854 if (leveldir_current->name)
1856 int text_width = getTextWidth(leveldir_current->name, FONT_TEXT_1);
1857 int lxpos = SX + (SXSIZE - text_width) / 2;
1858 int lypos = SY + 352;
1860 DrawText(lxpos, lypos, leveldir_current->name, FONT_TEXT_1);
1863 game_status = last_game_status; /* restore current game status */
1868 /* scroll micro level, if needed */
1869 if ((lev_fieldx > STD_LEV_FIELDX || lev_fieldy > STD_LEV_FIELDY) &&
1870 DelayReached(&scroll_delay, MICROLEVEL_SCROLL_DELAY))
1872 switch (scroll_direction)
1878 scroll_direction = MV_UP;
1882 if (from_x < lev_fieldx - STD_LEV_FIELDX)
1885 scroll_direction = MV_DOWN;
1892 scroll_direction = MV_RIGHT;
1896 if (from_y < lev_fieldy - STD_LEV_FIELDY)
1899 scroll_direction = MV_LEFT;
1906 DrawMicroLevelExt(xpos, ypos, from_x, from_y);
1909 /* redraw micro level label, if needed */
1910 if (strcmp(level.name, NAMELESS_LEVEL_NAME) != 0 &&
1911 strcmp(level.author, ANONYMOUS_NAME) != 0 &&
1912 strcmp(level.author, leveldir_current->name) != 0 &&
1913 DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
1915 int max_label_counter = 23;
1917 if (leveldir_current->imported_from != NULL)
1918 max_label_counter += 14;
1920 label_counter = (label_counter + 1) % max_label_counter;
1921 label_state = (label_counter >= 0 && label_counter <= 7 ?
1922 MICROLABEL_LEVEL_NAME :
1923 label_counter >= 9 && label_counter <= 12 ?
1924 MICROLABEL_CREATED_BY :
1925 label_counter >= 14 && label_counter <= 21 ?
1926 MICROLABEL_LEVEL_AUTHOR :
1927 label_counter >= 23 && label_counter <= 26 ?
1928 MICROLABEL_IMPORTED_FROM :
1929 label_counter >= 28 && label_counter <= 35 ?
1930 MICROLABEL_LEVEL_IMPORT_INFO : MICROLABEL_EMPTY);
1931 DrawMicroLevelLabelExt(label_state);
1934 game_status = last_game_status; /* restore current game status */
1937 void WaitForEventToContinue()
1939 boolean still_wait = TRUE;
1941 /* simulate releasing mouse button over last gadget, if still pressed */
1943 HandleGadgets(-1, -1, 0);
1945 button_status = MB_RELEASED;
1957 case EVENT_BUTTONPRESS:
1958 case EVENT_KEYPRESS:
1962 case EVENT_KEYRELEASE:
1963 ClearPlayerAction();
1967 HandleOtherEvents(&event);
1971 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
1978 /* don't eat all CPU time */
1983 #define MAX_REQUEST_LINES 13
1984 #define MAX_REQUEST_LINE_FONT1_LEN 7
1985 #define MAX_REQUEST_LINE_FONT2_LEN 10
1987 boolean Request(char *text, unsigned int req_state)
1989 int mx, my, ty, result = -1;
1990 unsigned int old_door_state;
1991 int last_game_status = game_status; /* save current game status */
1992 int max_request_line_len = MAX_REQUEST_LINE_FONT1_LEN;
1993 int font_nr = FONT_TEXT_2;
1994 int max_word_len = 0;
1997 for (text_ptr = text; *text_ptr; text_ptr++)
1999 max_word_len = (*text_ptr != ' ' ? max_word_len + 1 : 0);
2001 if (max_word_len > MAX_REQUEST_LINE_FONT1_LEN)
2003 max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
2004 font_nr = FONT_LEVEL_NUMBER;
2011 SetMouseCursor(CURSOR_DEFAULT);
2014 #if defined(PLATFORM_UNIX)
2015 /* pause network game while waiting for request to answer */
2016 if (options.network &&
2017 game_status == GAME_MODE_PLAYING &&
2018 req_state & REQUEST_WAIT_FOR)
2019 SendToServer_PausePlaying();
2022 old_door_state = GetDoorState();
2024 /* simulate releasing mouse button over last gadget, if still pressed */
2026 HandleGadgets(-1, -1, 0);
2030 CloseDoor(DOOR_CLOSE_1);
2032 /* save old door content */
2033 BlitBitmap(bitmap_db_door, bitmap_db_door,
2034 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
2035 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
2037 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
2039 /* clear door drawing field */
2040 DrawBackground(DX, DY, DXSIZE, DYSIZE);
2042 /* force DOOR font on preview level */
2043 game_status = GAME_MODE_PSEUDO_DOOR;
2045 /* write text for request */
2046 for (ty = 0; ty < MAX_REQUEST_LINES; ty++)
2048 char text_line[max_request_line_len + 1];
2054 for (tl = 0, tx = 0; tx < max_request_line_len; tl++, tx++)
2057 if (!tc || tc == ' ')
2068 strncpy(text_line, text, tl);
2071 DrawText(DX + (DXSIZE - tl * getFontWidth(font_nr)) / 2,
2072 DY + 8 + ty * (getFontHeight(font_nr) + 2),
2073 text_line, font_nr);
2075 text += tl + (tc == ' ' ? 1 : 0);
2078 game_status = last_game_status; /* restore current game status */
2080 if (req_state & REQ_ASK)
2082 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
2083 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
2085 else if (req_state & REQ_CONFIRM)
2087 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
2089 else if (req_state & REQ_PLAYER)
2091 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
2092 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
2093 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
2094 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
2097 /* copy request gadgets to door backbuffer */
2098 BlitBitmap(drawto, bitmap_db_door,
2099 DX, DY, DXSIZE, DYSIZE,
2100 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2102 OpenDoor(DOOR_OPEN_1);
2108 if (!(req_state & REQUEST_WAIT_FOR))
2110 SetDrawBackgroundMask(REDRAW_FIELD);
2115 if (game_status != GAME_MODE_MAIN)
2118 button_status = MB_RELEASED;
2120 request_gadget_id = -1;
2122 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
2125 SetMouseCursor(CURSOR_DEFAULT);
2138 case EVENT_BUTTONPRESS:
2139 case EVENT_BUTTONRELEASE:
2140 case EVENT_MOTIONNOTIFY:
2142 if (event.type == EVENT_MOTIONNOTIFY)
2144 if (!PointerInWindow(window))
2145 continue; /* window and pointer are on different screens */
2150 motion_status = TRUE;
2151 mx = ((MotionEvent *) &event)->x;
2152 my = ((MotionEvent *) &event)->y;
2156 motion_status = FALSE;
2157 mx = ((ButtonEvent *) &event)->x;
2158 my = ((ButtonEvent *) &event)->y;
2159 if (event.type == EVENT_BUTTONPRESS)
2160 button_status = ((ButtonEvent *) &event)->button;
2162 button_status = MB_RELEASED;
2165 /* this sets 'request_gadget_id' */
2166 HandleGadgets(mx, my, button_status);
2168 switch(request_gadget_id)
2170 case TOOL_CTRL_ID_YES:
2173 case TOOL_CTRL_ID_NO:
2176 case TOOL_CTRL_ID_CONFIRM:
2177 result = TRUE | FALSE;
2180 case TOOL_CTRL_ID_PLAYER_1:
2183 case TOOL_CTRL_ID_PLAYER_2:
2186 case TOOL_CTRL_ID_PLAYER_3:
2189 case TOOL_CTRL_ID_PLAYER_4:
2200 case EVENT_KEYPRESS:
2201 switch(GetEventKey((KeyEvent *)&event, TRUE))
2214 if (req_state & REQ_PLAYER)
2218 case EVENT_KEYRELEASE:
2219 ClearPlayerAction();
2223 HandleOtherEvents(&event);
2227 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
2229 int joy = AnyJoystick();
2231 if (joy & JOY_BUTTON_1)
2233 else if (joy & JOY_BUTTON_2)
2239 /* don't eat all CPU time */
2243 if (game_status != GAME_MODE_MAIN)
2248 if (!(req_state & REQ_STAY_OPEN))
2250 CloseDoor(DOOR_CLOSE_1);
2252 if (!(req_state & REQ_STAY_CLOSED) && (old_door_state & DOOR_OPEN_1))
2254 BlitBitmap(bitmap_db_door, bitmap_db_door,
2255 DOOR_GFX_PAGEX2,DOOR_GFX_PAGEY1, DXSIZE,DYSIZE,
2256 DOOR_GFX_PAGEX1,DOOR_GFX_PAGEY1);
2257 OpenDoor(DOOR_OPEN_1);
2263 SetDrawBackgroundMask(REDRAW_FIELD);
2265 #if defined(PLATFORM_UNIX)
2266 /* continue network game after request */
2267 if (options.network &&
2268 game_status == GAME_MODE_PLAYING &&
2269 req_state & REQUEST_WAIT_FOR)
2270 SendToServer_ContinuePlaying();
2276 unsigned int OpenDoor(unsigned int door_state)
2278 unsigned int new_door_state;
2280 if (door_state & DOOR_COPY_BACK)
2282 BlitBitmap(bitmap_db_door, bitmap_db_door,
2283 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE + VYSIZE,
2284 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2285 door_state &= ~DOOR_COPY_BACK;
2288 new_door_state = MoveDoor(door_state);
2290 return(new_door_state);
2293 unsigned int CloseDoor(unsigned int door_state)
2295 unsigned int new_door_state;
2297 BlitBitmap(backbuffer, bitmap_db_door,
2298 DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2299 BlitBitmap(backbuffer, bitmap_db_door,
2300 VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
2302 new_door_state = MoveDoor(door_state);
2304 return(new_door_state);
2307 unsigned int GetDoorState()
2309 return MoveDoor(DOOR_GET_STATE);
2312 unsigned int SetDoorState(unsigned int door_state)
2314 return MoveDoor(door_state | DOOR_SET_STATE);
2317 unsigned int MoveDoor(unsigned int door_state)
2319 static int door1 = DOOR_OPEN_1;
2320 static int door2 = DOOR_CLOSE_2;
2321 unsigned long door_delay = 0;
2322 unsigned long door_delay_value;
2325 if (door_state == DOOR_GET_STATE)
2326 return(door1 | door2);
2328 if (door_state & DOOR_SET_STATE)
2330 if (door_state & DOOR_ACTION_1)
2331 door1 = door_state & DOOR_ACTION_1;
2332 if (door_state & DOOR_ACTION_2)
2333 door2 = door_state & DOOR_ACTION_2;
2335 return(door1 | door2);
2338 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
2339 door_state &= ~DOOR_OPEN_1;
2340 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
2341 door_state &= ~DOOR_CLOSE_1;
2342 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
2343 door_state &= ~DOOR_OPEN_2;
2344 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
2345 door_state &= ~DOOR_CLOSE_2;
2347 door_delay_value = (door_state & DOOR_ACTION_1 ? door_1.step_delay :
2350 if (setup.quick_doors)
2352 stepsize = 20; /* must be choosen to always draw last frame */
2353 door_delay_value = 0;
2355 StopSound(SND_DOOR_OPENING);
2356 StopSound(SND_DOOR_CLOSING);
2359 if (global.autoplay_leveldir)
2361 door_state |= DOOR_NO_DELAY;
2362 door_state &= ~DOOR_CLOSE_ALL;
2365 if (door_state & DOOR_ACTION)
2367 boolean door_1_done = !(door_state & DOOR_ACTION_1);
2368 boolean door_2_done = !(door_state & DOOR_ACTION_2);
2369 int start = ((door_state & DOOR_NO_DELAY) ? DXSIZE : 0);
2370 int end = (door_state & DOOR_ACTION_1 &&
2371 door_1.anim_mode == ANIM_VERTICAL ? DYSIZE : DXSIZE);
2374 if (!(door_state & DOOR_NO_DELAY))
2376 /* opening door sound has priority over simultaneously closing door */
2377 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
2378 PlaySoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
2379 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
2380 PlaySoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
2383 for (x = start; x <= end && !(door_1_done && door_2_done); x += stepsize)
2385 Bitmap *bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
2386 GC gc = bitmap->stored_clip_gc;
2388 if (door_state & DOOR_ACTION_1)
2390 int a = MIN(x * door_1.step_offset, end);
2391 int i = (door_state & DOOR_OPEN_1 ? end - a : a);
2395 BlitBitmap(bitmap_db_door, drawto,
2396 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + i / 2,
2397 DXSIZE,DYSIZE - i / 2, DX, DY);
2399 ClearRectangle(drawto, DX, DY + DYSIZE - i / 2, DXSIZE, i / 2);
2402 if (door_1.anim_mode == ANIM_HORIZONTAL && x <= DXSIZE)
2404 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
2405 int dst1_x = DX + DXSIZE - i, dst1_y = DY;
2406 int src2_x = DXSIZE - i, src2_y = DOOR_GFX_PAGEY1;
2407 int dst2_x = DX, dst2_y = DY;
2408 int width = i, height = DYSIZE;
2410 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2411 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2414 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2415 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2418 else if (door_1.anim_mode == ANIM_VERTICAL && x <= DYSIZE)
2420 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
2421 int dst1_x = DX, dst1_y = DY + DYSIZE - i;
2422 int src2_x = 0, src2_y = DOOR_GFX_PAGEY1 + DYSIZE - i;
2423 int dst2_x = DX, dst2_y = DY;
2424 int width = DXSIZE, height = i;
2426 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2427 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2430 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2431 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2434 else if (x <= DXSIZE) /* ANIM_DEFAULT */
2436 int j = (door_1.anim_mode == ANIM_DEFAULT ? (DXSIZE - i) / 3 : 0);
2438 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2439 BlitBitmapMasked(bitmap, drawto,
2440 DXSIZE, DOOR_GFX_PAGEY1, i, 77,
2441 DX + DXSIZE - i, DY + j);
2442 BlitBitmapMasked(bitmap, drawto,
2443 DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63,
2444 DX + DXSIZE - i, DY + 140 + j);
2445 SetClipOrigin(bitmap, gc, DX - DXSIZE + i,
2446 DY - (DOOR_GFX_PAGEY1 + j));
2447 BlitBitmapMasked(bitmap, drawto,
2448 DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j,
2450 BlitBitmapMasked(bitmap, drawto,
2451 DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63,
2454 BlitBitmapMasked(bitmap, drawto,
2455 DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
2457 BlitBitmapMasked(bitmap, drawto,
2458 DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
2460 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2461 BlitBitmapMasked(bitmap, drawto,
2462 DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
2463 DX + DXSIZE - i, DY + 77 + j);
2464 BlitBitmapMasked(bitmap, drawto,
2465 DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
2466 DX + DXSIZE - i, DY + 203 + j);
2469 redraw_mask |= REDRAW_DOOR_1;
2470 door_1_done = (a == end);
2473 if (door_state & DOOR_ACTION_2)
2475 int a = MIN(x * door_2.step_offset, VXSIZE);
2476 int i = (door_state & DOOR_OPEN_2 ? VXSIZE - a : a);
2480 BlitBitmap(bitmap_db_door, drawto,
2481 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + i / 2,
2482 VXSIZE, VYSIZE - i / 2, VX, VY);
2484 ClearRectangle(drawto, VX, VY + VYSIZE - i / 2, VXSIZE, i / 2);
2487 if (door_2.anim_mode == ANIM_HORIZONTAL && x <= VXSIZE)
2489 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
2490 int dst1_x = VX + VXSIZE - i, dst1_y = VY;
2491 int src2_x = VXSIZE - i, src2_y = DOOR_GFX_PAGEY2;
2492 int dst2_x = VX, dst2_y = VY;
2493 int width = i, height = VYSIZE;
2495 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2496 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2499 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2500 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2503 else if (door_2.anim_mode == ANIM_VERTICAL && x <= VYSIZE)
2505 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
2506 int dst1_x = VX, dst1_y = VY + VYSIZE - i;
2507 int src2_x = 0, src2_y = DOOR_GFX_PAGEY2 + VYSIZE - i;
2508 int dst2_x = VX, dst2_y = VY;
2509 int width = VXSIZE, height = i;
2511 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2512 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2515 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2516 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2519 else if (x <= VXSIZE) /* ANIM_DEFAULT */
2521 int j = (door_2.anim_mode == ANIM_DEFAULT ? (VXSIZE - i) / 3 : 0);
2523 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2524 BlitBitmapMasked(bitmap, drawto,
2525 VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2,
2526 VX + VXSIZE - i, VY + j);
2527 SetClipOrigin(bitmap, gc,
2528 VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
2529 BlitBitmapMasked(bitmap, drawto,
2530 VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j,
2533 BlitBitmapMasked(bitmap, drawto,
2534 VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2,
2535 i, VYSIZE / 2, VX, VY + VYSIZE / 2 - j);
2536 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2537 BlitBitmapMasked(bitmap, drawto,
2538 VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2,
2540 VX + VXSIZE - i, VY + VYSIZE / 2 + j);
2543 redraw_mask |= REDRAW_DOOR_2;
2544 door_2_done = (a == VXSIZE);
2549 if (game_status == GAME_MODE_MAIN)
2552 if (!(door_state & DOOR_NO_DELAY))
2553 WaitUntilDelayReached(&door_delay, door_delay_value);
2557 if (setup.quick_doors)
2559 StopSound(SND_DOOR_OPENING);
2560 StopSound(SND_DOOR_CLOSING);
2563 if (door_state & DOOR_ACTION_1)
2564 door1 = door_state & DOOR_ACTION_1;
2565 if (door_state & DOOR_ACTION_2)
2566 door2 = door_state & DOOR_ACTION_2;
2568 return (door1 | door2);
2571 void DrawSpecialEditorDoor()
2573 /* draw bigger toolbox window */
2574 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
2575 DOOR_GFX_PAGEX7, 0, EXSIZE + 8, 8,
2577 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
2578 EX - 4, VY - 4, EXSIZE + 8, EYSIZE - VYSIZE + 4,
2581 redraw_mask |= REDRAW_ALL;
2584 void UndrawSpecialEditorDoor()
2586 /* draw normal tape recorder window */
2587 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
2588 EX - 4, EY - 12, EXSIZE + 8, EYSIZE - VYSIZE + 12,
2591 redraw_mask |= REDRAW_ALL;
2595 /* ---------- new tool button stuff ---------------------------------------- */
2597 /* graphic position values for tool buttons */
2598 #define TOOL_BUTTON_YES_XPOS 2
2599 #define TOOL_BUTTON_YES_YPOS 250
2600 #define TOOL_BUTTON_YES_GFX_YPOS 0
2601 #define TOOL_BUTTON_YES_XSIZE 46
2602 #define TOOL_BUTTON_YES_YSIZE 28
2603 #define TOOL_BUTTON_NO_XPOS 52
2604 #define TOOL_BUTTON_NO_YPOS TOOL_BUTTON_YES_YPOS
2605 #define TOOL_BUTTON_NO_GFX_YPOS TOOL_BUTTON_YES_GFX_YPOS
2606 #define TOOL_BUTTON_NO_XSIZE TOOL_BUTTON_YES_XSIZE
2607 #define TOOL_BUTTON_NO_YSIZE TOOL_BUTTON_YES_YSIZE
2608 #define TOOL_BUTTON_CONFIRM_XPOS TOOL_BUTTON_YES_XPOS
2609 #define TOOL_BUTTON_CONFIRM_YPOS TOOL_BUTTON_YES_YPOS
2610 #define TOOL_BUTTON_CONFIRM_GFX_YPOS 30
2611 #define TOOL_BUTTON_CONFIRM_XSIZE 96
2612 #define TOOL_BUTTON_CONFIRM_YSIZE TOOL_BUTTON_YES_YSIZE
2613 #define TOOL_BUTTON_PLAYER_XSIZE 30
2614 #define TOOL_BUTTON_PLAYER_YSIZE 30
2615 #define TOOL_BUTTON_PLAYER_GFX_XPOS 5
2616 #define TOOL_BUTTON_PLAYER_GFX_YPOS 185
2617 #define TOOL_BUTTON_PLAYER_XPOS (5 + TOOL_BUTTON_PLAYER_XSIZE / 2)
2618 #define TOOL_BUTTON_PLAYER_YPOS (215 - TOOL_BUTTON_PLAYER_YSIZE / 2)
2619 #define TOOL_BUTTON_PLAYER1_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2620 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2621 #define TOOL_BUTTON_PLAYER2_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2622 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2623 #define TOOL_BUTTON_PLAYER3_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2624 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2625 #define TOOL_BUTTON_PLAYER4_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2626 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2627 #define TOOL_BUTTON_PLAYER1_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2628 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2629 #define TOOL_BUTTON_PLAYER2_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2630 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2631 #define TOOL_BUTTON_PLAYER3_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2632 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2633 #define TOOL_BUTTON_PLAYER4_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2634 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2643 } toolbutton_info[NUM_TOOL_BUTTONS] =
2646 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_GFX_YPOS,
2647 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_YPOS,
2648 TOOL_BUTTON_YES_XSIZE, TOOL_BUTTON_YES_YSIZE,
2653 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_GFX_YPOS,
2654 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_YPOS,
2655 TOOL_BUTTON_NO_XSIZE, TOOL_BUTTON_NO_YSIZE,
2660 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_GFX_YPOS,
2661 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_YPOS,
2662 TOOL_BUTTON_CONFIRM_XSIZE, TOOL_BUTTON_CONFIRM_YSIZE,
2663 TOOL_CTRL_ID_CONFIRM,
2667 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2668 TOOL_BUTTON_PLAYER1_XPOS, TOOL_BUTTON_PLAYER1_YPOS,
2669 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2670 TOOL_CTRL_ID_PLAYER_1,
2674 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2675 TOOL_BUTTON_PLAYER2_XPOS, TOOL_BUTTON_PLAYER2_YPOS,
2676 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2677 TOOL_CTRL_ID_PLAYER_2,
2681 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2682 TOOL_BUTTON_PLAYER3_XPOS, TOOL_BUTTON_PLAYER3_YPOS,
2683 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2684 TOOL_CTRL_ID_PLAYER_3,
2688 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2689 TOOL_BUTTON_PLAYER4_XPOS, TOOL_BUTTON_PLAYER4_YPOS,
2690 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2691 TOOL_CTRL_ID_PLAYER_4,
2696 void CreateToolButtons()
2700 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
2702 Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
2703 Bitmap *deco_bitmap = None;
2704 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
2705 struct GadgetInfo *gi;
2706 unsigned long event_mask;
2707 int gd_xoffset, gd_yoffset;
2708 int gd_x1, gd_x2, gd_y;
2711 event_mask = GD_EVENT_RELEASED;
2713 gd_xoffset = toolbutton_info[i].xpos;
2714 gd_yoffset = toolbutton_info[i].ypos;
2715 gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
2716 gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
2717 gd_y = DOOR_GFX_PAGEY1 + gd_yoffset;
2719 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
2721 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
2723 getMiniGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr),
2724 &deco_bitmap, &deco_x, &deco_y);
2725 deco_xpos = (toolbutton_info[i].width - MINI_TILEX) / 2;
2726 deco_ypos = (toolbutton_info[i].height - MINI_TILEY) / 2;
2729 gi = CreateGadget(GDI_CUSTOM_ID, id,
2730 GDI_INFO_TEXT, toolbutton_info[i].infotext,
2731 GDI_X, DX + toolbutton_info[i].x,
2732 GDI_Y, DY + toolbutton_info[i].y,
2733 GDI_WIDTH, toolbutton_info[i].width,
2734 GDI_HEIGHT, toolbutton_info[i].height,
2735 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
2736 GDI_STATE, GD_BUTTON_UNPRESSED,
2737 GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
2738 GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
2739 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
2740 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
2741 GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
2742 GDI_DECORATION_SHIFTING, 1, 1,
2743 GDI_EVENT_MASK, event_mask,
2744 GDI_CALLBACK_ACTION, HandleToolButtons,
2748 Error(ERR_EXIT, "cannot create gadget");
2750 tool_gadget[id] = gi;
2754 void FreeToolButtons()
2758 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
2759 FreeGadget(tool_gadget[i]);
2762 static void UnmapToolButtons()
2766 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
2767 UnmapGadget(tool_gadget[i]);
2770 static void HandleToolButtons(struct GadgetInfo *gi)
2772 request_gadget_id = gi->custom_id;
2775 int get_next_element(int element)
2779 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
2780 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
2781 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
2782 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
2783 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
2784 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
2785 case EL_AMOEBA_DROPPING: return EL_AMOEBA_WET;
2787 default: return element;
2791 int el_act_dir2img(int element, int action, int direction)
2793 element = GFX_ELEMENT(element);
2794 direction = MV_DIR_BIT(direction);
2796 return element_info[element].direction_graphic[action][direction];
2799 static int el_act_dir2crm(int element, int action, int direction)
2801 element = GFX_ELEMENT(element);
2802 direction = MV_DIR_BIT(direction);
2804 return element_info[element].direction_crumbled[action][direction];
2807 int el_act2img(int element, int action)
2809 element = GFX_ELEMENT(element);
2811 return element_info[element].graphic[action];
2814 int el_act2crm(int element, int action)
2816 element = GFX_ELEMENT(element);
2818 return element_info[element].crumbled[action];
2821 int el_dir2img(int element, int direction)
2823 element = GFX_ELEMENT(element);
2825 return el_act_dir2img(element, ACTION_DEFAULT, direction);
2828 int el2img(int element)
2830 element = GFX_ELEMENT(element);
2832 return element_info[element].graphic[ACTION_DEFAULT];
2835 int el2edimg(int element)
2837 element = GFX_ELEMENT(element);
2839 return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
2842 int el2preimg(int element)
2844 element = GFX_ELEMENT(element);
2846 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];