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], MovDir[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], MovDir[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 void DrawAllPlayers()
536 for(i=0; i<MAX_PLAYERS; i++)
537 if (stored_player[i].active)
538 DrawPlayer(&stored_player[i]);
541 void DrawPlayerField(int x, int y)
543 if (!IS_PLAYER(x, y))
546 DrawPlayer(PLAYERINFO(x, y));
549 void DrawPlayer(struct PlayerInfo *player)
553 int move_dir = player->MovDir;
555 int last_jx = player->last_jx;
556 int last_jy = player->last_jy;
557 int next_jx = jx + (jx - last_jx);
558 int next_jy = jy + (jy - last_jy);
559 boolean player_is_moving = (last_jx != jx || last_jy != jy ? TRUE : FALSE);
561 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? +1 : 0);
562 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? +1 : 0);
563 int last_jx = (player->is_moving ? jx - dx : jx);
564 int last_jy = (player->is_moving ? jy - dy : jy);
565 int next_jx = jx + dx;
566 int next_jy = jy + dy;
567 boolean player_is_moving = (player->MovPos ? TRUE : FALSE);
569 int sx = SCREENX(jx), sy = SCREENY(jy);
570 int sxx = 0, syy = 0;
571 int element = Feld[jx][jy], last_element = Feld[last_jx][last_jy];
573 int action = ACTION_DEFAULT;
576 if (!player->active || !IN_SCR_FIELD(SCREENX(last_jx), SCREENY(last_jy)))
580 if (!IN_LEV_FIELD(jx, jy))
582 printf("DrawPlayerField(): x = %d, y = %d\n",jx,jy);
583 printf("DrawPlayerField(): sx = %d, sy = %d\n",sx,sy);
584 printf("DrawPlayerField(): This should never happen!\n");
589 if (element == EL_EXPLOSION)
592 action = (player->is_pushing ? ACTION_PUSHING :
593 player->is_digging ? ACTION_DIGGING :
594 player->is_collecting ? ACTION_COLLECTING :
595 player->is_moving ? ACTION_MOVING :
596 player->is_snapping ? ACTION_SNAPPING : ACTION_DEFAULT);
599 printf("::: '%s'\n", element_action_info[action].suffix);
602 InitPlayerGfxAnimation(player, action, move_dir);
604 /* ----------------------------------------------------------------------- */
605 /* draw things in the field the player is leaving, if needed */
606 /* ----------------------------------------------------------------------- */
609 if (player->is_moving)
611 if (player_is_moving)
614 if (Back[last_jx][last_jy] && IS_DRAWABLE(last_element))
616 DrawLevelElement(last_jx, last_jy, Back[last_jx][last_jy]);
618 if (last_element == EL_DYNAMITE_ACTIVE ||
619 last_element == EL_SP_DISK_RED_ACTIVE)
620 DrawDynamite(last_jx, last_jy);
622 DrawLevelFieldThruMask(last_jx, last_jy);
624 else if (last_element == EL_DYNAMITE_ACTIVE ||
625 last_element == EL_SP_DISK_RED_ACTIVE)
626 DrawDynamite(last_jx, last_jy);
628 DrawLevelField(last_jx, last_jy);
630 if (player->is_pushing && IN_SCR_FIELD(SCREENX(next_jx), SCREENY(next_jy)))
631 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
634 if (!IN_SCR_FIELD(sx, sy))
637 if (setup.direct_draw)
638 SetDrawtoField(DRAW_BUFFERED);
640 /* ----------------------------------------------------------------------- */
641 /* draw things behind the player, if needed */
642 /* ----------------------------------------------------------------------- */
645 DrawLevelElement(jx, jy, Back[jx][jy]);
646 else if (IS_ACTIVE_BOMB(element))
647 DrawLevelElement(jx, jy, EL_EMPTY);
650 if (player_is_moving && GfxElement[jx][jy] != EL_UNDEFINED)
652 if (GFX_CRUMBLED(GfxElement[jx][jy]))
653 DrawLevelFieldCrumbledSandDigging(jx, jy, move_dir, player->StepFrame);
656 int old_element = GfxElement[jx][jy];
657 int old_graphic = el_act_dir2img(old_element, action, move_dir);
658 int frame = getGraphicAnimationFrame(old_graphic, player->StepFrame);
660 DrawGraphic(sx, sy, old_graphic, frame);
665 GfxElement[jx][jy] = EL_UNDEFINED;
667 DrawLevelField(jx, jy);
671 /* ----------------------------------------------------------------------- */
672 /* draw player himself */
673 /* ----------------------------------------------------------------------- */
675 if (player->use_murphy_graphic)
677 static int last_horizontal_dir = MV_LEFT;
679 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
680 last_horizontal_dir = move_dir;
682 graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, move_dir);
684 if (graphic == IMG_SP_MURPHY) /* undefined => use special graphic */
686 int direction = (player->is_snapping ? move_dir : last_horizontal_dir);
688 graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, direction);
692 graphic = el_act_dir2img(player->element_nr, player->GfxAction, move_dir);
694 frame = getGraphicAnimationFrame(graphic, player->Frame);
698 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
699 sxx = player->GfxPos;
701 syy = player->GfxPos;
704 if (!setup.soft_scrolling && ScreenMovPos)
707 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
709 if (SHIELD_ON(player))
711 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
712 IMG_SHIELD_NORMAL_ACTIVE);
713 int frame = getGraphicAnimationFrame(graphic, -1);
715 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
718 /* ----------------------------------------------------------------------- */
719 /* draw things the player is pushing, if needed */
720 /* ----------------------------------------------------------------------- */
723 printf("::: %d, %d [%d, %d] [%d]\n",
724 player->is_pushing, player_is_moving, player->GfxAction,
725 player->is_moving, player_is_moving);
729 if (player->is_pushing && player->is_moving)
731 if (player->is_pushing && player_is_moving)
734 int px = SCREENX(next_jx), py = SCREENY(next_jy);
736 if (Back[next_jx][next_jy])
737 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
739 if ((sxx || syy) && element == EL_SOKOBAN_OBJECT)
740 DrawGraphicShiftedThruMask(px, py, sxx, syy, IMG_SOKOBAN_OBJECT, 0,
744 int element = MovingOrBlocked2Element(next_jx, next_jy);
745 int graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
746 int frame = getGraphicAnimationFrame(graphic, player->Frame);
748 DrawGraphicShifted(px, py, sxx, syy, graphic, frame,
749 NO_CUTTING, NO_MASKING);
753 /* ----------------------------------------------------------------------- */
754 /* draw things in front of player (active dynamite or dynabombs) */
755 /* ----------------------------------------------------------------------- */
757 if (IS_ACTIVE_BOMB(element))
759 graphic = el2img(element);
760 frame = getGraphicAnimationFrame(graphic, GfxFrame[jx][jy]);
762 if (game.emulation == EMU_SUPAPLEX)
763 DrawGraphic(sx, sy, IMG_SP_DISK_RED, frame);
765 DrawGraphicThruMask(sx, sy, graphic, frame);
768 if (player_is_moving && last_element == EL_EXPLOSION)
770 int graphic = el_act2img(GfxElement[last_jx][last_jy], ACTION_EXPLODING);
771 int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
772 int phase = ExplodePhase[last_jx][last_jy] - 1;
773 int frame = getGraphicAnimationFrame(graphic, phase - delay);
776 DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy), graphic, frame);
779 /* ----------------------------------------------------------------------- */
780 /* draw elements the player is just walking/passing through/under */
781 /* ----------------------------------------------------------------------- */
783 /* handle the field the player is leaving ... */
784 if (player_is_moving && IS_ACCESSIBLE_INSIDE(last_element))
785 DrawLevelField(last_jx, last_jy);
786 else if (player_is_moving && IS_ACCESSIBLE_UNDER(last_element))
787 DrawLevelFieldThruMask(last_jx, last_jy);
789 /* ... and the field the player is entering */
790 if (IS_ACCESSIBLE_INSIDE(element))
791 DrawLevelField(jx, jy);
792 else if (IS_ACCESSIBLE_UNDER(element))
793 DrawLevelFieldThruMask(jx, jy);
795 if (setup.direct_draw)
797 int dest_x = SX + SCREENX(MIN(jx, last_jx)) * TILEX;
798 int dest_y = SY + SCREENY(MIN(jy, last_jy)) * TILEY;
799 int x_size = TILEX * (1 + ABS(jx - last_jx));
800 int y_size = TILEY * (1 + ABS(jy - last_jy));
802 BlitBitmap(drawto_field, window,
803 dest_x, dest_y, x_size, y_size, dest_x, dest_y);
804 SetDrawtoField(DRAW_DIRECT);
807 MarkTileDirty(sx,sy);
810 void getGraphicSource(int graphic, int frame, Bitmap **bitmap, int *x, int *y)
812 struct GraphicInfo *g = &graphic_info[graphic];
816 if (g->offset_y == 0) /* frames are ordered horizontally */
818 int max_width = g->anim_frames_per_line * g->width;
820 *x = (g->src_x + frame * g->offset_x) % max_width;
821 *y = g->src_y + (g->src_x + frame * g->offset_x) / max_width * g->height;
823 else if (g->offset_x == 0) /* frames are ordered vertically */
825 int max_height = g->anim_frames_per_line * g->height;
827 *x = g->src_x + (g->src_y + frame * g->offset_y) / max_height * g->width;
828 *y = (g->src_y + frame * g->offset_y) % max_height;
830 else /* frames are ordered diagonally */
832 *x = g->src_x + frame * g->offset_x;
833 *y = g->src_y + frame * g->offset_y;
837 void DrawGraphic(int x, int y, int graphic, int frame)
840 if (!IN_SCR_FIELD(x, y))
842 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
843 printf("DrawGraphic(): This should never happen!\n");
848 DrawGraphicExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic, frame);
852 void DrawGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
858 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
859 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
862 void DrawGraphicThruMask(int x, int y, int graphic, int frame)
865 if (!IN_SCR_FIELD(x, y))
867 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
868 printf("DrawGraphicThruMask(): This should never happen!\n");
873 DrawGraphicThruMaskExt(drawto_field, FX + x * TILEX, FY + y *TILEY, graphic,
878 void DrawGraphicThruMaskExt(DrawBuffer *d, int dest_x, int dest_y, int graphic,
886 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
887 drawing_gc = src_bitmap->stored_clip_gc;
889 GC drawing_gc = src_bitmap->stored_clip_gc;
890 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
891 int src_x = graphic_info[graphic].src_x;
892 int src_y = graphic_info[graphic].src_y;
893 int offset_x = graphic_info[graphic].offset_x;
894 int offset_y = graphic_info[graphic].offset_y;
896 src_x += frame * offset_x;
897 src_y += frame * offset_y;
901 SetClipOrigin(src_bitmap, drawing_gc, dest_x - src_x, dest_y - src_y);
902 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX, TILEY, dest_x, dest_y);
905 void DrawMiniGraphic(int x, int y, int graphic)
907 DrawMiniGraphicExt(drawto, SX + x * MINI_TILEX,SY + y * MINI_TILEY, graphic);
908 MarkTileDirty(x / 2, y / 2);
911 void getMiniGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
913 struct GraphicInfo *g = &graphic_info[graphic];
915 int mini_starty = g->bitmap->height * 2 / 3;
918 *x = mini_startx + g->src_x / 2;
919 *y = mini_starty + g->src_y / 2;
922 void DrawMiniGraphicExt(DrawBuffer *d, int x, int y, int graphic)
927 getMiniGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
928 BlitBitmap(src_bitmap, d, src_x, src_y, MINI_TILEX, MINI_TILEY, x, y);
931 void DrawGraphicShifted(int x,int y, int dx,int dy, int graphic, int frame,
932 int cut_mode, int mask_mode)
937 int width = TILEX, height = TILEY;
943 DrawGraphic(x, y, graphic, frame);
947 if (dx || dy) /* shifted graphic */
949 if (x < BX1) /* object enters playfield from the left */
956 else if (x > BX2) /* object enters playfield from the right */
962 else if (x==BX1 && dx < 0) /* object leaves playfield to the left */
968 else if (x==BX2 && dx > 0) /* object leaves playfield to the right */
970 else if (dx) /* general horizontal movement */
971 MarkTileDirty(x + SIGN(dx), y);
973 if (y < BY1) /* object enters playfield from the top */
975 if (cut_mode==CUT_BELOW) /* object completely above top border */
983 else if (y > BY2) /* object enters playfield from the bottom */
989 else if (y==BY1 && dy < 0) /* object leaves playfield to the top */
995 else if (dy > 0 && cut_mode == CUT_ABOVE)
997 if (y == BY2) /* object completely above bottom border */
1003 MarkTileDirty(x, y + 1);
1004 } /* object leaves playfield to the bottom */
1005 else if (dy > 0 && (y == BY2 || cut_mode == CUT_BELOW))
1007 else if (dy) /* general vertical movement */
1008 MarkTileDirty(x, y + SIGN(dy));
1012 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1014 src_bitmap = graphic_info[graphic].bitmap;
1015 src_x = graphic_info[graphic].src_x;
1016 src_y = graphic_info[graphic].src_y;
1017 offset_x = graphic_info[graphic].offset_x;
1018 offset_y = graphic_info[graphic].offset_y;
1020 src_x += frame * offset_x;
1021 src_y += frame * offset_y;
1024 drawing_gc = src_bitmap->stored_clip_gc;
1029 dest_x = FX + x * TILEX + dx;
1030 dest_y = FY + y * TILEY + dy;
1033 if (!IN_SCR_FIELD(x,y))
1035 printf("DrawGraphicShifted(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
1036 printf("DrawGraphicShifted(): This should never happen!\n");
1041 if (mask_mode == USE_MASKING)
1043 SetClipOrigin(src_bitmap, drawing_gc, dest_x - src_x, dest_y - src_y);
1044 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1048 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1054 void DrawGraphicShiftedThruMask(int x, int y, int dx, int dy, int graphic,
1055 int frame, int cut_mode)
1057 DrawGraphicShifted(x,y, dx,dy, graphic, frame, cut_mode, USE_MASKING);
1060 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
1061 int cut_mode, int mask_mode)
1063 int lx = LEVELX(x), ly = LEVELY(y);
1067 if (IN_LEV_FIELD(lx, ly))
1069 SetRandomAnimationValue(lx, ly);
1071 graphic = el_act_dir2img(element, GfxAction[lx][ly], MovDir[lx][ly]);
1072 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1074 else /* border element */
1076 graphic = el2img(element);
1077 frame = getGraphicAnimationFrame(graphic, -1);
1080 if (element == EL_EXPANDABLE_WALL)
1082 boolean left_stopped = FALSE, right_stopped = FALSE;
1084 if (!IN_LEV_FIELD(lx - 1, ly) || IS_WALL(Feld[lx - 1][ly]))
1085 left_stopped = TRUE;
1086 if (!IN_LEV_FIELD(lx + 1, ly) || IS_WALL(Feld[lx + 1][ly]))
1087 right_stopped = TRUE;
1089 if (left_stopped && right_stopped)
1091 else if (left_stopped)
1093 graphic = IMG_EXPANDABLE_WALL_GROWING_RIGHT;
1094 frame = graphic_info[graphic].anim_frames - 1;
1096 else if (right_stopped)
1098 graphic = IMG_EXPANDABLE_WALL_GROWING_LEFT;
1099 frame = graphic_info[graphic].anim_frames - 1;
1104 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, mask_mode);
1105 else if (mask_mode == USE_MASKING)
1106 DrawGraphicThruMask(x, y, graphic, frame);
1108 DrawGraphic(x, y, graphic, frame);
1111 void DrawLevelElementExt(int x, int y, int dx, int dy, int element,
1112 int cut_mode, int mask_mode)
1114 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1115 DrawScreenElementExt(SCREENX(x), SCREENY(y), dx, dy, element,
1116 cut_mode, mask_mode);
1119 void DrawScreenElementShifted(int x, int y, int dx, int dy, int element,
1122 DrawScreenElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1125 void DrawLevelElementShifted(int x, int y, int dx, int dy, int element,
1128 DrawLevelElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1131 void DrawLevelElementThruMask(int x, int y, int element)
1133 DrawLevelElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1136 void DrawLevelFieldThruMask(int x, int y)
1138 DrawLevelElementExt(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
1141 static void DrawLevelFieldCrumbledSandExt(int x, int y, int graphic, int frame)
1145 int sx = SCREENX(x), sy = SCREENY(y);
1147 int width, height, cx, cy, i;
1149 int crumbled_border_size = graphic_info[graphic].border_size;
1151 int snip = TILEX / 8; /* number of border pixels from "crumbled graphic" */
1153 static int xy[4][2] =
1162 if (x == 0 && y == 7)
1163 printf("::: %d, %d [%d]\n", GfxElement[x][y], Feld[x][y],
1164 crumbled_border_size);
1167 if (!IN_LEV_FIELD(x, y))
1170 element = (GfxElement[x][y] != EL_UNDEFINED && Feld[x][y] != EL_EXPLOSION ?
1171 GfxElement[x][y] : Feld[x][y]);
1173 /* crumble field itself */
1174 if (GFX_CRUMBLED(element) && !IS_MOVING(x, y))
1176 if (!IN_SCR_FIELD(sx, sy))
1179 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1183 int xx = x + xy[i][0];
1184 int yy = y + xy[i][1];
1186 element = (IN_LEV_FIELD(xx, yy) ? Feld[xx][yy] : BorderElement);
1188 /* check if neighbour field is of same type */
1189 if (GFX_CRUMBLED(element) && !IS_MOVING(xx, yy))
1193 if (Feld[x][y] == EL_CUSTOM_START + 123)
1194 printf("::: crumble [%d] THE CHAOS ENGINE (%d, %d): %d, %d\n",
1195 i, Feld[x][y], element,
1196 GFX_CRUMBLED(element), IS_MOVING(x, y));
1199 if (i == 1 || i == 2)
1201 width = crumbled_border_size;
1203 cx = (i == 2 ? TILEX - crumbled_border_size : 0);
1209 height = crumbled_border_size;
1211 cy = (i == 3 ? TILEY - crumbled_border_size : 0);
1214 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1215 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
1218 MarkTileDirty(sx, sy);
1220 else /* crumble neighbour fields */
1223 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1228 int xx = x + xy[i][0];
1229 int yy = y + xy[i][1];
1230 int sxx = sx + xy[i][0];
1231 int syy = sy + xy[i][1];
1233 if (!IN_LEV_FIELD(xx, yy) ||
1234 !IN_SCR_FIELD(sxx, syy) ||
1235 !GFX_CRUMBLED(Feld[xx][yy]) ||
1240 graphic = el_act2crm(Feld[xx][yy], ACTION_DEFAULT);
1241 crumbled_border_size = graphic_info[graphic].border_size;
1243 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1246 if (i == 1 || i == 2)
1248 width = crumbled_border_size;
1250 cx = (i == 1 ? TILEX - crumbled_border_size : 0);
1256 height = crumbled_border_size;
1258 cy = (i == 0 ? TILEY - crumbled_border_size : 0);
1261 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1262 width, height, FX + sxx * TILEX + cx, FY + syy * TILEY + cy);
1264 MarkTileDirty(sxx, syy);
1269 void DrawLevelFieldCrumbledSand(int x, int y)
1274 if (!IN_LEV_FIELD(x, y))
1277 graphic = el_act2crm(Feld[x][y], ACTION_DEFAULT);
1279 DrawLevelFieldCrumbledSandExt(x, y, graphic, 0);
1281 DrawLevelFieldCrumbledSandExt(x, y, IMG_SAND_CRUMBLED, 0);
1285 void DrawLevelFieldCrumbledSandDigging(int x, int y, int direction,
1289 int graphic1 = el_act_dir2img(GfxElement[x][y], ACTION_DIGGING, direction);
1290 int graphic2 = el_act_dir2crm(GfxElement[x][y], ACTION_DIGGING, direction);
1292 int graphic1 = el_act_dir2img(EL_SAND, ACTION_DIGGING, direction);
1293 int graphic2 = el_act_dir2img(EL_SAND_CRUMBLED, ACTION_DIGGING, direction);
1295 int frame1 = getGraphicAnimationFrame(graphic1, step_frame);
1296 int frame2 = getGraphicAnimationFrame(graphic2, step_frame);
1297 int sx = SCREENX(x), sy = SCREENY(y);
1299 DrawGraphic(sx, sy, graphic1, frame1);
1300 DrawLevelFieldCrumbledSandExt(x, y, graphic2, frame2);
1303 void DrawLevelFieldCrumbledSandNeighbours(int x, int y)
1305 int sx = SCREENX(x), sy = SCREENY(y);
1306 static int xy[4][2] =
1317 int xx = x + xy[i][0];
1318 int yy = y + xy[i][1];
1319 int sxx = sx + xy[i][0];
1320 int syy = sy + xy[i][1];
1322 if (!IN_LEV_FIELD(xx, yy) ||
1323 !IN_SCR_FIELD(sxx, syy) ||
1324 !GFX_CRUMBLED(Feld[xx][yy]) ||
1328 DrawLevelField(xx, yy);
1332 static int getBorderElement(int x, int y)
1336 { EL_STEELWALL_TOPLEFT, EL_INVISIBLE_STEELWALL_TOPLEFT },
1337 { EL_STEELWALL_TOPRIGHT, EL_INVISIBLE_STEELWALL_TOPRIGHT },
1338 { EL_STEELWALL_BOTTOMLEFT, EL_INVISIBLE_STEELWALL_BOTTOMLEFT },
1339 { EL_STEELWALL_BOTTOMRIGHT, EL_INVISIBLE_STEELWALL_BOTTOMRIGHT },
1340 { EL_STEELWALL_VERTICAL, EL_INVISIBLE_STEELWALL_VERTICAL },
1341 { EL_STEELWALL_HORIZONTAL, EL_INVISIBLE_STEELWALL_HORIZONTAL },
1342 { EL_STEELWALL, EL_INVISIBLE_STEELWALL }
1344 int steel_type = (BorderElement == EL_STEELWALL ? 0 : 1);
1345 int steel_position = (x == -1 && y == -1 ? 0 :
1346 x == lev_fieldx && y == -1 ? 1 :
1347 x == -1 && y == lev_fieldy ? 2 :
1348 x == lev_fieldx && y == lev_fieldy ? 3 :
1349 x == -1 || x == lev_fieldx ? 4 :
1350 y == -1 || y == lev_fieldy ? 5 : 6);
1352 return border[steel_position][steel_type];
1355 void DrawScreenElement(int x, int y, int element)
1357 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
1358 DrawLevelFieldCrumbledSand(LEVELX(x), LEVELY(y));
1361 void DrawLevelElement(int x, int y, int element)
1363 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1364 DrawScreenElement(SCREENX(x), SCREENY(y), element);
1367 void DrawScreenField(int x, int y)
1369 int lx = LEVELX(x), ly = LEVELY(y);
1370 int element, content;
1372 if (!IN_LEV_FIELD(lx, ly))
1374 if (lx < -1 || lx > lev_fieldx || ly < -1 || ly > lev_fieldy)
1377 element = getBorderElement(lx, ly);
1379 DrawScreenElement(x, y, element);
1383 element = Feld[lx][ly];
1384 content = Store[lx][ly];
1386 if (IS_MOVING(lx, ly))
1388 int horiz_move = (MovDir[lx][ly] == MV_LEFT || MovDir[lx][ly] == MV_RIGHT);
1389 boolean cut_mode = NO_CUTTING;
1391 if (element == EL_QUICKSAND_EMPTYING ||
1392 element == EL_MAGIC_WALL_EMPTYING ||
1393 element == EL_BD_MAGIC_WALL_EMPTYING ||
1394 element == EL_AMOEBA_DROPPING)
1395 cut_mode = CUT_ABOVE;
1396 else if (element == EL_QUICKSAND_FILLING ||
1397 element == EL_MAGIC_WALL_FILLING ||
1398 element == EL_BD_MAGIC_WALL_FILLING)
1399 cut_mode = CUT_BELOW;
1401 if (cut_mode == CUT_ABOVE)
1402 DrawScreenElementShifted(x, y, 0, 0, element, NO_CUTTING);
1404 DrawScreenElement(x, y, EL_EMPTY);
1407 DrawScreenElementShifted(x, y, MovPos[lx][ly], 0, element, NO_CUTTING);
1408 else if (cut_mode == NO_CUTTING)
1409 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], element, cut_mode);
1411 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], content, cut_mode);
1413 if (content == EL_ACID)
1414 DrawLevelElementThruMask(lx, ly + 1, EL_ACID);
1416 else if (IS_BLOCKED(lx, ly))
1421 boolean cut_mode = NO_CUTTING;
1422 int element_old, content_old;
1424 Blocked2Moving(lx, ly, &oldx, &oldy);
1427 horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
1428 MovDir[oldx][oldy] == MV_RIGHT);
1430 element_old = Feld[oldx][oldy];
1431 content_old = Store[oldx][oldy];
1433 if (element_old == EL_QUICKSAND_EMPTYING ||
1434 element_old == EL_MAGIC_WALL_EMPTYING ||
1435 element_old == EL_BD_MAGIC_WALL_EMPTYING ||
1436 element_old == EL_AMOEBA_DROPPING)
1437 cut_mode = CUT_ABOVE;
1439 DrawScreenElement(x, y, EL_EMPTY);
1442 DrawScreenElementShifted(sx, sy, MovPos[oldx][oldy], 0, element_old,
1444 else if (cut_mode == NO_CUTTING)
1445 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], element_old,
1448 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], content_old,
1451 else if (IS_DRAWABLE(element))
1452 DrawScreenElement(x, y, element);
1454 DrawScreenElement(x, y, EL_EMPTY);
1457 void DrawLevelField(int x, int y)
1459 if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1460 DrawScreenField(SCREENX(x), SCREENY(y));
1461 else if (IS_MOVING(x, y))
1465 Moving2Blocked(x, y, &newx, &newy);
1466 if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
1467 DrawScreenField(SCREENX(newx), SCREENY(newy));
1469 else if (IS_BLOCKED(x, y))
1473 Blocked2Moving(x, y, &oldx, &oldy);
1474 if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
1475 DrawScreenField(SCREENX(oldx), SCREENY(oldy));
1479 void DrawMiniElement(int x, int y, int element)
1483 graphic = el2edimg(element);
1484 DrawMiniGraphic(x, y, graphic);
1487 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
1489 int x = sx + scroll_x, y = sy + scroll_y;
1491 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
1492 DrawMiniElement(sx, sy, EL_EMPTY);
1493 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
1494 DrawMiniElement(sx, sy, Feld[x][y]);
1496 DrawMiniGraphic(sx, sy, el2edimg(getBorderElement(x, y)));
1499 void DrawEnvelopeBackground(int envelope_nr, int startx, int starty,
1500 int x, int y, int xsize, int ysize, int font_nr)
1502 int font_width = getFontWidth(font_nr);
1503 int font_height = getFontHeight(font_nr);
1504 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1507 int dst_x = SX + startx + x * font_width;
1508 int dst_y = SY + starty + y * font_height;
1509 int width = graphic_info[graphic].width;
1510 int height = graphic_info[graphic].height;
1511 int inner_width = MAX(width - 2 * font_width, font_width);
1512 int inner_height = MAX(height - 2 * font_height, font_height);
1513 int inner_sx = (width >= 3 * font_width ? font_width : 0);
1514 int inner_sy = (height >= 3 * font_height ? font_height : 0);
1515 boolean draw_masked = graphic_info[graphic].draw_masked;
1517 getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
1519 if (src_bitmap == NULL || width < font_width || height < font_height)
1521 ClearRectangle(drawto, dst_x, dst_y, font_width, font_height);
1525 src_x += (x == 0 ? 0 : x == xsize - 1 ? width - font_width :
1526 inner_sx + (x - 1) * font_width % inner_width);
1527 src_y += (y == 0 ? 0 : y == ysize - 1 ? height - font_height :
1528 inner_sy + (y - 1) * font_height % inner_height);
1532 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1533 dst_x - src_x, dst_y - src_y);
1534 BlitBitmapMasked(src_bitmap, drawto, src_x, src_y, font_width, font_height,
1538 BlitBitmap(src_bitmap, drawto, src_x, src_y, font_width, font_height,
1542 void AnimateEnvelope(int envelope_nr, int anim_mode, int action)
1544 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1545 boolean draw_masked = graphic_info[graphic].draw_masked;
1546 int mask_mode = (draw_masked ? BLIT_MASKED : BLIT_ON_BACKGROUND);
1547 boolean ffwd_delay = (tape.playing && tape.fast_forward);
1548 unsigned long anim_delay = 0;
1549 int anim_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
1550 int font_nr = FONT_ENVELOPE_1 + envelope_nr;
1551 int font_width = getFontWidth(font_nr);
1552 int font_height = getFontHeight(font_nr);
1553 int max_xsize = level.envelope_xsize[envelope_nr];
1554 int max_ysize = level.envelope_ysize[envelope_nr];
1555 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize : 0);
1556 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize : 0);
1557 int xend = max_xsize;
1558 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize : 0);
1559 int xstep = (xstart < xend ? 1 : 0);
1560 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
1563 for (x=xstart, y=ystart; x <= xend && y <= yend; x += xstep, y += ystep)
1565 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
1566 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
1567 int sx = (SXSIZE - xsize * font_width) / 2;
1568 int sy = (SYSIZE - ysize * font_height) / 2;
1571 SetDrawtoField(DRAW_BUFFERED);
1573 BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
1575 SetDrawtoField(DRAW_BACKBUFFER);
1577 for (yy=0; yy < ysize; yy++) for (xx=0; xx < xsize; xx++)
1578 DrawEnvelopeBackground(envelope_nr, sx,sy, xx,yy, xsize, ysize, font_nr);
1580 DrawTextToTextArea(SX + sx + font_width, SY + sy + font_height,
1581 level.envelope_text[envelope_nr], font_nr, max_xsize,
1582 xsize - 2, ysize - 2, mask_mode);
1584 redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
1587 WaitUntilDelayReached(&anim_delay, anim_delay_value / 2);
1591 void ShowEnvelope(int envelope_nr)
1593 int element = EL_ENVELOPE_1 + envelope_nr;
1594 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1595 int sound_opening = element_info[element].sound[ACTION_OPENING];
1596 int sound_closing = element_info[element].sound[ACTION_CLOSING];
1597 boolean ffwd_delay = (tape.playing && tape.fast_forward);
1598 int wait_delay_value = (ffwd_delay ? 500 : 1000);
1599 int anim_mode = graphic_info[graphic].anim_mode;
1600 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
1601 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
1603 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
1605 PlaySoundStereo(sound_opening, SOUND_MIDDLE);
1607 if (anim_mode == ANIM_DEFAULT)
1608 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_OPENING);
1610 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_OPENING);
1613 Delay(wait_delay_value);
1615 WaitForEventToContinue();
1617 PlaySoundStereo(sound_closing, SOUND_MIDDLE);
1619 if (anim_mode != ANIM_NONE)
1620 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_CLOSING);
1622 if (anim_mode == ANIM_DEFAULT)
1623 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_CLOSING);
1625 game.envelope_active = FALSE;
1627 SetDrawtoField(DRAW_BUFFERED);
1629 redraw_mask |= REDRAW_FIELD;
1633 void getMicroGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
1635 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
1636 int mini_startx = src_bitmap->width * 3 / 4;
1637 int mini_starty = src_bitmap->height * 2 / 3;
1638 int src_x = mini_startx + graphic_info[graphic].src_x / 8;
1639 int src_y = mini_starty + graphic_info[graphic].src_y / 8;
1641 *bitmap = src_bitmap;
1646 void DrawMicroElement(int xpos, int ypos, int element)
1650 int graphic = el2preimg(element);
1652 getMicroGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
1653 BlitBitmap(src_bitmap, drawto, src_x, src_y, MICRO_TILEX, MICRO_TILEY,
1661 SetDrawBackgroundMask(REDRAW_NONE);
1664 for(x=BX1; x<=BX2; x++)
1665 for(y=BY1; y<=BY2; y++)
1666 DrawScreenField(x, y);
1668 redraw_mask |= REDRAW_FIELD;
1671 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
1675 for(x=0; x<size_x; x++)
1676 for(y=0; y<size_y; y++)
1677 DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
1679 redraw_mask |= REDRAW_FIELD;
1682 static void DrawMicroLevelExt(int xpos, int ypos, int from_x, int from_y)
1686 DrawBackground(xpos, ypos, MICROLEV_XSIZE, MICROLEV_YSIZE);
1688 if (lev_fieldx < STD_LEV_FIELDX)
1689 xpos += (STD_LEV_FIELDX - lev_fieldx) / 2 * MICRO_TILEX;
1690 if (lev_fieldy < STD_LEV_FIELDY)
1691 ypos += (STD_LEV_FIELDY - lev_fieldy) / 2 * MICRO_TILEY;
1693 xpos += MICRO_TILEX;
1694 ypos += MICRO_TILEY;
1696 for(x=-1; x<=STD_LEV_FIELDX; x++)
1698 for(y=-1; y<=STD_LEV_FIELDY; y++)
1700 int lx = from_x + x, ly = from_y + y;
1702 if (lx >= 0 && lx < lev_fieldx && ly >= 0 && ly < lev_fieldy)
1703 DrawMicroElement(xpos + x * MICRO_TILEX, ypos + y * MICRO_TILEY,
1704 level.field[lx][ly]);
1705 else if (lx >= -1 && lx < lev_fieldx+1 && ly >= -1 && ly < lev_fieldy+1
1706 && BorderElement != EL_EMPTY)
1707 DrawMicroElement(xpos + x * MICRO_TILEX, ypos + y * MICRO_TILEY,
1708 getBorderElement(lx, ly));
1712 redraw_mask |= REDRAW_MICROLEVEL;
1715 #define MICROLABEL_EMPTY 0
1716 #define MICROLABEL_LEVEL_NAME 1
1717 #define MICROLABEL_CREATED_BY 2
1718 #define MICROLABEL_LEVEL_AUTHOR 3
1719 #define MICROLABEL_IMPORTED_FROM 4
1720 #define MICROLABEL_LEVEL_IMPORT_INFO 5
1722 static void DrawMicroLevelLabelExt(int mode)
1724 char label_text[MAX_OUTPUT_LINESIZE + 1];
1725 int max_len_label_text;
1726 int font_nr = FONT_TEXT_2;
1728 if (mode == MICROLABEL_CREATED_BY || mode == MICROLABEL_IMPORTED_FROM)
1729 font_nr = FONT_TEXT_3;
1731 max_len_label_text = SXSIZE / getFontWidth(font_nr);
1733 DrawBackground(SX, MICROLABEL_YPOS, SXSIZE, getFontHeight(font_nr));
1735 strncpy(label_text, (mode == MICROLABEL_LEVEL_NAME ? level.name :
1736 mode == MICROLABEL_CREATED_BY ? "created by" :
1737 mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
1738 mode == MICROLABEL_IMPORTED_FROM ? "imported from" :
1739 mode == MICROLABEL_LEVEL_IMPORT_INFO ?
1740 leveldir_current->imported_from : ""),
1741 max_len_label_text);
1742 label_text[max_len_label_text] = '\0';
1744 if (strlen(label_text) > 0)
1746 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
1747 int lypos = MICROLABEL_YPOS;
1749 DrawText(lxpos, lypos, label_text, font_nr);
1752 redraw_mask |= REDRAW_MICROLEVEL;
1755 void DrawMicroLevel(int xpos, int ypos, boolean restart)
1757 static unsigned long scroll_delay = 0;
1758 static unsigned long label_delay = 0;
1759 static int from_x, from_y, scroll_direction;
1760 static int label_state, label_counter;
1761 int last_game_status = game_status; /* save current game status */
1763 /* force PREVIEW font on preview level */
1764 game_status = GAME_MODE_PSEUDO_PREVIEW;
1768 from_x = from_y = 0;
1769 scroll_direction = MV_RIGHT;
1773 DrawMicroLevelExt(xpos, ypos, from_x, from_y);
1774 DrawMicroLevelLabelExt(label_state);
1776 /* initialize delay counters */
1777 DelayReached(&scroll_delay, 0);
1778 DelayReached(&label_delay, 0);
1780 if (leveldir_current->name)
1782 int text_width = getTextWidth(leveldir_current->name, FONT_TEXT_1);
1783 int lxpos = SX + (SXSIZE - text_width) / 2;
1784 int lypos = SY + 352;
1786 DrawText(lxpos, lypos, leveldir_current->name, FONT_TEXT_1);
1789 game_status = last_game_status; /* restore current game status */
1794 /* scroll micro level, if needed */
1795 if ((lev_fieldx > STD_LEV_FIELDX || lev_fieldy > STD_LEV_FIELDY) &&
1796 DelayReached(&scroll_delay, MICROLEVEL_SCROLL_DELAY))
1798 switch (scroll_direction)
1804 scroll_direction = MV_UP;
1808 if (from_x < lev_fieldx - STD_LEV_FIELDX)
1811 scroll_direction = MV_DOWN;
1818 scroll_direction = MV_RIGHT;
1822 if (from_y < lev_fieldy - STD_LEV_FIELDY)
1825 scroll_direction = MV_LEFT;
1832 DrawMicroLevelExt(xpos, ypos, from_x, from_y);
1835 /* redraw micro level label, if needed */
1836 if (strcmp(level.name, NAMELESS_LEVEL_NAME) != 0 &&
1837 strcmp(level.author, ANONYMOUS_NAME) != 0 &&
1838 strcmp(level.author, leveldir_current->name) != 0 &&
1839 DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
1841 int max_label_counter = 23;
1843 if (leveldir_current->imported_from != NULL)
1844 max_label_counter += 14;
1846 label_counter = (label_counter + 1) % max_label_counter;
1847 label_state = (label_counter >= 0 && label_counter <= 7 ?
1848 MICROLABEL_LEVEL_NAME :
1849 label_counter >= 9 && label_counter <= 12 ?
1850 MICROLABEL_CREATED_BY :
1851 label_counter >= 14 && label_counter <= 21 ?
1852 MICROLABEL_LEVEL_AUTHOR :
1853 label_counter >= 23 && label_counter <= 26 ?
1854 MICROLABEL_IMPORTED_FROM :
1855 label_counter >= 28 && label_counter <= 35 ?
1856 MICROLABEL_LEVEL_IMPORT_INFO : MICROLABEL_EMPTY);
1857 DrawMicroLevelLabelExt(label_state);
1860 game_status = last_game_status; /* restore current game status */
1863 void WaitForEventToContinue()
1865 boolean still_wait = TRUE;
1867 /* simulate releasing mouse button over last gadget, if still pressed */
1869 HandleGadgets(-1, -1, 0);
1871 button_status = MB_RELEASED;
1883 case EVENT_BUTTONPRESS:
1884 case EVENT_KEYPRESS:
1888 case EVENT_KEYRELEASE:
1889 ClearPlayerAction();
1893 HandleOtherEvents(&event);
1897 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
1904 /* don't eat all CPU time */
1909 #define MAX_REQUEST_LINES 13
1910 #define MAX_REQUEST_LINE_LEN 7
1912 boolean Request(char *text, unsigned int req_state)
1914 int mx, my, ty, result = -1;
1915 unsigned int old_door_state;
1916 int last_game_status = game_status; /* save current game status */
1919 SetMouseCursor(CURSOR_DEFAULT);
1922 #if defined(PLATFORM_UNIX)
1923 /* pause network game while waiting for request to answer */
1924 if (options.network &&
1925 game_status == GAME_MODE_PLAYING &&
1926 req_state & REQUEST_WAIT_FOR)
1927 SendToServer_PausePlaying();
1930 old_door_state = GetDoorState();
1932 /* simulate releasing mouse button over last gadget, if still pressed */
1934 HandleGadgets(-1, -1, 0);
1938 CloseDoor(DOOR_CLOSE_1);
1940 /* save old door content */
1941 BlitBitmap(bitmap_db_door, bitmap_db_door,
1942 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
1943 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
1945 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
1947 /* clear door drawing field */
1948 DrawBackground(DX, DY, DXSIZE, DYSIZE);
1950 /* force DOOR font on preview level */
1951 game_status = GAME_MODE_PSEUDO_DOOR;
1953 /* write text for request */
1954 for(ty=0; ty < MAX_REQUEST_LINES; ty++)
1956 char text_line[MAX_REQUEST_LINE_LEN + 1];
1962 for(tl=0,tx=0; tx < MAX_REQUEST_LINE_LEN; tl++,tx++)
1965 if (!tc || tc == ' ')
1976 strncpy(text_line, text, tl);
1979 DrawText(DX + (DXSIZE - tl * getFontWidth(FONT_TEXT_2)) / 2,
1980 DY + 8 + ty * (getFontHeight(FONT_TEXT_2) + 2),
1981 text_line, FONT_TEXT_2);
1983 text += tl + (tc == ' ' ? 1 : 0);
1986 game_status = last_game_status; /* restore current game status */
1988 if (req_state & REQ_ASK)
1990 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
1991 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
1993 else if (req_state & REQ_CONFIRM)
1995 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
1997 else if (req_state & REQ_PLAYER)
1999 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
2000 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
2001 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
2002 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
2005 /* copy request gadgets to door backbuffer */
2006 BlitBitmap(drawto, bitmap_db_door,
2007 DX, DY, DXSIZE, DYSIZE,
2008 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2010 OpenDoor(DOOR_OPEN_1);
2016 if (!(req_state & REQUEST_WAIT_FOR))
2018 SetDrawBackgroundMask(REDRAW_FIELD);
2023 if (game_status != GAME_MODE_MAIN)
2026 button_status = MB_RELEASED;
2028 request_gadget_id = -1;
2030 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
2033 SetMouseCursor(CURSOR_DEFAULT);
2046 case EVENT_BUTTONPRESS:
2047 case EVENT_BUTTONRELEASE:
2048 case EVENT_MOTIONNOTIFY:
2050 if (event.type == EVENT_MOTIONNOTIFY)
2052 if (!PointerInWindow(window))
2053 continue; /* window and pointer are on different screens */
2058 motion_status = TRUE;
2059 mx = ((MotionEvent *) &event)->x;
2060 my = ((MotionEvent *) &event)->y;
2064 motion_status = FALSE;
2065 mx = ((ButtonEvent *) &event)->x;
2066 my = ((ButtonEvent *) &event)->y;
2067 if (event.type == EVENT_BUTTONPRESS)
2068 button_status = ((ButtonEvent *) &event)->button;
2070 button_status = MB_RELEASED;
2073 /* this sets 'request_gadget_id' */
2074 HandleGadgets(mx, my, button_status);
2076 switch(request_gadget_id)
2078 case TOOL_CTRL_ID_YES:
2081 case TOOL_CTRL_ID_NO:
2084 case TOOL_CTRL_ID_CONFIRM:
2085 result = TRUE | FALSE;
2088 case TOOL_CTRL_ID_PLAYER_1:
2091 case TOOL_CTRL_ID_PLAYER_2:
2094 case TOOL_CTRL_ID_PLAYER_3:
2097 case TOOL_CTRL_ID_PLAYER_4:
2108 case EVENT_KEYPRESS:
2109 switch(GetEventKey((KeyEvent *)&event, TRUE))
2122 if (req_state & REQ_PLAYER)
2126 case EVENT_KEYRELEASE:
2127 ClearPlayerAction();
2131 HandleOtherEvents(&event);
2135 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
2137 int joy = AnyJoystick();
2139 if (joy & JOY_BUTTON_1)
2141 else if (joy & JOY_BUTTON_2)
2147 /* don't eat all CPU time */
2151 if (game_status != GAME_MODE_MAIN)
2156 if (!(req_state & REQ_STAY_OPEN))
2158 CloseDoor(DOOR_CLOSE_1);
2160 if (!(req_state & REQ_STAY_CLOSED) && (old_door_state & DOOR_OPEN_1))
2162 BlitBitmap(bitmap_db_door, bitmap_db_door,
2163 DOOR_GFX_PAGEX2,DOOR_GFX_PAGEY1, DXSIZE,DYSIZE,
2164 DOOR_GFX_PAGEX1,DOOR_GFX_PAGEY1);
2165 OpenDoor(DOOR_OPEN_1);
2171 SetDrawBackgroundMask(REDRAW_FIELD);
2173 #if defined(PLATFORM_UNIX)
2174 /* continue network game after request */
2175 if (options.network &&
2176 game_status == GAME_MODE_PLAYING &&
2177 req_state & REQUEST_WAIT_FOR)
2178 SendToServer_ContinuePlaying();
2184 unsigned int OpenDoor(unsigned int door_state)
2186 unsigned int new_door_state;
2188 if (door_state & DOOR_COPY_BACK)
2190 BlitBitmap(bitmap_db_door, bitmap_db_door,
2191 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE + VYSIZE,
2192 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2193 door_state &= ~DOOR_COPY_BACK;
2196 new_door_state = MoveDoor(door_state);
2198 return(new_door_state);
2201 unsigned int CloseDoor(unsigned int door_state)
2203 unsigned int new_door_state;
2205 BlitBitmap(backbuffer, bitmap_db_door,
2206 DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2207 BlitBitmap(backbuffer, bitmap_db_door,
2208 VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
2210 new_door_state = MoveDoor(door_state);
2212 return(new_door_state);
2215 unsigned int GetDoorState()
2217 return MoveDoor(DOOR_GET_STATE);
2220 unsigned int SetDoorState(unsigned int door_state)
2222 return MoveDoor(door_state | DOOR_SET_STATE);
2225 unsigned int MoveDoor(unsigned int door_state)
2227 static int door1 = DOOR_OPEN_1;
2228 static int door2 = DOOR_CLOSE_2;
2229 unsigned long door_delay = 0;
2230 unsigned long door_delay_value;
2233 if (door_state == DOOR_GET_STATE)
2234 return(door1 | door2);
2236 if (door_state & DOOR_SET_STATE)
2238 if (door_state & DOOR_ACTION_1)
2239 door1 = door_state & DOOR_ACTION_1;
2240 if (door_state & DOOR_ACTION_2)
2241 door2 = door_state & DOOR_ACTION_2;
2243 return(door1 | door2);
2246 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
2247 door_state &= ~DOOR_OPEN_1;
2248 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
2249 door_state &= ~DOOR_CLOSE_1;
2250 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
2251 door_state &= ~DOOR_OPEN_2;
2252 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
2253 door_state &= ~DOOR_CLOSE_2;
2255 door_delay_value = (door_state & DOOR_ACTION_1 ? door_1.step_delay :
2258 if (setup.quick_doors)
2260 stepsize = 20; /* must be choosen to always draw last frame */
2261 door_delay_value = 0;
2263 StopSound(SND_DOOR_OPENING);
2264 StopSound(SND_DOOR_CLOSING);
2267 if (global.autoplay_leveldir)
2269 door_state |= DOOR_NO_DELAY;
2270 door_state &= ~DOOR_CLOSE_ALL;
2273 if (door_state & DOOR_ACTION)
2275 boolean door_1_done = !(door_state & DOOR_ACTION_1);
2276 boolean door_2_done = !(door_state & DOOR_ACTION_2);
2277 int start = ((door_state & DOOR_NO_DELAY) ? DXSIZE : 0);
2278 int end = (door_state & DOOR_ACTION_1 &&
2279 door_1.anim_mode == ANIM_VERTICAL ? DYSIZE : DXSIZE);
2282 if (!(door_state & DOOR_NO_DELAY))
2284 /* opening door sound has priority over simultaneously closing door */
2285 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
2286 PlaySoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
2287 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
2288 PlaySoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
2291 for(x = start; x <= end && !(door_1_done && door_2_done); x += stepsize)
2293 Bitmap *bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
2294 GC gc = bitmap->stored_clip_gc;
2296 if (door_state & DOOR_ACTION_1)
2298 int a = MIN(x * door_1.step_offset, end);
2299 int i = (door_state & DOOR_OPEN_1 ? end - a : a);
2303 BlitBitmap(bitmap_db_door, drawto,
2304 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + i / 2,
2305 DXSIZE,DYSIZE - i / 2, DX, DY);
2307 ClearRectangle(drawto, DX, DY + DYSIZE - i / 2, DXSIZE, i / 2);
2310 if (door_1.anim_mode == ANIM_HORIZONTAL && x <= DXSIZE)
2312 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
2313 int dst1_x = DX + DXSIZE - i, dst1_y = DY;
2314 int src2_x = DXSIZE - i, src2_y = DOOR_GFX_PAGEY1;
2315 int dst2_x = DX, dst2_y = DY;
2316 int width = i, height = DYSIZE;
2318 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2319 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2322 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2323 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2326 else if (door_1.anim_mode == ANIM_VERTICAL && x <= DYSIZE)
2328 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
2329 int dst1_x = DX, dst1_y = DY + DYSIZE - i;
2330 int src2_x = 0, src2_y = DOOR_GFX_PAGEY1 + DYSIZE - i;
2331 int dst2_x = DX, dst2_y = DY;
2332 int width = DXSIZE, height = i;
2334 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2335 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2338 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2339 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2342 else if (x <= DXSIZE) /* ANIM_DEFAULT */
2344 int j = (door_1.anim_mode == ANIM_DEFAULT ? (DXSIZE - i) / 3 : 0);
2346 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2347 BlitBitmapMasked(bitmap, drawto,
2348 DXSIZE, DOOR_GFX_PAGEY1, i, 77,
2349 DX + DXSIZE - i, DY + j);
2350 BlitBitmapMasked(bitmap, drawto,
2351 DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63,
2352 DX + DXSIZE - i, DY + 140 + j);
2353 SetClipOrigin(bitmap, gc, DX - DXSIZE + i,
2354 DY - (DOOR_GFX_PAGEY1 + j));
2355 BlitBitmapMasked(bitmap, drawto,
2356 DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j,
2358 BlitBitmapMasked(bitmap, drawto,
2359 DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63,
2362 BlitBitmapMasked(bitmap, drawto,
2363 DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
2365 BlitBitmapMasked(bitmap, drawto,
2366 DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
2368 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2369 BlitBitmapMasked(bitmap, drawto,
2370 DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
2371 DX + DXSIZE - i, DY + 77 + j);
2372 BlitBitmapMasked(bitmap, drawto,
2373 DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
2374 DX + DXSIZE - i, DY + 203 + j);
2377 redraw_mask |= REDRAW_DOOR_1;
2378 door_1_done = (a == end);
2381 if (door_state & DOOR_ACTION_2)
2383 int a = MIN(x * door_2.step_offset, VXSIZE);
2384 int i = (door_state & DOOR_OPEN_2 ? VXSIZE - a : a);
2388 BlitBitmap(bitmap_db_door, drawto,
2389 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + i / 2,
2390 VXSIZE, VYSIZE - i / 2, VX, VY);
2392 ClearRectangle(drawto, VX, VY + VYSIZE - i / 2, VXSIZE, i / 2);
2395 if (door_2.anim_mode == ANIM_HORIZONTAL && x <= VXSIZE)
2397 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
2398 int dst1_x = VX + VXSIZE - i, dst1_y = VY;
2399 int src2_x = VXSIZE - i, src2_y = DOOR_GFX_PAGEY2;
2400 int dst2_x = VX, dst2_y = VY;
2401 int width = i, height = VYSIZE;
2403 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2404 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2407 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2408 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2411 else if (door_2.anim_mode == ANIM_VERTICAL && x <= VYSIZE)
2413 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
2414 int dst1_x = VX, dst1_y = VY + VYSIZE - i;
2415 int src2_x = 0, src2_y = DOOR_GFX_PAGEY2 + VYSIZE - i;
2416 int dst2_x = VX, dst2_y = VY;
2417 int width = VXSIZE, height = i;
2419 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2420 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2423 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2424 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2427 else if (x <= VXSIZE) /* ANIM_DEFAULT */
2429 int j = (door_2.anim_mode == ANIM_DEFAULT ? (VXSIZE - i) / 3 : 0);
2431 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2432 BlitBitmapMasked(bitmap, drawto,
2433 VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2,
2434 VX + VXSIZE - i, VY + j);
2435 SetClipOrigin(bitmap, gc,
2436 VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
2437 BlitBitmapMasked(bitmap, drawto,
2438 VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j,
2441 BlitBitmapMasked(bitmap, drawto,
2442 VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2,
2443 i, VYSIZE / 2, VX, VY + VYSIZE / 2 - j);
2444 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2445 BlitBitmapMasked(bitmap, drawto,
2446 VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2,
2448 VX + VXSIZE - i, VY + VYSIZE / 2 + j);
2451 redraw_mask |= REDRAW_DOOR_2;
2452 door_2_done = (a == VXSIZE);
2457 if (game_status == GAME_MODE_MAIN)
2460 if (!(door_state & DOOR_NO_DELAY))
2461 WaitUntilDelayReached(&door_delay, door_delay_value);
2465 if (setup.quick_doors)
2467 StopSound(SND_DOOR_OPENING);
2468 StopSound(SND_DOOR_CLOSING);
2471 if (door_state & DOOR_ACTION_1)
2472 door1 = door_state & DOOR_ACTION_1;
2473 if (door_state & DOOR_ACTION_2)
2474 door2 = door_state & DOOR_ACTION_2;
2476 return (door1 | door2);
2479 void DrawSpecialEditorDoor()
2481 /* draw bigger toolbox window */
2482 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
2483 DOOR_GFX_PAGEX7, 0, EXSIZE + 8, 8,
2485 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
2486 EX - 4, VY - 4, EXSIZE + 8, EYSIZE - VYSIZE + 4,
2489 redraw_mask |= REDRAW_ALL;
2492 void UndrawSpecialEditorDoor()
2494 /* draw normal tape recorder window */
2495 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
2496 EX - 4, EY - 12, EXSIZE + 8, EYSIZE - VYSIZE + 12,
2499 redraw_mask |= REDRAW_ALL;
2503 /* ---------- new tool button stuff ---------------------------------------- */
2505 /* graphic position values for tool buttons */
2506 #define TOOL_BUTTON_YES_XPOS 2
2507 #define TOOL_BUTTON_YES_YPOS 250
2508 #define TOOL_BUTTON_YES_GFX_YPOS 0
2509 #define TOOL_BUTTON_YES_XSIZE 46
2510 #define TOOL_BUTTON_YES_YSIZE 28
2511 #define TOOL_BUTTON_NO_XPOS 52
2512 #define TOOL_BUTTON_NO_YPOS TOOL_BUTTON_YES_YPOS
2513 #define TOOL_BUTTON_NO_GFX_YPOS TOOL_BUTTON_YES_GFX_YPOS
2514 #define TOOL_BUTTON_NO_XSIZE TOOL_BUTTON_YES_XSIZE
2515 #define TOOL_BUTTON_NO_YSIZE TOOL_BUTTON_YES_YSIZE
2516 #define TOOL_BUTTON_CONFIRM_XPOS TOOL_BUTTON_YES_XPOS
2517 #define TOOL_BUTTON_CONFIRM_YPOS TOOL_BUTTON_YES_YPOS
2518 #define TOOL_BUTTON_CONFIRM_GFX_YPOS 30
2519 #define TOOL_BUTTON_CONFIRM_XSIZE 96
2520 #define TOOL_BUTTON_CONFIRM_YSIZE TOOL_BUTTON_YES_YSIZE
2521 #define TOOL_BUTTON_PLAYER_XSIZE 30
2522 #define TOOL_BUTTON_PLAYER_YSIZE 30
2523 #define TOOL_BUTTON_PLAYER_GFX_XPOS 5
2524 #define TOOL_BUTTON_PLAYER_GFX_YPOS 185
2525 #define TOOL_BUTTON_PLAYER_XPOS (5 + TOOL_BUTTON_PLAYER_XSIZE / 2)
2526 #define TOOL_BUTTON_PLAYER_YPOS (215 - TOOL_BUTTON_PLAYER_YSIZE / 2)
2527 #define TOOL_BUTTON_PLAYER1_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2528 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2529 #define TOOL_BUTTON_PLAYER2_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2530 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2531 #define TOOL_BUTTON_PLAYER3_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2532 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2533 #define TOOL_BUTTON_PLAYER4_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2534 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2535 #define TOOL_BUTTON_PLAYER1_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2536 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2537 #define TOOL_BUTTON_PLAYER2_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2538 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2539 #define TOOL_BUTTON_PLAYER3_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2540 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2541 #define TOOL_BUTTON_PLAYER4_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2542 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2551 } toolbutton_info[NUM_TOOL_BUTTONS] =
2554 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_GFX_YPOS,
2555 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_YPOS,
2556 TOOL_BUTTON_YES_XSIZE, TOOL_BUTTON_YES_YSIZE,
2561 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_GFX_YPOS,
2562 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_YPOS,
2563 TOOL_BUTTON_NO_XSIZE, TOOL_BUTTON_NO_YSIZE,
2568 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_GFX_YPOS,
2569 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_YPOS,
2570 TOOL_BUTTON_CONFIRM_XSIZE, TOOL_BUTTON_CONFIRM_YSIZE,
2571 TOOL_CTRL_ID_CONFIRM,
2575 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2576 TOOL_BUTTON_PLAYER1_XPOS, TOOL_BUTTON_PLAYER1_YPOS,
2577 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2578 TOOL_CTRL_ID_PLAYER_1,
2582 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2583 TOOL_BUTTON_PLAYER2_XPOS, TOOL_BUTTON_PLAYER2_YPOS,
2584 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2585 TOOL_CTRL_ID_PLAYER_2,
2589 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2590 TOOL_BUTTON_PLAYER3_XPOS, TOOL_BUTTON_PLAYER3_YPOS,
2591 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2592 TOOL_CTRL_ID_PLAYER_3,
2596 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2597 TOOL_BUTTON_PLAYER4_XPOS, TOOL_BUTTON_PLAYER4_YPOS,
2598 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2599 TOOL_CTRL_ID_PLAYER_4,
2604 void CreateToolButtons()
2608 for (i=0; i<NUM_TOOL_BUTTONS; i++)
2610 Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
2611 Bitmap *deco_bitmap = None;
2612 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
2613 struct GadgetInfo *gi;
2614 unsigned long event_mask;
2615 int gd_xoffset, gd_yoffset;
2616 int gd_x1, gd_x2, gd_y;
2619 event_mask = GD_EVENT_RELEASED;
2621 gd_xoffset = toolbutton_info[i].xpos;
2622 gd_yoffset = toolbutton_info[i].ypos;
2623 gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
2624 gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
2625 gd_y = DOOR_GFX_PAGEY1 + gd_yoffset;
2627 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
2629 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
2631 getMiniGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr),
2632 &deco_bitmap, &deco_x, &deco_y);
2633 deco_xpos = (toolbutton_info[i].width - MINI_TILEX) / 2;
2634 deco_ypos = (toolbutton_info[i].height - MINI_TILEY) / 2;
2637 gi = CreateGadget(GDI_CUSTOM_ID, id,
2638 GDI_INFO_TEXT, toolbutton_info[i].infotext,
2639 GDI_X, DX + toolbutton_info[i].x,
2640 GDI_Y, DY + toolbutton_info[i].y,
2641 GDI_WIDTH, toolbutton_info[i].width,
2642 GDI_HEIGHT, toolbutton_info[i].height,
2643 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
2644 GDI_STATE, GD_BUTTON_UNPRESSED,
2645 GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
2646 GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
2647 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
2648 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
2649 GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
2650 GDI_DECORATION_SHIFTING, 1, 1,
2651 GDI_EVENT_MASK, event_mask,
2652 GDI_CALLBACK_ACTION, HandleToolButtons,
2656 Error(ERR_EXIT, "cannot create gadget");
2658 tool_gadget[id] = gi;
2662 void FreeToolButtons()
2666 for (i=0; i<NUM_TOOL_BUTTONS; i++)
2667 FreeGadget(tool_gadget[i]);
2670 static void UnmapToolButtons()
2674 for (i=0; i<NUM_TOOL_BUTTONS; i++)
2675 UnmapGadget(tool_gadget[i]);
2678 static void HandleToolButtons(struct GadgetInfo *gi)
2680 request_gadget_id = gi->custom_id;
2683 int get_next_element(int element)
2687 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
2688 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
2689 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
2690 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
2691 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
2692 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
2693 case EL_AMOEBA_DROPPING: return EL_AMOEBA_WET;
2695 default: return element;
2699 int el_act_dir2img(int element, int action, int direction)
2701 element = GFX_ELEMENT(element);
2702 direction = MV_DIR_BIT(direction);
2704 return element_info[element].direction_graphic[action][direction];
2707 static int el_act_dir2crm(int element, int action, int direction)
2709 element = GFX_ELEMENT(element);
2710 direction = MV_DIR_BIT(direction);
2712 return element_info[element].direction_crumbled[action][direction];
2715 int el_act2img(int element, int action)
2717 element = GFX_ELEMENT(element);
2719 return element_info[element].graphic[action];
2722 int el_act2crm(int element, int action)
2724 element = GFX_ELEMENT(element);
2726 return element_info[element].crumbled[action];
2729 int el_dir2img(int element, int direction)
2731 element = GFX_ELEMENT(element);
2733 return el_act_dir2img(element, ACTION_DEFAULT, direction);
2736 int el2img(int element)
2738 element = GFX_ELEMENT(element);
2740 return element_info[element].graphic[ACTION_DEFAULT];
2743 int el2edimg(int element)
2745 element = GFX_ELEMENT(element);
2747 return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
2750 int el2preimg(int element)
2752 element = GFX_ELEMENT(element);
2754 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];