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 static void DrawLevelFieldCrumbledSandExt(int x, int y, int graphic, int frame)
1199 int sx = SCREENX(x), sy = SCREENY(y);
1201 int width, height, cx, cy, i;
1203 int crumbled_border_size = graphic_info[graphic].border_size;
1205 int snip = TILEX / 8; /* number of border pixels from "crumbled graphic" */
1207 static int xy[4][2] =
1216 if (x == 0 && y == 7)
1217 printf("::: %d, %d [%d]\n", GfxElement[x][y], Feld[x][y],
1218 crumbled_border_size);
1221 if (!IN_LEV_FIELD(x, y))
1224 element = (GfxElement[x][y] != EL_UNDEFINED && Feld[x][y] != EL_EXPLOSION ?
1225 GfxElement[x][y] : Feld[x][y]);
1227 /* crumble field itself */
1228 if (GFX_CRUMBLED(element) && !IS_MOVING(x, y))
1230 if (!IN_SCR_FIELD(sx, sy))
1233 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1235 for (i = 0; i < 4; i++)
1237 int xx = x + xy[i][0];
1238 int yy = y + xy[i][1];
1240 element = (IN_LEV_FIELD(xx, yy) ? Feld[xx][yy] : BorderElement);
1242 /* check if neighbour field is of same type */
1243 if (GFX_CRUMBLED(element) && !IS_MOVING(xx, yy))
1247 if (Feld[x][y] == EL_CUSTOM_START + 123)
1248 printf("::: crumble [%d] THE CHAOS ENGINE (%d, %d): %d, %d\n",
1249 i, Feld[x][y], element,
1250 GFX_CRUMBLED(element), IS_MOVING(x, y));
1253 if (i == 1 || i == 2)
1255 width = crumbled_border_size;
1257 cx = (i == 2 ? TILEX - crumbled_border_size : 0);
1263 height = crumbled_border_size;
1265 cy = (i == 3 ? TILEY - crumbled_border_size : 0);
1268 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1269 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
1272 MarkTileDirty(sx, sy);
1274 else /* crumble neighbour fields */
1277 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1280 for (i = 0; i < 4; i++)
1282 int xx = x + xy[i][0];
1283 int yy = y + xy[i][1];
1284 int sxx = sx + xy[i][0];
1285 int syy = sy + xy[i][1];
1287 if (!IN_LEV_FIELD(xx, yy) ||
1288 !IN_SCR_FIELD(sxx, syy) ||
1289 !GFX_CRUMBLED(Feld[xx][yy]) ||
1294 graphic = el_act2crm(Feld[xx][yy], ACTION_DEFAULT);
1295 crumbled_border_size = graphic_info[graphic].border_size;
1297 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1300 if (i == 1 || i == 2)
1302 width = crumbled_border_size;
1304 cx = (i == 1 ? TILEX - crumbled_border_size : 0);
1310 height = crumbled_border_size;
1312 cy = (i == 0 ? TILEY - crumbled_border_size : 0);
1315 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1316 width, height, FX + sxx * TILEX + cx, FY + syy * TILEY + cy);
1318 MarkTileDirty(sxx, syy);
1323 void DrawLevelFieldCrumbledSand(int x, int y)
1328 if (!IN_LEV_FIELD(x, y))
1331 graphic = el_act2crm(Feld[x][y], ACTION_DEFAULT);
1333 DrawLevelFieldCrumbledSandExt(x, y, graphic, 0);
1335 DrawLevelFieldCrumbledSandExt(x, y, IMG_SAND_CRUMBLED, 0);
1339 void DrawLevelFieldCrumbledSandDigging(int x, int y, int direction,
1343 int graphic1 = el_act_dir2img(GfxElement[x][y], ACTION_DIGGING, direction);
1344 int graphic2 = el_act_dir2crm(GfxElement[x][y], ACTION_DIGGING, direction);
1346 int graphic1 = el_act_dir2img(EL_SAND, ACTION_DIGGING, direction);
1347 int graphic2 = el_act_dir2img(EL_SAND_CRUMBLED, ACTION_DIGGING, direction);
1349 int frame1 = getGraphicAnimationFrame(graphic1, step_frame);
1350 int frame2 = getGraphicAnimationFrame(graphic2, step_frame);
1351 int sx = SCREENX(x), sy = SCREENY(y);
1353 DrawGraphic(sx, sy, graphic1, frame1);
1354 DrawLevelFieldCrumbledSandExt(x, y, graphic2, frame2);
1357 void DrawLevelFieldCrumbledSandNeighbours(int x, int y)
1359 int sx = SCREENX(x), sy = SCREENY(y);
1360 static int xy[4][2] =
1369 for (i = 0; i < 4; i++)
1371 int xx = x + xy[i][0];
1372 int yy = y + xy[i][1];
1373 int sxx = sx + xy[i][0];
1374 int syy = sy + xy[i][1];
1376 if (!IN_LEV_FIELD(xx, yy) ||
1377 !IN_SCR_FIELD(sxx, syy) ||
1378 !GFX_CRUMBLED(Feld[xx][yy]) ||
1382 DrawLevelField(xx, yy);
1386 static int getBorderElement(int x, int y)
1390 { EL_STEELWALL_TOPLEFT, EL_INVISIBLE_STEELWALL_TOPLEFT },
1391 { EL_STEELWALL_TOPRIGHT, EL_INVISIBLE_STEELWALL_TOPRIGHT },
1392 { EL_STEELWALL_BOTTOMLEFT, EL_INVISIBLE_STEELWALL_BOTTOMLEFT },
1393 { EL_STEELWALL_BOTTOMRIGHT, EL_INVISIBLE_STEELWALL_BOTTOMRIGHT },
1394 { EL_STEELWALL_VERTICAL, EL_INVISIBLE_STEELWALL_VERTICAL },
1395 { EL_STEELWALL_HORIZONTAL, EL_INVISIBLE_STEELWALL_HORIZONTAL },
1396 { EL_STEELWALL, EL_INVISIBLE_STEELWALL }
1398 int steel_type = (BorderElement == EL_STEELWALL ? 0 : 1);
1399 int steel_position = (x == -1 && y == -1 ? 0 :
1400 x == lev_fieldx && y == -1 ? 1 :
1401 x == -1 && y == lev_fieldy ? 2 :
1402 x == lev_fieldx && y == lev_fieldy ? 3 :
1403 x == -1 || x == lev_fieldx ? 4 :
1404 y == -1 || y == lev_fieldy ? 5 : 6);
1406 return border[steel_position][steel_type];
1409 void DrawScreenElement(int x, int y, int element)
1411 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
1412 DrawLevelFieldCrumbledSand(LEVELX(x), LEVELY(y));
1415 void DrawLevelElement(int x, int y, int element)
1417 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1418 DrawScreenElement(SCREENX(x), SCREENY(y), element);
1421 void DrawScreenField(int x, int y)
1423 int lx = LEVELX(x), ly = LEVELY(y);
1424 int element, content;
1426 if (!IN_LEV_FIELD(lx, ly))
1428 if (lx < -1 || lx > lev_fieldx || ly < -1 || ly > lev_fieldy)
1431 element = getBorderElement(lx, ly);
1433 DrawScreenElement(x, y, element);
1437 element = Feld[lx][ly];
1438 content = Store[lx][ly];
1440 if (IS_MOVING(lx, ly))
1442 int horiz_move = (MovDir[lx][ly] == MV_LEFT || MovDir[lx][ly] == MV_RIGHT);
1443 boolean cut_mode = NO_CUTTING;
1445 if (element == EL_QUICKSAND_EMPTYING ||
1446 element == EL_MAGIC_WALL_EMPTYING ||
1447 element == EL_BD_MAGIC_WALL_EMPTYING ||
1448 element == EL_AMOEBA_DROPPING)
1449 cut_mode = CUT_ABOVE;
1450 else if (element == EL_QUICKSAND_FILLING ||
1451 element == EL_MAGIC_WALL_FILLING ||
1452 element == EL_BD_MAGIC_WALL_FILLING)
1453 cut_mode = CUT_BELOW;
1455 if (cut_mode == CUT_ABOVE)
1456 DrawScreenElementShifted(x, y, 0, 0, element, NO_CUTTING);
1458 DrawScreenElement(x, y, EL_EMPTY);
1461 DrawScreenElementShifted(x, y, MovPos[lx][ly], 0, element, NO_CUTTING);
1462 else if (cut_mode == NO_CUTTING)
1463 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], element, cut_mode);
1465 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], content, cut_mode);
1467 if (content == EL_ACID)
1468 DrawLevelElementThruMask(lx, ly + 1, EL_ACID);
1470 else if (IS_BLOCKED(lx, ly))
1475 boolean cut_mode = NO_CUTTING;
1476 int element_old, content_old;
1478 Blocked2Moving(lx, ly, &oldx, &oldy);
1481 horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
1482 MovDir[oldx][oldy] == MV_RIGHT);
1484 element_old = Feld[oldx][oldy];
1485 content_old = Store[oldx][oldy];
1487 if (element_old == EL_QUICKSAND_EMPTYING ||
1488 element_old == EL_MAGIC_WALL_EMPTYING ||
1489 element_old == EL_BD_MAGIC_WALL_EMPTYING ||
1490 element_old == EL_AMOEBA_DROPPING)
1491 cut_mode = CUT_ABOVE;
1493 DrawScreenElement(x, y, EL_EMPTY);
1496 DrawScreenElementShifted(sx, sy, MovPos[oldx][oldy], 0, element_old,
1498 else if (cut_mode == NO_CUTTING)
1499 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], element_old,
1502 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], content_old,
1505 else if (IS_DRAWABLE(element))
1506 DrawScreenElement(x, y, element);
1508 DrawScreenElement(x, y, EL_EMPTY);
1511 void DrawLevelField(int x, int y)
1513 if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1514 DrawScreenField(SCREENX(x), SCREENY(y));
1515 else if (IS_MOVING(x, y))
1519 Moving2Blocked(x, y, &newx, &newy);
1520 if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
1521 DrawScreenField(SCREENX(newx), SCREENY(newy));
1523 else if (IS_BLOCKED(x, y))
1527 Blocked2Moving(x, y, &oldx, &oldy);
1528 if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
1529 DrawScreenField(SCREENX(oldx), SCREENY(oldy));
1533 void DrawMiniElement(int x, int y, int element)
1537 graphic = el2edimg(element);
1538 DrawMiniGraphic(x, y, graphic);
1541 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
1543 int x = sx + scroll_x, y = sy + scroll_y;
1545 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
1546 DrawMiniElement(sx, sy, EL_EMPTY);
1547 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
1548 DrawMiniElement(sx, sy, Feld[x][y]);
1550 DrawMiniGraphic(sx, sy, el2edimg(getBorderElement(x, y)));
1553 void DrawEnvelopeBackground(int envelope_nr, int startx, int starty,
1554 int x, int y, int xsize, int ysize, int font_nr)
1556 int font_width = getFontWidth(font_nr);
1557 int font_height = getFontHeight(font_nr);
1558 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1561 int dst_x = SX + startx + x * font_width;
1562 int dst_y = SY + starty + y * font_height;
1563 int width = graphic_info[graphic].width;
1564 int height = graphic_info[graphic].height;
1565 int inner_width = MAX(width - 2 * font_width, font_width);
1566 int inner_height = MAX(height - 2 * font_height, font_height);
1567 int inner_sx = (width >= 3 * font_width ? font_width : 0);
1568 int inner_sy = (height >= 3 * font_height ? font_height : 0);
1569 boolean draw_masked = graphic_info[graphic].draw_masked;
1571 getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
1573 if (src_bitmap == NULL || width < font_width || height < font_height)
1575 ClearRectangle(drawto, dst_x, dst_y, font_width, font_height);
1579 src_x += (x == 0 ? 0 : x == xsize - 1 ? width - font_width :
1580 inner_sx + (x - 1) * font_width % inner_width);
1581 src_y += (y == 0 ? 0 : y == ysize - 1 ? height - font_height :
1582 inner_sy + (y - 1) * font_height % inner_height);
1586 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1587 dst_x - src_x, dst_y - src_y);
1588 BlitBitmapMasked(src_bitmap, drawto, src_x, src_y, font_width, font_height,
1592 BlitBitmap(src_bitmap, drawto, src_x, src_y, font_width, font_height,
1596 void AnimateEnvelope(int envelope_nr, int anim_mode, int action)
1598 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1599 boolean draw_masked = graphic_info[graphic].draw_masked;
1600 int mask_mode = (draw_masked ? BLIT_MASKED : BLIT_ON_BACKGROUND);
1601 boolean ffwd_delay = (tape.playing && tape.fast_forward);
1602 unsigned long anim_delay = 0;
1603 int anim_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
1604 int font_nr = FONT_ENVELOPE_1 + envelope_nr;
1605 int font_width = getFontWidth(font_nr);
1606 int font_height = getFontHeight(font_nr);
1607 int max_xsize = level.envelope_xsize[envelope_nr];
1608 int max_ysize = level.envelope_ysize[envelope_nr];
1609 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize : 0);
1610 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize : 0);
1611 int xend = max_xsize;
1612 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize : 0);
1613 int xstep = (xstart < xend ? 1 : 0);
1614 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
1617 for (x = xstart, y = ystart; x <= xend && y <= yend; x += xstep, y += ystep)
1619 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
1620 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
1621 int sx = (SXSIZE - xsize * font_width) / 2;
1622 int sy = (SYSIZE - ysize * font_height) / 2;
1625 SetDrawtoField(DRAW_BUFFERED);
1627 BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
1629 SetDrawtoField(DRAW_BACKBUFFER);
1631 for (yy = 0; yy < ysize; yy++) for (xx = 0; xx < xsize; xx++)
1632 DrawEnvelopeBackground(envelope_nr, sx,sy, xx,yy, xsize, ysize, font_nr);
1634 DrawTextToTextArea(SX + sx + font_width, SY + sy + font_height,
1635 level.envelope_text[envelope_nr], font_nr, max_xsize,
1636 xsize - 2, ysize - 2, mask_mode);
1638 redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
1641 WaitUntilDelayReached(&anim_delay, anim_delay_value / 2);
1645 void ShowEnvelope(int envelope_nr)
1647 int element = EL_ENVELOPE_1 + envelope_nr;
1648 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1649 int sound_opening = element_info[element].sound[ACTION_OPENING];
1650 int sound_closing = element_info[element].sound[ACTION_CLOSING];
1651 boolean ffwd_delay = (tape.playing && tape.fast_forward);
1652 int wait_delay_value = (ffwd_delay ? 500 : 1000);
1653 int anim_mode = graphic_info[graphic].anim_mode;
1654 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
1655 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
1657 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
1659 PlaySoundStereo(sound_opening, SOUND_MIDDLE);
1661 if (anim_mode == ANIM_DEFAULT)
1662 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_OPENING);
1664 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_OPENING);
1667 Delay(wait_delay_value);
1669 WaitForEventToContinue();
1671 PlaySoundStereo(sound_closing, SOUND_MIDDLE);
1673 if (anim_mode != ANIM_NONE)
1674 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_CLOSING);
1676 if (anim_mode == ANIM_DEFAULT)
1677 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_CLOSING);
1679 game.envelope_active = FALSE;
1681 SetDrawtoField(DRAW_BUFFERED);
1683 redraw_mask |= REDRAW_FIELD;
1687 void getMicroGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
1689 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
1690 int mini_startx = src_bitmap->width * 3 / 4;
1691 int mini_starty = src_bitmap->height * 2 / 3;
1692 int src_x = mini_startx + graphic_info[graphic].src_x / 8;
1693 int src_y = mini_starty + graphic_info[graphic].src_y / 8;
1695 *bitmap = src_bitmap;
1700 void DrawMicroElement(int xpos, int ypos, int element)
1704 int graphic = el2preimg(element);
1706 getMicroGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
1707 BlitBitmap(src_bitmap, drawto, src_x, src_y, MICRO_TILEX, MICRO_TILEY,
1715 SetDrawBackgroundMask(REDRAW_NONE);
1718 for (x = BX1; x <= BX2; x++)
1719 for (y = BY1; y <= BY2; y++)
1720 DrawScreenField(x, y);
1722 redraw_mask |= REDRAW_FIELD;
1725 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
1729 for (x = 0; x < size_x; x++)
1730 for (y = 0; y < size_y; y++)
1731 DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
1733 redraw_mask |= REDRAW_FIELD;
1736 static void DrawMicroLevelExt(int xpos, int ypos, int from_x, int from_y)
1740 DrawBackground(xpos, ypos, MICROLEV_XSIZE, MICROLEV_YSIZE);
1742 if (lev_fieldx < STD_LEV_FIELDX)
1743 xpos += (STD_LEV_FIELDX - lev_fieldx) / 2 * MICRO_TILEX;
1744 if (lev_fieldy < STD_LEV_FIELDY)
1745 ypos += (STD_LEV_FIELDY - lev_fieldy) / 2 * MICRO_TILEY;
1747 xpos += MICRO_TILEX;
1748 ypos += MICRO_TILEY;
1750 for (x = -1; x <= STD_LEV_FIELDX; x++)
1752 for (y = -1; y <= STD_LEV_FIELDY; y++)
1754 int lx = from_x + x, ly = from_y + y;
1756 if (lx >= 0 && lx < lev_fieldx && ly >= 0 && ly < lev_fieldy)
1757 DrawMicroElement(xpos + x * MICRO_TILEX, ypos + y * MICRO_TILEY,
1758 level.field[lx][ly]);
1759 else if (lx >= -1 && lx < lev_fieldx+1 && ly >= -1 && ly < lev_fieldy+1
1760 && BorderElement != EL_EMPTY)
1761 DrawMicroElement(xpos + x * MICRO_TILEX, ypos + y * MICRO_TILEY,
1762 getBorderElement(lx, ly));
1766 redraw_mask |= REDRAW_MICROLEVEL;
1769 #define MICROLABEL_EMPTY 0
1770 #define MICROLABEL_LEVEL_NAME 1
1771 #define MICROLABEL_CREATED_BY 2
1772 #define MICROLABEL_LEVEL_AUTHOR 3
1773 #define MICROLABEL_IMPORTED_FROM 4
1774 #define MICROLABEL_LEVEL_IMPORT_INFO 5
1776 static void DrawMicroLevelLabelExt(int mode)
1778 char label_text[MAX_OUTPUT_LINESIZE + 1];
1779 int max_len_label_text;
1780 int font_nr = FONT_TEXT_2;
1782 if (mode == MICROLABEL_CREATED_BY || mode == MICROLABEL_IMPORTED_FROM)
1783 font_nr = FONT_TEXT_3;
1785 max_len_label_text = SXSIZE / getFontWidth(font_nr);
1787 DrawBackground(SX, MICROLABEL_YPOS, SXSIZE, getFontHeight(font_nr));
1789 strncpy(label_text, (mode == MICROLABEL_LEVEL_NAME ? level.name :
1790 mode == MICROLABEL_CREATED_BY ? "created by" :
1791 mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
1792 mode == MICROLABEL_IMPORTED_FROM ? "imported from" :
1793 mode == MICROLABEL_LEVEL_IMPORT_INFO ?
1794 leveldir_current->imported_from : ""),
1795 max_len_label_text);
1796 label_text[max_len_label_text] = '\0';
1798 if (strlen(label_text) > 0)
1800 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
1801 int lypos = MICROLABEL_YPOS;
1803 DrawText(lxpos, lypos, label_text, font_nr);
1806 redraw_mask |= REDRAW_MICROLEVEL;
1809 void DrawMicroLevel(int xpos, int ypos, boolean restart)
1811 static unsigned long scroll_delay = 0;
1812 static unsigned long label_delay = 0;
1813 static int from_x, from_y, scroll_direction;
1814 static int label_state, label_counter;
1815 int last_game_status = game_status; /* save current game status */
1817 /* force PREVIEW font on preview level */
1818 game_status = GAME_MODE_PSEUDO_PREVIEW;
1822 from_x = from_y = 0;
1823 scroll_direction = MV_RIGHT;
1827 DrawMicroLevelExt(xpos, ypos, from_x, from_y);
1828 DrawMicroLevelLabelExt(label_state);
1830 /* initialize delay counters */
1831 DelayReached(&scroll_delay, 0);
1832 DelayReached(&label_delay, 0);
1834 if (leveldir_current->name)
1836 int text_width = getTextWidth(leveldir_current->name, FONT_TEXT_1);
1837 int lxpos = SX + (SXSIZE - text_width) / 2;
1838 int lypos = SY + 352;
1840 DrawText(lxpos, lypos, leveldir_current->name, FONT_TEXT_1);
1843 game_status = last_game_status; /* restore current game status */
1848 /* scroll micro level, if needed */
1849 if ((lev_fieldx > STD_LEV_FIELDX || lev_fieldy > STD_LEV_FIELDY) &&
1850 DelayReached(&scroll_delay, MICROLEVEL_SCROLL_DELAY))
1852 switch (scroll_direction)
1858 scroll_direction = MV_UP;
1862 if (from_x < lev_fieldx - STD_LEV_FIELDX)
1865 scroll_direction = MV_DOWN;
1872 scroll_direction = MV_RIGHT;
1876 if (from_y < lev_fieldy - STD_LEV_FIELDY)
1879 scroll_direction = MV_LEFT;
1886 DrawMicroLevelExt(xpos, ypos, from_x, from_y);
1889 /* redraw micro level label, if needed */
1890 if (strcmp(level.name, NAMELESS_LEVEL_NAME) != 0 &&
1891 strcmp(level.author, ANONYMOUS_NAME) != 0 &&
1892 strcmp(level.author, leveldir_current->name) != 0 &&
1893 DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
1895 int max_label_counter = 23;
1897 if (leveldir_current->imported_from != NULL)
1898 max_label_counter += 14;
1900 label_counter = (label_counter + 1) % max_label_counter;
1901 label_state = (label_counter >= 0 && label_counter <= 7 ?
1902 MICROLABEL_LEVEL_NAME :
1903 label_counter >= 9 && label_counter <= 12 ?
1904 MICROLABEL_CREATED_BY :
1905 label_counter >= 14 && label_counter <= 21 ?
1906 MICROLABEL_LEVEL_AUTHOR :
1907 label_counter >= 23 && label_counter <= 26 ?
1908 MICROLABEL_IMPORTED_FROM :
1909 label_counter >= 28 && label_counter <= 35 ?
1910 MICROLABEL_LEVEL_IMPORT_INFO : MICROLABEL_EMPTY);
1911 DrawMicroLevelLabelExt(label_state);
1914 game_status = last_game_status; /* restore current game status */
1917 void WaitForEventToContinue()
1919 boolean still_wait = TRUE;
1921 /* simulate releasing mouse button over last gadget, if still pressed */
1923 HandleGadgets(-1, -1, 0);
1925 button_status = MB_RELEASED;
1937 case EVENT_BUTTONPRESS:
1938 case EVENT_KEYPRESS:
1942 case EVENT_KEYRELEASE:
1943 ClearPlayerAction();
1947 HandleOtherEvents(&event);
1951 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
1958 /* don't eat all CPU time */
1963 #define MAX_REQUEST_LINES 13
1964 #define MAX_REQUEST_LINE_FONT1_LEN 7
1965 #define MAX_REQUEST_LINE_FONT2_LEN 10
1967 boolean Request(char *text, unsigned int req_state)
1969 int mx, my, ty, result = -1;
1970 unsigned int old_door_state;
1971 int last_game_status = game_status; /* save current game status */
1972 int max_request_line_len = MAX_REQUEST_LINE_FONT1_LEN;
1973 int font_nr = FONT_TEXT_2;
1974 int max_word_len = 0;
1977 for (text_ptr = text; *text_ptr; text_ptr++)
1979 max_word_len = (*text_ptr != ' ' ? max_word_len + 1 : 0);
1981 if (max_word_len > MAX_REQUEST_LINE_FONT1_LEN)
1983 max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
1984 font_nr = FONT_LEVEL_NUMBER;
1991 SetMouseCursor(CURSOR_DEFAULT);
1994 #if defined(PLATFORM_UNIX)
1995 /* pause network game while waiting for request to answer */
1996 if (options.network &&
1997 game_status == GAME_MODE_PLAYING &&
1998 req_state & REQUEST_WAIT_FOR)
1999 SendToServer_PausePlaying();
2002 old_door_state = GetDoorState();
2004 /* simulate releasing mouse button over last gadget, if still pressed */
2006 HandleGadgets(-1, -1, 0);
2010 CloseDoor(DOOR_CLOSE_1);
2012 /* save old door content */
2013 BlitBitmap(bitmap_db_door, bitmap_db_door,
2014 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
2015 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
2017 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
2019 /* clear door drawing field */
2020 DrawBackground(DX, DY, DXSIZE, DYSIZE);
2022 /* force DOOR font on preview level */
2023 game_status = GAME_MODE_PSEUDO_DOOR;
2025 /* write text for request */
2026 for (ty = 0; ty < MAX_REQUEST_LINES; ty++)
2028 char text_line[max_request_line_len + 1];
2034 for (tl = 0, tx = 0; tx < max_request_line_len; tl++, tx++)
2037 if (!tc || tc == ' ')
2048 strncpy(text_line, text, tl);
2051 DrawText(DX + (DXSIZE - tl * getFontWidth(font_nr)) / 2,
2052 DY + 8 + ty * (getFontHeight(font_nr) + 2),
2053 text_line, font_nr);
2055 text += tl + (tc == ' ' ? 1 : 0);
2058 game_status = last_game_status; /* restore current game status */
2060 if (req_state & REQ_ASK)
2062 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
2063 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
2065 else if (req_state & REQ_CONFIRM)
2067 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
2069 else if (req_state & REQ_PLAYER)
2071 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
2072 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
2073 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
2074 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
2077 /* copy request gadgets to door backbuffer */
2078 BlitBitmap(drawto, bitmap_db_door,
2079 DX, DY, DXSIZE, DYSIZE,
2080 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2082 OpenDoor(DOOR_OPEN_1);
2088 if (!(req_state & REQUEST_WAIT_FOR))
2090 SetDrawBackgroundMask(REDRAW_FIELD);
2095 if (game_status != GAME_MODE_MAIN)
2098 button_status = MB_RELEASED;
2100 request_gadget_id = -1;
2102 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
2105 SetMouseCursor(CURSOR_DEFAULT);
2118 case EVENT_BUTTONPRESS:
2119 case EVENT_BUTTONRELEASE:
2120 case EVENT_MOTIONNOTIFY:
2122 if (event.type == EVENT_MOTIONNOTIFY)
2124 if (!PointerInWindow(window))
2125 continue; /* window and pointer are on different screens */
2130 motion_status = TRUE;
2131 mx = ((MotionEvent *) &event)->x;
2132 my = ((MotionEvent *) &event)->y;
2136 motion_status = FALSE;
2137 mx = ((ButtonEvent *) &event)->x;
2138 my = ((ButtonEvent *) &event)->y;
2139 if (event.type == EVENT_BUTTONPRESS)
2140 button_status = ((ButtonEvent *) &event)->button;
2142 button_status = MB_RELEASED;
2145 /* this sets 'request_gadget_id' */
2146 HandleGadgets(mx, my, button_status);
2148 switch(request_gadget_id)
2150 case TOOL_CTRL_ID_YES:
2153 case TOOL_CTRL_ID_NO:
2156 case TOOL_CTRL_ID_CONFIRM:
2157 result = TRUE | FALSE;
2160 case TOOL_CTRL_ID_PLAYER_1:
2163 case TOOL_CTRL_ID_PLAYER_2:
2166 case TOOL_CTRL_ID_PLAYER_3:
2169 case TOOL_CTRL_ID_PLAYER_4:
2180 case EVENT_KEYPRESS:
2181 switch(GetEventKey((KeyEvent *)&event, TRUE))
2194 if (req_state & REQ_PLAYER)
2198 case EVENT_KEYRELEASE:
2199 ClearPlayerAction();
2203 HandleOtherEvents(&event);
2207 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
2209 int joy = AnyJoystick();
2211 if (joy & JOY_BUTTON_1)
2213 else if (joy & JOY_BUTTON_2)
2219 /* don't eat all CPU time */
2223 if (game_status != GAME_MODE_MAIN)
2228 if (!(req_state & REQ_STAY_OPEN))
2230 CloseDoor(DOOR_CLOSE_1);
2232 if (!(req_state & REQ_STAY_CLOSED) && (old_door_state & DOOR_OPEN_1))
2234 BlitBitmap(bitmap_db_door, bitmap_db_door,
2235 DOOR_GFX_PAGEX2,DOOR_GFX_PAGEY1, DXSIZE,DYSIZE,
2236 DOOR_GFX_PAGEX1,DOOR_GFX_PAGEY1);
2237 OpenDoor(DOOR_OPEN_1);
2243 SetDrawBackgroundMask(REDRAW_FIELD);
2245 #if defined(PLATFORM_UNIX)
2246 /* continue network game after request */
2247 if (options.network &&
2248 game_status == GAME_MODE_PLAYING &&
2249 req_state & REQUEST_WAIT_FOR)
2250 SendToServer_ContinuePlaying();
2256 unsigned int OpenDoor(unsigned int door_state)
2258 unsigned int new_door_state;
2260 if (door_state & DOOR_COPY_BACK)
2262 BlitBitmap(bitmap_db_door, bitmap_db_door,
2263 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE + VYSIZE,
2264 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2265 door_state &= ~DOOR_COPY_BACK;
2268 new_door_state = MoveDoor(door_state);
2270 return(new_door_state);
2273 unsigned int CloseDoor(unsigned int door_state)
2275 unsigned int new_door_state;
2277 BlitBitmap(backbuffer, bitmap_db_door,
2278 DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2279 BlitBitmap(backbuffer, bitmap_db_door,
2280 VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
2282 new_door_state = MoveDoor(door_state);
2284 return(new_door_state);
2287 unsigned int GetDoorState()
2289 return MoveDoor(DOOR_GET_STATE);
2292 unsigned int SetDoorState(unsigned int door_state)
2294 return MoveDoor(door_state | DOOR_SET_STATE);
2297 unsigned int MoveDoor(unsigned int door_state)
2299 static int door1 = DOOR_OPEN_1;
2300 static int door2 = DOOR_CLOSE_2;
2301 unsigned long door_delay = 0;
2302 unsigned long door_delay_value;
2305 if (door_state == DOOR_GET_STATE)
2306 return(door1 | door2);
2308 if (door_state & DOOR_SET_STATE)
2310 if (door_state & DOOR_ACTION_1)
2311 door1 = door_state & DOOR_ACTION_1;
2312 if (door_state & DOOR_ACTION_2)
2313 door2 = door_state & DOOR_ACTION_2;
2315 return(door1 | door2);
2318 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
2319 door_state &= ~DOOR_OPEN_1;
2320 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
2321 door_state &= ~DOOR_CLOSE_1;
2322 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
2323 door_state &= ~DOOR_OPEN_2;
2324 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
2325 door_state &= ~DOOR_CLOSE_2;
2327 door_delay_value = (door_state & DOOR_ACTION_1 ? door_1.step_delay :
2330 if (setup.quick_doors)
2332 stepsize = 20; /* must be choosen to always draw last frame */
2333 door_delay_value = 0;
2335 StopSound(SND_DOOR_OPENING);
2336 StopSound(SND_DOOR_CLOSING);
2339 if (global.autoplay_leveldir)
2341 door_state |= DOOR_NO_DELAY;
2342 door_state &= ~DOOR_CLOSE_ALL;
2345 if (door_state & DOOR_ACTION)
2347 boolean door_1_done = !(door_state & DOOR_ACTION_1);
2348 boolean door_2_done = !(door_state & DOOR_ACTION_2);
2349 int start = ((door_state & DOOR_NO_DELAY) ? DXSIZE : 0);
2350 int end = (door_state & DOOR_ACTION_1 &&
2351 door_1.anim_mode == ANIM_VERTICAL ? DYSIZE : DXSIZE);
2354 if (!(door_state & DOOR_NO_DELAY))
2356 /* opening door sound has priority over simultaneously closing door */
2357 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
2358 PlaySoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
2359 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
2360 PlaySoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
2363 for (x = start; x <= end && !(door_1_done && door_2_done); x += stepsize)
2365 Bitmap *bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
2366 GC gc = bitmap->stored_clip_gc;
2368 if (door_state & DOOR_ACTION_1)
2370 int a = MIN(x * door_1.step_offset, end);
2371 int i = (door_state & DOOR_OPEN_1 ? end - a : a);
2375 BlitBitmap(bitmap_db_door, drawto,
2376 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + i / 2,
2377 DXSIZE,DYSIZE - i / 2, DX, DY);
2379 ClearRectangle(drawto, DX, DY + DYSIZE - i / 2, DXSIZE, i / 2);
2382 if (door_1.anim_mode == ANIM_HORIZONTAL && x <= DXSIZE)
2384 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
2385 int dst1_x = DX + DXSIZE - i, dst1_y = DY;
2386 int src2_x = DXSIZE - i, src2_y = DOOR_GFX_PAGEY1;
2387 int dst2_x = DX, dst2_y = DY;
2388 int width = i, height = DYSIZE;
2390 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2391 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2394 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2395 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2398 else if (door_1.anim_mode == ANIM_VERTICAL && x <= DYSIZE)
2400 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
2401 int dst1_x = DX, dst1_y = DY + DYSIZE - i;
2402 int src2_x = 0, src2_y = DOOR_GFX_PAGEY1 + DYSIZE - i;
2403 int dst2_x = DX, dst2_y = DY;
2404 int width = DXSIZE, height = i;
2406 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2407 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2410 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2411 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2414 else if (x <= DXSIZE) /* ANIM_DEFAULT */
2416 int j = (door_1.anim_mode == ANIM_DEFAULT ? (DXSIZE - i) / 3 : 0);
2418 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2419 BlitBitmapMasked(bitmap, drawto,
2420 DXSIZE, DOOR_GFX_PAGEY1, i, 77,
2421 DX + DXSIZE - i, DY + j);
2422 BlitBitmapMasked(bitmap, drawto,
2423 DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63,
2424 DX + DXSIZE - i, DY + 140 + j);
2425 SetClipOrigin(bitmap, gc, DX - DXSIZE + i,
2426 DY - (DOOR_GFX_PAGEY1 + j));
2427 BlitBitmapMasked(bitmap, drawto,
2428 DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j,
2430 BlitBitmapMasked(bitmap, drawto,
2431 DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63,
2434 BlitBitmapMasked(bitmap, drawto,
2435 DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
2437 BlitBitmapMasked(bitmap, drawto,
2438 DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
2440 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2441 BlitBitmapMasked(bitmap, drawto,
2442 DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
2443 DX + DXSIZE - i, DY + 77 + j);
2444 BlitBitmapMasked(bitmap, drawto,
2445 DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
2446 DX + DXSIZE - i, DY + 203 + j);
2449 redraw_mask |= REDRAW_DOOR_1;
2450 door_1_done = (a == end);
2453 if (door_state & DOOR_ACTION_2)
2455 int a = MIN(x * door_2.step_offset, VXSIZE);
2456 int i = (door_state & DOOR_OPEN_2 ? VXSIZE - a : a);
2460 BlitBitmap(bitmap_db_door, drawto,
2461 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + i / 2,
2462 VXSIZE, VYSIZE - i / 2, VX, VY);
2464 ClearRectangle(drawto, VX, VY + VYSIZE - i / 2, VXSIZE, i / 2);
2467 if (door_2.anim_mode == ANIM_HORIZONTAL && x <= VXSIZE)
2469 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
2470 int dst1_x = VX + VXSIZE - i, dst1_y = VY;
2471 int src2_x = VXSIZE - i, src2_y = DOOR_GFX_PAGEY2;
2472 int dst2_x = VX, dst2_y = VY;
2473 int width = i, height = VYSIZE;
2475 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2476 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2479 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2480 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2483 else if (door_2.anim_mode == ANIM_VERTICAL && x <= VYSIZE)
2485 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
2486 int dst1_x = VX, dst1_y = VY + VYSIZE - i;
2487 int src2_x = 0, src2_y = DOOR_GFX_PAGEY2 + VYSIZE - i;
2488 int dst2_x = VX, dst2_y = VY;
2489 int width = VXSIZE, height = i;
2491 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2492 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2495 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2496 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2499 else if (x <= VXSIZE) /* ANIM_DEFAULT */
2501 int j = (door_2.anim_mode == ANIM_DEFAULT ? (VXSIZE - i) / 3 : 0);
2503 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2504 BlitBitmapMasked(bitmap, drawto,
2505 VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2,
2506 VX + VXSIZE - i, VY + j);
2507 SetClipOrigin(bitmap, gc,
2508 VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
2509 BlitBitmapMasked(bitmap, drawto,
2510 VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j,
2513 BlitBitmapMasked(bitmap, drawto,
2514 VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2,
2515 i, VYSIZE / 2, VX, VY + VYSIZE / 2 - j);
2516 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2517 BlitBitmapMasked(bitmap, drawto,
2518 VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2,
2520 VX + VXSIZE - i, VY + VYSIZE / 2 + j);
2523 redraw_mask |= REDRAW_DOOR_2;
2524 door_2_done = (a == VXSIZE);
2529 if (game_status == GAME_MODE_MAIN)
2532 if (!(door_state & DOOR_NO_DELAY))
2533 WaitUntilDelayReached(&door_delay, door_delay_value);
2537 if (setup.quick_doors)
2539 StopSound(SND_DOOR_OPENING);
2540 StopSound(SND_DOOR_CLOSING);
2543 if (door_state & DOOR_ACTION_1)
2544 door1 = door_state & DOOR_ACTION_1;
2545 if (door_state & DOOR_ACTION_2)
2546 door2 = door_state & DOOR_ACTION_2;
2548 return (door1 | door2);
2551 void DrawSpecialEditorDoor()
2553 /* draw bigger toolbox window */
2554 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
2555 DOOR_GFX_PAGEX7, 0, EXSIZE + 8, 8,
2557 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
2558 EX - 4, VY - 4, EXSIZE + 8, EYSIZE - VYSIZE + 4,
2561 redraw_mask |= REDRAW_ALL;
2564 void UndrawSpecialEditorDoor()
2566 /* draw normal tape recorder window */
2567 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
2568 EX - 4, EY - 12, EXSIZE + 8, EYSIZE - VYSIZE + 12,
2571 redraw_mask |= REDRAW_ALL;
2575 /* ---------- new tool button stuff ---------------------------------------- */
2577 /* graphic position values for tool buttons */
2578 #define TOOL_BUTTON_YES_XPOS 2
2579 #define TOOL_BUTTON_YES_YPOS 250
2580 #define TOOL_BUTTON_YES_GFX_YPOS 0
2581 #define TOOL_BUTTON_YES_XSIZE 46
2582 #define TOOL_BUTTON_YES_YSIZE 28
2583 #define TOOL_BUTTON_NO_XPOS 52
2584 #define TOOL_BUTTON_NO_YPOS TOOL_BUTTON_YES_YPOS
2585 #define TOOL_BUTTON_NO_GFX_YPOS TOOL_BUTTON_YES_GFX_YPOS
2586 #define TOOL_BUTTON_NO_XSIZE TOOL_BUTTON_YES_XSIZE
2587 #define TOOL_BUTTON_NO_YSIZE TOOL_BUTTON_YES_YSIZE
2588 #define TOOL_BUTTON_CONFIRM_XPOS TOOL_BUTTON_YES_XPOS
2589 #define TOOL_BUTTON_CONFIRM_YPOS TOOL_BUTTON_YES_YPOS
2590 #define TOOL_BUTTON_CONFIRM_GFX_YPOS 30
2591 #define TOOL_BUTTON_CONFIRM_XSIZE 96
2592 #define TOOL_BUTTON_CONFIRM_YSIZE TOOL_BUTTON_YES_YSIZE
2593 #define TOOL_BUTTON_PLAYER_XSIZE 30
2594 #define TOOL_BUTTON_PLAYER_YSIZE 30
2595 #define TOOL_BUTTON_PLAYER_GFX_XPOS 5
2596 #define TOOL_BUTTON_PLAYER_GFX_YPOS 185
2597 #define TOOL_BUTTON_PLAYER_XPOS (5 + TOOL_BUTTON_PLAYER_XSIZE / 2)
2598 #define TOOL_BUTTON_PLAYER_YPOS (215 - TOOL_BUTTON_PLAYER_YSIZE / 2)
2599 #define TOOL_BUTTON_PLAYER1_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2600 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2601 #define TOOL_BUTTON_PLAYER2_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2602 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2603 #define TOOL_BUTTON_PLAYER3_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2604 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2605 #define TOOL_BUTTON_PLAYER4_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2606 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2607 #define TOOL_BUTTON_PLAYER1_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2608 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2609 #define TOOL_BUTTON_PLAYER2_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2610 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2611 #define TOOL_BUTTON_PLAYER3_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2612 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2613 #define TOOL_BUTTON_PLAYER4_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2614 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2623 } toolbutton_info[NUM_TOOL_BUTTONS] =
2626 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_GFX_YPOS,
2627 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_YPOS,
2628 TOOL_BUTTON_YES_XSIZE, TOOL_BUTTON_YES_YSIZE,
2633 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_GFX_YPOS,
2634 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_YPOS,
2635 TOOL_BUTTON_NO_XSIZE, TOOL_BUTTON_NO_YSIZE,
2640 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_GFX_YPOS,
2641 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_YPOS,
2642 TOOL_BUTTON_CONFIRM_XSIZE, TOOL_BUTTON_CONFIRM_YSIZE,
2643 TOOL_CTRL_ID_CONFIRM,
2647 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2648 TOOL_BUTTON_PLAYER1_XPOS, TOOL_BUTTON_PLAYER1_YPOS,
2649 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2650 TOOL_CTRL_ID_PLAYER_1,
2654 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2655 TOOL_BUTTON_PLAYER2_XPOS, TOOL_BUTTON_PLAYER2_YPOS,
2656 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2657 TOOL_CTRL_ID_PLAYER_2,
2661 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2662 TOOL_BUTTON_PLAYER3_XPOS, TOOL_BUTTON_PLAYER3_YPOS,
2663 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2664 TOOL_CTRL_ID_PLAYER_3,
2668 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2669 TOOL_BUTTON_PLAYER4_XPOS, TOOL_BUTTON_PLAYER4_YPOS,
2670 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2671 TOOL_CTRL_ID_PLAYER_4,
2676 void CreateToolButtons()
2680 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
2682 Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
2683 Bitmap *deco_bitmap = None;
2684 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
2685 struct GadgetInfo *gi;
2686 unsigned long event_mask;
2687 int gd_xoffset, gd_yoffset;
2688 int gd_x1, gd_x2, gd_y;
2691 event_mask = GD_EVENT_RELEASED;
2693 gd_xoffset = toolbutton_info[i].xpos;
2694 gd_yoffset = toolbutton_info[i].ypos;
2695 gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
2696 gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
2697 gd_y = DOOR_GFX_PAGEY1 + gd_yoffset;
2699 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
2701 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
2703 getMiniGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr),
2704 &deco_bitmap, &deco_x, &deco_y);
2705 deco_xpos = (toolbutton_info[i].width - MINI_TILEX) / 2;
2706 deco_ypos = (toolbutton_info[i].height - MINI_TILEY) / 2;
2709 gi = CreateGadget(GDI_CUSTOM_ID, id,
2710 GDI_INFO_TEXT, toolbutton_info[i].infotext,
2711 GDI_X, DX + toolbutton_info[i].x,
2712 GDI_Y, DY + toolbutton_info[i].y,
2713 GDI_WIDTH, toolbutton_info[i].width,
2714 GDI_HEIGHT, toolbutton_info[i].height,
2715 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
2716 GDI_STATE, GD_BUTTON_UNPRESSED,
2717 GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
2718 GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
2719 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
2720 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
2721 GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
2722 GDI_DECORATION_SHIFTING, 1, 1,
2723 GDI_EVENT_MASK, event_mask,
2724 GDI_CALLBACK_ACTION, HandleToolButtons,
2728 Error(ERR_EXIT, "cannot create gadget");
2730 tool_gadget[id] = gi;
2734 void FreeToolButtons()
2738 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
2739 FreeGadget(tool_gadget[i]);
2742 static void UnmapToolButtons()
2746 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
2747 UnmapGadget(tool_gadget[i]);
2750 static void HandleToolButtons(struct GadgetInfo *gi)
2752 request_gadget_id = gi->custom_id;
2755 int get_next_element(int element)
2759 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
2760 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
2761 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
2762 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
2763 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
2764 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
2765 case EL_AMOEBA_DROPPING: return EL_AMOEBA_WET;
2767 default: return element;
2771 int el_act_dir2img(int element, int action, int direction)
2773 element = GFX_ELEMENT(element);
2774 direction = MV_DIR_BIT(direction);
2776 return element_info[element].direction_graphic[action][direction];
2779 static int el_act_dir2crm(int element, int action, int direction)
2781 element = GFX_ELEMENT(element);
2782 direction = MV_DIR_BIT(direction);
2784 return element_info[element].direction_crumbled[action][direction];
2787 int el_act2img(int element, int action)
2789 element = GFX_ELEMENT(element);
2791 return element_info[element].graphic[action];
2794 int el_act2crm(int element, int action)
2796 element = GFX_ELEMENT(element);
2798 return element_info[element].crumbled[action];
2801 int el_dir2img(int element, int direction)
2803 element = GFX_ELEMENT(element);
2805 return el_act_dir2img(element, ACTION_DEFAULT, direction);
2808 int el2img(int element)
2810 element = GFX_ELEMENT(element);
2812 return element_info[element].graphic[ACTION_DEFAULT];
2815 int el2edimg(int element)
2817 element = GFX_ELEMENT(element);
2819 return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
2822 int el2preimg(int element)
2824 element = GFX_ELEMENT(element);
2826 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];