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 boolean no_delay = (tape.index_search);
1623 unsigned long anim_delay = 0;
1624 int frame_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
1625 int anim_delay_value = (no_delay ? 0 : frame_delay_value);
1626 int font_nr = FONT_ENVELOPE_1 + envelope_nr;
1627 int font_width = getFontWidth(font_nr);
1628 int font_height = getFontHeight(font_nr);
1629 int max_xsize = level.envelope_xsize[envelope_nr];
1630 int max_ysize = level.envelope_ysize[envelope_nr];
1631 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize : 0);
1632 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize : 0);
1633 int xend = max_xsize;
1634 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize : 0);
1635 int xstep = (xstart < xend ? 1 : 0);
1636 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
1639 for (x = xstart, y = ystart; x <= xend && y <= yend; x += xstep, y += ystep)
1641 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
1642 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
1643 int sx = (SXSIZE - xsize * font_width) / 2;
1644 int sy = (SYSIZE - ysize * font_height) / 2;
1647 SetDrawtoField(DRAW_BUFFERED);
1649 BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
1651 SetDrawtoField(DRAW_BACKBUFFER);
1653 for (yy = 0; yy < ysize; yy++) for (xx = 0; xx < xsize; xx++)
1654 DrawEnvelopeBackground(envelope_nr, sx,sy, xx,yy, xsize, ysize, font_nr);
1656 DrawTextToTextArea(SX + sx + font_width, SY + sy + font_height,
1657 level.envelope_text[envelope_nr], font_nr, max_xsize,
1658 xsize - 2, ysize - 2, mask_mode);
1660 redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
1663 WaitUntilDelayReached(&anim_delay, anim_delay_value / 2);
1667 void ShowEnvelope(int envelope_nr)
1669 int element = EL_ENVELOPE_1 + envelope_nr;
1670 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1671 int sound_opening = element_info[element].sound[ACTION_OPENING];
1672 int sound_closing = element_info[element].sound[ACTION_CLOSING];
1673 boolean ffwd_delay = (tape.playing && tape.fast_forward);
1674 boolean no_delay = (tape.index_search);
1675 int normal_delay_value = ONE_SECOND_DELAY / (ffwd_delay ? 2 : 1);
1676 int wait_delay_value = (no_delay ? 0 : normal_delay_value);
1677 int anim_mode = graphic_info[graphic].anim_mode;
1678 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
1679 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
1681 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
1683 PlaySoundStereo(sound_opening, SOUND_MIDDLE);
1685 if (anim_mode == ANIM_DEFAULT)
1686 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_OPENING);
1688 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_OPENING);
1691 Delay(wait_delay_value);
1693 WaitForEventToContinue();
1695 PlaySoundStereo(sound_closing, SOUND_MIDDLE);
1697 if (anim_mode != ANIM_NONE)
1698 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_CLOSING);
1700 if (anim_mode == ANIM_DEFAULT)
1701 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_CLOSING);
1703 game.envelope_active = FALSE;
1705 SetDrawtoField(DRAW_BUFFERED);
1707 redraw_mask |= REDRAW_FIELD;
1711 void getMicroGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
1713 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
1714 int mini_startx = src_bitmap->width * 3 / 4;
1715 int mini_starty = src_bitmap->height * 2 / 3;
1716 int src_x = mini_startx + graphic_info[graphic].src_x / 8;
1717 int src_y = mini_starty + graphic_info[graphic].src_y / 8;
1719 *bitmap = src_bitmap;
1724 void DrawMicroElement(int xpos, int ypos, int element)
1728 int graphic = el2preimg(element);
1730 getMicroGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
1731 BlitBitmap(src_bitmap, drawto, src_x, src_y, MICRO_TILEX, MICRO_TILEY,
1739 SetDrawBackgroundMask(REDRAW_NONE);
1742 for (x = BX1; x <= BX2; x++)
1743 for (y = BY1; y <= BY2; y++)
1744 DrawScreenField(x, y);
1746 redraw_mask |= REDRAW_FIELD;
1749 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
1753 for (x = 0; x < size_x; x++)
1754 for (y = 0; y < size_y; y++)
1755 DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
1757 redraw_mask |= REDRAW_FIELD;
1760 static void DrawMicroLevelExt(int xpos, int ypos, int from_x, int from_y)
1764 DrawBackground(xpos, ypos, MICROLEV_XSIZE, MICROLEV_YSIZE);
1766 if (lev_fieldx < STD_LEV_FIELDX)
1767 xpos += (STD_LEV_FIELDX - lev_fieldx) / 2 * MICRO_TILEX;
1768 if (lev_fieldy < STD_LEV_FIELDY)
1769 ypos += (STD_LEV_FIELDY - lev_fieldy) / 2 * MICRO_TILEY;
1771 xpos += MICRO_TILEX;
1772 ypos += MICRO_TILEY;
1774 for (x = -1; x <= STD_LEV_FIELDX; x++)
1776 for (y = -1; y <= STD_LEV_FIELDY; y++)
1778 int lx = from_x + x, ly = from_y + y;
1780 if (lx >= 0 && lx < lev_fieldx && ly >= 0 && ly < lev_fieldy)
1781 DrawMicroElement(xpos + x * MICRO_TILEX, ypos + y * MICRO_TILEY,
1782 level.field[lx][ly]);
1783 else if (lx >= -1 && lx < lev_fieldx+1 && ly >= -1 && ly < lev_fieldy+1
1784 && BorderElement != EL_EMPTY)
1785 DrawMicroElement(xpos + x * MICRO_TILEX, ypos + y * MICRO_TILEY,
1786 getBorderElement(lx, ly));
1790 redraw_mask |= REDRAW_MICROLEVEL;
1793 #define MICROLABEL_EMPTY 0
1794 #define MICROLABEL_LEVEL_NAME 1
1795 #define MICROLABEL_CREATED_BY 2
1796 #define MICROLABEL_LEVEL_AUTHOR 3
1797 #define MICROLABEL_IMPORTED_FROM 4
1798 #define MICROLABEL_LEVEL_IMPORT_INFO 5
1800 static void DrawMicroLevelLabelExt(int mode)
1802 char label_text[MAX_OUTPUT_LINESIZE + 1];
1803 int max_len_label_text;
1804 int font_nr = FONT_TEXT_2;
1806 if (mode == MICROLABEL_CREATED_BY || mode == MICROLABEL_IMPORTED_FROM)
1807 font_nr = FONT_TEXT_3;
1809 max_len_label_text = SXSIZE / getFontWidth(font_nr);
1811 DrawBackground(SX, MICROLABEL_YPOS, SXSIZE, getFontHeight(font_nr));
1813 strncpy(label_text, (mode == MICROLABEL_LEVEL_NAME ? level.name :
1814 mode == MICROLABEL_CREATED_BY ? "created by" :
1815 mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
1816 mode == MICROLABEL_IMPORTED_FROM ? "imported from" :
1817 mode == MICROLABEL_LEVEL_IMPORT_INFO ?
1818 leveldir_current->imported_from : ""),
1819 max_len_label_text);
1820 label_text[max_len_label_text] = '\0';
1822 if (strlen(label_text) > 0)
1824 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
1825 int lypos = MICROLABEL_YPOS;
1827 DrawText(lxpos, lypos, label_text, font_nr);
1830 redraw_mask |= REDRAW_MICROLEVEL;
1833 void DrawMicroLevel(int xpos, int ypos, boolean restart)
1835 static unsigned long scroll_delay = 0;
1836 static unsigned long label_delay = 0;
1837 static int from_x, from_y, scroll_direction;
1838 static int label_state, label_counter;
1839 int last_game_status = game_status; /* save current game status */
1841 /* force PREVIEW font on preview level */
1842 game_status = GAME_MODE_PSEUDO_PREVIEW;
1846 from_x = from_y = 0;
1847 scroll_direction = MV_RIGHT;
1851 DrawMicroLevelExt(xpos, ypos, from_x, from_y);
1852 DrawMicroLevelLabelExt(label_state);
1854 /* initialize delay counters */
1855 DelayReached(&scroll_delay, 0);
1856 DelayReached(&label_delay, 0);
1858 if (leveldir_current->name)
1860 int text_width = getTextWidth(leveldir_current->name, FONT_TEXT_1);
1861 int lxpos = SX + (SXSIZE - text_width) / 2;
1862 int lypos = SY + 352;
1864 DrawText(lxpos, lypos, leveldir_current->name, FONT_TEXT_1);
1867 game_status = last_game_status; /* restore current game status */
1872 /* scroll micro level, if needed */
1873 if ((lev_fieldx > STD_LEV_FIELDX || lev_fieldy > STD_LEV_FIELDY) &&
1874 DelayReached(&scroll_delay, MICROLEVEL_SCROLL_DELAY))
1876 switch (scroll_direction)
1882 scroll_direction = MV_UP;
1886 if (from_x < lev_fieldx - STD_LEV_FIELDX)
1889 scroll_direction = MV_DOWN;
1896 scroll_direction = MV_RIGHT;
1900 if (from_y < lev_fieldy - STD_LEV_FIELDY)
1903 scroll_direction = MV_LEFT;
1910 DrawMicroLevelExt(xpos, ypos, from_x, from_y);
1913 /* redraw micro level label, if needed */
1914 if (strcmp(level.name, NAMELESS_LEVEL_NAME) != 0 &&
1915 strcmp(level.author, ANONYMOUS_NAME) != 0 &&
1916 strcmp(level.author, leveldir_current->name) != 0 &&
1917 DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
1919 int max_label_counter = 23;
1921 if (leveldir_current->imported_from != NULL)
1922 max_label_counter += 14;
1924 label_counter = (label_counter + 1) % max_label_counter;
1925 label_state = (label_counter >= 0 && label_counter <= 7 ?
1926 MICROLABEL_LEVEL_NAME :
1927 label_counter >= 9 && label_counter <= 12 ?
1928 MICROLABEL_CREATED_BY :
1929 label_counter >= 14 && label_counter <= 21 ?
1930 MICROLABEL_LEVEL_AUTHOR :
1931 label_counter >= 23 && label_counter <= 26 ?
1932 MICROLABEL_IMPORTED_FROM :
1933 label_counter >= 28 && label_counter <= 35 ?
1934 MICROLABEL_LEVEL_IMPORT_INFO : MICROLABEL_EMPTY);
1935 DrawMicroLevelLabelExt(label_state);
1938 game_status = last_game_status; /* restore current game status */
1941 void WaitForEventToContinue()
1943 boolean still_wait = TRUE;
1945 /* simulate releasing mouse button over last gadget, if still pressed */
1947 HandleGadgets(-1, -1, 0);
1949 button_status = MB_RELEASED;
1961 case EVENT_BUTTONPRESS:
1962 case EVENT_KEYPRESS:
1966 case EVENT_KEYRELEASE:
1967 ClearPlayerAction();
1971 HandleOtherEvents(&event);
1975 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
1982 /* don't eat all CPU time */
1987 #define MAX_REQUEST_LINES 13
1988 #define MAX_REQUEST_LINE_FONT1_LEN 7
1989 #define MAX_REQUEST_LINE_FONT2_LEN 10
1991 boolean Request(char *text, unsigned int req_state)
1993 int mx, my, ty, result = -1;
1994 unsigned int old_door_state;
1995 int last_game_status = game_status; /* save current game status */
1996 int max_request_line_len = MAX_REQUEST_LINE_FONT1_LEN;
1997 int font_nr = FONT_TEXT_2;
1998 int max_word_len = 0;
2001 for (text_ptr = text; *text_ptr; text_ptr++)
2003 max_word_len = (*text_ptr != ' ' ? max_word_len + 1 : 0);
2005 if (max_word_len > MAX_REQUEST_LINE_FONT1_LEN)
2007 max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
2008 font_nr = FONT_LEVEL_NUMBER;
2015 SetMouseCursor(CURSOR_DEFAULT);
2018 #if defined(PLATFORM_UNIX)
2019 /* pause network game while waiting for request to answer */
2020 if (options.network &&
2021 game_status == GAME_MODE_PLAYING &&
2022 req_state & REQUEST_WAIT_FOR)
2023 SendToServer_PausePlaying();
2026 old_door_state = GetDoorState();
2028 /* simulate releasing mouse button over last gadget, if still pressed */
2030 HandleGadgets(-1, -1, 0);
2034 CloseDoor(DOOR_CLOSE_1);
2036 /* save old door content */
2037 BlitBitmap(bitmap_db_door, bitmap_db_door,
2038 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
2039 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
2041 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
2043 /* clear door drawing field */
2044 DrawBackground(DX, DY, DXSIZE, DYSIZE);
2046 /* force DOOR font on preview level */
2047 game_status = GAME_MODE_PSEUDO_DOOR;
2049 /* write text for request */
2050 for (ty = 0; ty < MAX_REQUEST_LINES; ty++)
2052 char text_line[max_request_line_len + 1];
2058 for (tl = 0, tx = 0; tx < max_request_line_len; tl++, tx++)
2061 if (!tc || tc == ' ')
2072 strncpy(text_line, text, tl);
2075 DrawText(DX + (DXSIZE - tl * getFontWidth(font_nr)) / 2,
2076 DY + 8 + ty * (getFontHeight(font_nr) + 2),
2077 text_line, font_nr);
2079 text += tl + (tc == ' ' ? 1 : 0);
2082 game_status = last_game_status; /* restore current game status */
2084 if (req_state & REQ_ASK)
2086 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
2087 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
2089 else if (req_state & REQ_CONFIRM)
2091 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
2093 else if (req_state & REQ_PLAYER)
2095 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
2096 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
2097 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
2098 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
2101 /* copy request gadgets to door backbuffer */
2102 BlitBitmap(drawto, bitmap_db_door,
2103 DX, DY, DXSIZE, DYSIZE,
2104 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2106 OpenDoor(DOOR_OPEN_1);
2112 if (!(req_state & REQUEST_WAIT_FOR))
2114 SetDrawBackgroundMask(REDRAW_FIELD);
2119 if (game_status != GAME_MODE_MAIN)
2122 button_status = MB_RELEASED;
2124 request_gadget_id = -1;
2126 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
2129 SetMouseCursor(CURSOR_DEFAULT);
2142 case EVENT_BUTTONPRESS:
2143 case EVENT_BUTTONRELEASE:
2144 case EVENT_MOTIONNOTIFY:
2146 if (event.type == EVENT_MOTIONNOTIFY)
2148 if (!PointerInWindow(window))
2149 continue; /* window and pointer are on different screens */
2154 motion_status = TRUE;
2155 mx = ((MotionEvent *) &event)->x;
2156 my = ((MotionEvent *) &event)->y;
2160 motion_status = FALSE;
2161 mx = ((ButtonEvent *) &event)->x;
2162 my = ((ButtonEvent *) &event)->y;
2163 if (event.type == EVENT_BUTTONPRESS)
2164 button_status = ((ButtonEvent *) &event)->button;
2166 button_status = MB_RELEASED;
2169 /* this sets 'request_gadget_id' */
2170 HandleGadgets(mx, my, button_status);
2172 switch(request_gadget_id)
2174 case TOOL_CTRL_ID_YES:
2177 case TOOL_CTRL_ID_NO:
2180 case TOOL_CTRL_ID_CONFIRM:
2181 result = TRUE | FALSE;
2184 case TOOL_CTRL_ID_PLAYER_1:
2187 case TOOL_CTRL_ID_PLAYER_2:
2190 case TOOL_CTRL_ID_PLAYER_3:
2193 case TOOL_CTRL_ID_PLAYER_4:
2204 case EVENT_KEYPRESS:
2205 switch(GetEventKey((KeyEvent *)&event, TRUE))
2218 if (req_state & REQ_PLAYER)
2222 case EVENT_KEYRELEASE:
2223 ClearPlayerAction();
2227 HandleOtherEvents(&event);
2231 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
2233 int joy = AnyJoystick();
2235 if (joy & JOY_BUTTON_1)
2237 else if (joy & JOY_BUTTON_2)
2243 /* don't eat all CPU time */
2247 if (game_status != GAME_MODE_MAIN)
2252 if (!(req_state & REQ_STAY_OPEN))
2254 CloseDoor(DOOR_CLOSE_1);
2256 if (!(req_state & REQ_STAY_CLOSED) && (old_door_state & DOOR_OPEN_1))
2258 BlitBitmap(bitmap_db_door, bitmap_db_door,
2259 DOOR_GFX_PAGEX2,DOOR_GFX_PAGEY1, DXSIZE,DYSIZE,
2260 DOOR_GFX_PAGEX1,DOOR_GFX_PAGEY1);
2261 OpenDoor(DOOR_OPEN_1);
2267 SetDrawBackgroundMask(REDRAW_FIELD);
2269 #if defined(PLATFORM_UNIX)
2270 /* continue network game after request */
2271 if (options.network &&
2272 game_status == GAME_MODE_PLAYING &&
2273 req_state & REQUEST_WAIT_FOR)
2274 SendToServer_ContinuePlaying();
2280 unsigned int OpenDoor(unsigned int door_state)
2282 unsigned int new_door_state;
2284 if (door_state & DOOR_COPY_BACK)
2286 BlitBitmap(bitmap_db_door, bitmap_db_door,
2287 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE + VYSIZE,
2288 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2289 door_state &= ~DOOR_COPY_BACK;
2292 new_door_state = MoveDoor(door_state);
2294 return(new_door_state);
2297 unsigned int CloseDoor(unsigned int door_state)
2299 unsigned int new_door_state;
2301 BlitBitmap(backbuffer, bitmap_db_door,
2302 DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2303 BlitBitmap(backbuffer, bitmap_db_door,
2304 VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
2306 new_door_state = MoveDoor(door_state);
2308 return(new_door_state);
2311 unsigned int GetDoorState()
2313 return MoveDoor(DOOR_GET_STATE);
2316 unsigned int SetDoorState(unsigned int door_state)
2318 return MoveDoor(door_state | DOOR_SET_STATE);
2321 unsigned int MoveDoor(unsigned int door_state)
2323 static int door1 = DOOR_OPEN_1;
2324 static int door2 = DOOR_CLOSE_2;
2325 unsigned long door_delay = 0;
2326 unsigned long door_delay_value;
2329 if (door_state == DOOR_GET_STATE)
2330 return(door1 | door2);
2332 if (door_state & DOOR_SET_STATE)
2334 if (door_state & DOOR_ACTION_1)
2335 door1 = door_state & DOOR_ACTION_1;
2336 if (door_state & DOOR_ACTION_2)
2337 door2 = door_state & DOOR_ACTION_2;
2339 return(door1 | door2);
2342 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
2343 door_state &= ~DOOR_OPEN_1;
2344 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
2345 door_state &= ~DOOR_CLOSE_1;
2346 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
2347 door_state &= ~DOOR_OPEN_2;
2348 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
2349 door_state &= ~DOOR_CLOSE_2;
2351 door_delay_value = (door_state & DOOR_ACTION_1 ? door_1.step_delay :
2354 if (setup.quick_doors)
2356 stepsize = 20; /* must be choosen to always draw last frame */
2357 door_delay_value = 0;
2360 StopSound(SND_DOOR_OPENING);
2361 StopSound(SND_DOOR_CLOSING);
2365 if (global.autoplay_leveldir)
2367 door_state |= DOOR_NO_DELAY;
2368 door_state &= ~DOOR_CLOSE_ALL;
2371 if (door_state & DOOR_ACTION)
2373 boolean door_1_done = !(door_state & DOOR_ACTION_1);
2374 boolean door_2_done = !(door_state & DOOR_ACTION_2);
2375 int start = ((door_state & DOOR_NO_DELAY) ? DXSIZE : 0);
2376 int end = (door_state & DOOR_ACTION_1 &&
2377 door_1.anim_mode == ANIM_VERTICAL ? DYSIZE : DXSIZE);
2380 if (!(door_state & DOOR_NO_DELAY) && !setup.quick_doors)
2382 /* opening door sound has priority over simultaneously closing door */
2383 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
2384 PlaySoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
2385 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
2386 PlaySoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
2389 for (x = start; x <= end && !(door_1_done && door_2_done); x += stepsize)
2391 Bitmap *bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
2392 GC gc = bitmap->stored_clip_gc;
2394 if (door_state & DOOR_ACTION_1)
2396 int a = MIN(x * door_1.step_offset, end);
2397 int i = (door_state & DOOR_OPEN_1 ? end - a : a);
2401 BlitBitmap(bitmap_db_door, drawto,
2402 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + i / 2,
2403 DXSIZE,DYSIZE - i / 2, DX, DY);
2405 ClearRectangle(drawto, DX, DY + DYSIZE - i / 2, DXSIZE, i / 2);
2408 if (door_1.anim_mode == ANIM_HORIZONTAL && x <= DXSIZE)
2410 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
2411 int dst1_x = DX + DXSIZE - i, dst1_y = DY;
2412 int src2_x = DXSIZE - i, src2_y = DOOR_GFX_PAGEY1;
2413 int dst2_x = DX, dst2_y = DY;
2414 int width = i, height = DYSIZE;
2416 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2417 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2420 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2421 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2424 else if (door_1.anim_mode == ANIM_VERTICAL && x <= DYSIZE)
2426 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
2427 int dst1_x = DX, dst1_y = DY + DYSIZE - i;
2428 int src2_x = 0, src2_y = DOOR_GFX_PAGEY1 + DYSIZE - i;
2429 int dst2_x = DX, dst2_y = DY;
2430 int width = DXSIZE, height = i;
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 (x <= DXSIZE) /* ANIM_DEFAULT */
2442 int j = (door_1.anim_mode == ANIM_DEFAULT ? (DXSIZE - i) / 3 : 0);
2444 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2445 BlitBitmapMasked(bitmap, drawto,
2446 DXSIZE, DOOR_GFX_PAGEY1, i, 77,
2447 DX + DXSIZE - i, DY + j);
2448 BlitBitmapMasked(bitmap, drawto,
2449 DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63,
2450 DX + DXSIZE - i, DY + 140 + j);
2451 SetClipOrigin(bitmap, gc, DX - DXSIZE + i,
2452 DY - (DOOR_GFX_PAGEY1 + j));
2453 BlitBitmapMasked(bitmap, drawto,
2454 DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j,
2456 BlitBitmapMasked(bitmap, drawto,
2457 DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63,
2460 BlitBitmapMasked(bitmap, drawto,
2461 DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
2463 BlitBitmapMasked(bitmap, drawto,
2464 DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
2466 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2467 BlitBitmapMasked(bitmap, drawto,
2468 DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
2469 DX + DXSIZE - i, DY + 77 + j);
2470 BlitBitmapMasked(bitmap, drawto,
2471 DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
2472 DX + DXSIZE - i, DY + 203 + j);
2475 redraw_mask |= REDRAW_DOOR_1;
2476 door_1_done = (a == end);
2479 if (door_state & DOOR_ACTION_2)
2481 int a = MIN(x * door_2.step_offset, VXSIZE);
2482 int i = (door_state & DOOR_OPEN_2 ? VXSIZE - a : a);
2486 BlitBitmap(bitmap_db_door, drawto,
2487 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + i / 2,
2488 VXSIZE, VYSIZE - i / 2, VX, VY);
2490 ClearRectangle(drawto, VX, VY + VYSIZE - i / 2, VXSIZE, i / 2);
2493 if (door_2.anim_mode == ANIM_HORIZONTAL && x <= VXSIZE)
2495 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
2496 int dst1_x = VX + VXSIZE - i, dst1_y = VY;
2497 int src2_x = VXSIZE - i, src2_y = DOOR_GFX_PAGEY2;
2498 int dst2_x = VX, dst2_y = VY;
2499 int width = i, height = VYSIZE;
2501 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2502 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2505 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2506 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2509 else if (door_2.anim_mode == ANIM_VERTICAL && x <= VYSIZE)
2511 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
2512 int dst1_x = VX, dst1_y = VY + VYSIZE - i;
2513 int src2_x = 0, src2_y = DOOR_GFX_PAGEY2 + VYSIZE - i;
2514 int dst2_x = VX, dst2_y = VY;
2515 int width = VXSIZE, height = i;
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 (x <= VXSIZE) /* ANIM_DEFAULT */
2527 int j = (door_2.anim_mode == ANIM_DEFAULT ? (VXSIZE - i) / 3 : 0);
2529 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2530 BlitBitmapMasked(bitmap, drawto,
2531 VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2,
2532 VX + VXSIZE - i, VY + j);
2533 SetClipOrigin(bitmap, gc,
2534 VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
2535 BlitBitmapMasked(bitmap, drawto,
2536 VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j,
2539 BlitBitmapMasked(bitmap, drawto,
2540 VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2,
2541 i, VYSIZE / 2, VX, VY + VYSIZE / 2 - j);
2542 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2543 BlitBitmapMasked(bitmap, drawto,
2544 VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2,
2546 VX + VXSIZE - i, VY + VYSIZE / 2 + j);
2549 redraw_mask |= REDRAW_DOOR_2;
2550 door_2_done = (a == VXSIZE);
2555 if (game_status == GAME_MODE_MAIN)
2558 if (!(door_state & DOOR_NO_DELAY))
2559 WaitUntilDelayReached(&door_delay, door_delay_value);
2564 if (setup.quick_doors)
2566 StopSound(SND_DOOR_OPENING);
2567 StopSound(SND_DOOR_CLOSING);
2571 if (door_state & DOOR_ACTION_1)
2572 door1 = door_state & DOOR_ACTION_1;
2573 if (door_state & DOOR_ACTION_2)
2574 door2 = door_state & DOOR_ACTION_2;
2576 return (door1 | door2);
2579 void DrawSpecialEditorDoor()
2581 /* draw bigger toolbox window */
2582 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
2583 DOOR_GFX_PAGEX7, 0, EXSIZE + 8, 8,
2585 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
2586 EX - 4, VY - 4, EXSIZE + 8, EYSIZE - VYSIZE + 4,
2589 redraw_mask |= REDRAW_ALL;
2592 void UndrawSpecialEditorDoor()
2594 /* draw normal tape recorder window */
2595 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
2596 EX - 4, EY - 12, EXSIZE + 8, EYSIZE - VYSIZE + 12,
2599 redraw_mask |= REDRAW_ALL;
2603 /* ---------- new tool button stuff ---------------------------------------- */
2605 /* graphic position values for tool buttons */
2606 #define TOOL_BUTTON_YES_XPOS 2
2607 #define TOOL_BUTTON_YES_YPOS 250
2608 #define TOOL_BUTTON_YES_GFX_YPOS 0
2609 #define TOOL_BUTTON_YES_XSIZE 46
2610 #define TOOL_BUTTON_YES_YSIZE 28
2611 #define TOOL_BUTTON_NO_XPOS 52
2612 #define TOOL_BUTTON_NO_YPOS TOOL_BUTTON_YES_YPOS
2613 #define TOOL_BUTTON_NO_GFX_YPOS TOOL_BUTTON_YES_GFX_YPOS
2614 #define TOOL_BUTTON_NO_XSIZE TOOL_BUTTON_YES_XSIZE
2615 #define TOOL_BUTTON_NO_YSIZE TOOL_BUTTON_YES_YSIZE
2616 #define TOOL_BUTTON_CONFIRM_XPOS TOOL_BUTTON_YES_XPOS
2617 #define TOOL_BUTTON_CONFIRM_YPOS TOOL_BUTTON_YES_YPOS
2618 #define TOOL_BUTTON_CONFIRM_GFX_YPOS 30
2619 #define TOOL_BUTTON_CONFIRM_XSIZE 96
2620 #define TOOL_BUTTON_CONFIRM_YSIZE TOOL_BUTTON_YES_YSIZE
2621 #define TOOL_BUTTON_PLAYER_XSIZE 30
2622 #define TOOL_BUTTON_PLAYER_YSIZE 30
2623 #define TOOL_BUTTON_PLAYER_GFX_XPOS 5
2624 #define TOOL_BUTTON_PLAYER_GFX_YPOS 185
2625 #define TOOL_BUTTON_PLAYER_XPOS (5 + TOOL_BUTTON_PLAYER_XSIZE / 2)
2626 #define TOOL_BUTTON_PLAYER_YPOS (215 - TOOL_BUTTON_PLAYER_YSIZE / 2)
2627 #define TOOL_BUTTON_PLAYER1_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2628 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2629 #define TOOL_BUTTON_PLAYER2_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2630 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2631 #define TOOL_BUTTON_PLAYER3_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2632 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2633 #define TOOL_BUTTON_PLAYER4_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2634 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2635 #define TOOL_BUTTON_PLAYER1_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2636 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2637 #define TOOL_BUTTON_PLAYER2_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2638 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2639 #define TOOL_BUTTON_PLAYER3_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2640 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2641 #define TOOL_BUTTON_PLAYER4_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2642 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2651 } toolbutton_info[NUM_TOOL_BUTTONS] =
2654 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_GFX_YPOS,
2655 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_YPOS,
2656 TOOL_BUTTON_YES_XSIZE, TOOL_BUTTON_YES_YSIZE,
2661 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_GFX_YPOS,
2662 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_YPOS,
2663 TOOL_BUTTON_NO_XSIZE, TOOL_BUTTON_NO_YSIZE,
2668 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_GFX_YPOS,
2669 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_YPOS,
2670 TOOL_BUTTON_CONFIRM_XSIZE, TOOL_BUTTON_CONFIRM_YSIZE,
2671 TOOL_CTRL_ID_CONFIRM,
2675 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2676 TOOL_BUTTON_PLAYER1_XPOS, TOOL_BUTTON_PLAYER1_YPOS,
2677 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2678 TOOL_CTRL_ID_PLAYER_1,
2682 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2683 TOOL_BUTTON_PLAYER2_XPOS, TOOL_BUTTON_PLAYER2_YPOS,
2684 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2685 TOOL_CTRL_ID_PLAYER_2,
2689 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2690 TOOL_BUTTON_PLAYER3_XPOS, TOOL_BUTTON_PLAYER3_YPOS,
2691 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2692 TOOL_CTRL_ID_PLAYER_3,
2696 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2697 TOOL_BUTTON_PLAYER4_XPOS, TOOL_BUTTON_PLAYER4_YPOS,
2698 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2699 TOOL_CTRL_ID_PLAYER_4,
2704 void CreateToolButtons()
2708 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
2710 Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
2711 Bitmap *deco_bitmap = None;
2712 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
2713 struct GadgetInfo *gi;
2714 unsigned long event_mask;
2715 int gd_xoffset, gd_yoffset;
2716 int gd_x1, gd_x2, gd_y;
2719 event_mask = GD_EVENT_RELEASED;
2721 gd_xoffset = toolbutton_info[i].xpos;
2722 gd_yoffset = toolbutton_info[i].ypos;
2723 gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
2724 gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
2725 gd_y = DOOR_GFX_PAGEY1 + gd_yoffset;
2727 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
2729 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
2731 getMiniGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr),
2732 &deco_bitmap, &deco_x, &deco_y);
2733 deco_xpos = (toolbutton_info[i].width - MINI_TILEX) / 2;
2734 deco_ypos = (toolbutton_info[i].height - MINI_TILEY) / 2;
2737 gi = CreateGadget(GDI_CUSTOM_ID, id,
2738 GDI_INFO_TEXT, toolbutton_info[i].infotext,
2739 GDI_X, DX + toolbutton_info[i].x,
2740 GDI_Y, DY + toolbutton_info[i].y,
2741 GDI_WIDTH, toolbutton_info[i].width,
2742 GDI_HEIGHT, toolbutton_info[i].height,
2743 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
2744 GDI_STATE, GD_BUTTON_UNPRESSED,
2745 GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
2746 GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
2747 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
2748 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
2749 GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
2750 GDI_DECORATION_SHIFTING, 1, 1,
2751 GDI_EVENT_MASK, event_mask,
2752 GDI_CALLBACK_ACTION, HandleToolButtons,
2756 Error(ERR_EXIT, "cannot create gadget");
2758 tool_gadget[id] = gi;
2762 void FreeToolButtons()
2766 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
2767 FreeGadget(tool_gadget[i]);
2770 static void UnmapToolButtons()
2774 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
2775 UnmapGadget(tool_gadget[i]);
2778 static void HandleToolButtons(struct GadgetInfo *gi)
2780 request_gadget_id = gi->custom_id;
2783 int get_next_element(int element)
2787 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
2788 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
2789 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
2790 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
2791 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
2792 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
2793 case EL_AMOEBA_DROPPING: return EL_AMOEBA_WET;
2795 default: return element;
2799 int el_act_dir2img(int element, int action, int direction)
2801 element = GFX_ELEMENT(element);
2802 direction = MV_DIR_BIT(direction);
2804 return element_info[element].direction_graphic[action][direction];
2807 static int el_act_dir2crm(int element, int action, int direction)
2809 element = GFX_ELEMENT(element);
2810 direction = MV_DIR_BIT(direction);
2812 return element_info[element].direction_crumbled[action][direction];
2815 int el_act2img(int element, int action)
2817 element = GFX_ELEMENT(element);
2819 return element_info[element].graphic[action];
2822 int el_act2crm(int element, int action)
2824 element = GFX_ELEMENT(element);
2826 return element_info[element].crumbled[action];
2829 int el_dir2img(int element, int direction)
2831 element = GFX_ELEMENT(element);
2833 return el_act_dir2img(element, ACTION_DEFAULT, direction);
2836 int el2img(int element)
2838 element = GFX_ELEMENT(element);
2840 return element_info[element].graphic[ACTION_DEFAULT];
2843 int el2edimg(int element)
2845 element = GFX_ELEMENT(element);
2847 return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
2850 int el2preimg(int element)
2852 element = GFX_ELEMENT(element);
2854 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];