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);
747 int frame = getGraphicAnimationFrame(graphic, player->StepFrame);
749 int frame = getGraphicAnimationFrame(graphic, player->Frame);
752 DrawGraphicShifted(px, py, sxx, syy, graphic, frame,
753 NO_CUTTING, NO_MASKING);
757 /* ----------------------------------------------------------------------- */
758 /* draw things in front of player (active dynamite or dynabombs) */
759 /* ----------------------------------------------------------------------- */
761 if (IS_ACTIVE_BOMB(element))
763 graphic = el2img(element);
764 frame = getGraphicAnimationFrame(graphic, GfxFrame[jx][jy]);
766 if (game.emulation == EMU_SUPAPLEX)
767 DrawGraphic(sx, sy, IMG_SP_DISK_RED, frame);
769 DrawGraphicThruMask(sx, sy, graphic, frame);
772 if (player_is_moving && last_element == EL_EXPLOSION)
774 int graphic = el_act2img(GfxElement[last_jx][last_jy], ACTION_EXPLODING);
775 int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
776 int phase = ExplodePhase[last_jx][last_jy] - 1;
777 int frame = getGraphicAnimationFrame(graphic, phase - delay);
780 DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy), graphic, frame);
783 /* ----------------------------------------------------------------------- */
784 /* draw elements the player is just walking/passing through/under */
785 /* ----------------------------------------------------------------------- */
787 /* handle the field the player is leaving ... */
788 if (player_is_moving && IS_ACCESSIBLE_INSIDE(last_element))
789 DrawLevelField(last_jx, last_jy);
790 else if (player_is_moving && IS_ACCESSIBLE_UNDER(last_element))
791 DrawLevelFieldThruMask(last_jx, last_jy);
793 /* ... and the field the player is entering */
794 if (IS_ACCESSIBLE_INSIDE(element))
795 DrawLevelField(jx, jy);
796 else if (IS_ACCESSIBLE_UNDER(element))
797 DrawLevelFieldThruMask(jx, jy);
799 if (setup.direct_draw)
801 int dest_x = SX + SCREENX(MIN(jx, last_jx)) * TILEX;
802 int dest_y = SY + SCREENY(MIN(jy, last_jy)) * TILEY;
803 int x_size = TILEX * (1 + ABS(jx - last_jx));
804 int y_size = TILEY * (1 + ABS(jy - last_jy));
806 BlitBitmap(drawto_field, window,
807 dest_x, dest_y, x_size, y_size, dest_x, dest_y);
808 SetDrawtoField(DRAW_DIRECT);
811 MarkTileDirty(sx,sy);
814 void getGraphicSource(int graphic, int frame, Bitmap **bitmap, int *x, int *y)
816 struct GraphicInfo *g = &graphic_info[graphic];
820 if (g->offset_y == 0) /* frames are ordered horizontally */
822 int max_width = g->anim_frames_per_line * g->width;
824 *x = (g->src_x + frame * g->offset_x) % max_width;
825 *y = g->src_y + (g->src_x + frame * g->offset_x) / max_width * g->height;
827 else if (g->offset_x == 0) /* frames are ordered vertically */
829 int max_height = g->anim_frames_per_line * g->height;
831 *x = g->src_x + (g->src_y + frame * g->offset_y) / max_height * g->width;
832 *y = (g->src_y + frame * g->offset_y) % max_height;
834 else /* frames are ordered diagonally */
836 *x = g->src_x + frame * g->offset_x;
837 *y = g->src_y + frame * g->offset_y;
841 void DrawGraphic(int x, int y, int graphic, int frame)
844 if (!IN_SCR_FIELD(x, y))
846 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
847 printf("DrawGraphic(): This should never happen!\n");
852 DrawGraphicExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic, frame);
856 void DrawGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
862 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
863 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
866 void DrawGraphicThruMask(int x, int y, int graphic, int frame)
869 if (!IN_SCR_FIELD(x, y))
871 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
872 printf("DrawGraphicThruMask(): This should never happen!\n");
877 DrawGraphicThruMaskExt(drawto_field, FX + x * TILEX, FY + y *TILEY, graphic,
882 void DrawGraphicThruMaskExt(DrawBuffer *d, int dest_x, int dest_y, int graphic,
890 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
891 drawing_gc = src_bitmap->stored_clip_gc;
893 GC drawing_gc = src_bitmap->stored_clip_gc;
894 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
895 int src_x = graphic_info[graphic].src_x;
896 int src_y = graphic_info[graphic].src_y;
897 int offset_x = graphic_info[graphic].offset_x;
898 int offset_y = graphic_info[graphic].offset_y;
900 src_x += frame * offset_x;
901 src_y += frame * offset_y;
905 SetClipOrigin(src_bitmap, drawing_gc, dest_x - src_x, dest_y - src_y);
906 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX, TILEY, dest_x, dest_y);
909 void DrawMiniGraphic(int x, int y, int graphic)
911 DrawMiniGraphicExt(drawto, SX + x * MINI_TILEX,SY + y * MINI_TILEY, graphic);
912 MarkTileDirty(x / 2, y / 2);
915 void getMiniGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
917 struct GraphicInfo *g = &graphic_info[graphic];
919 int mini_starty = g->bitmap->height * 2 / 3;
922 *x = mini_startx + g->src_x / 2;
923 *y = mini_starty + g->src_y / 2;
926 void DrawMiniGraphicExt(DrawBuffer *d, int x, int y, int graphic)
931 getMiniGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
932 BlitBitmap(src_bitmap, d, src_x, src_y, MINI_TILEX, MINI_TILEY, x, y);
935 void DrawGraphicShifted(int x,int y, int dx,int dy, int graphic, int frame,
936 int cut_mode, int mask_mode)
941 int width = TILEX, height = TILEY;
947 DrawGraphic(x, y, graphic, frame);
951 if (dx || dy) /* shifted graphic */
953 if (x < BX1) /* object enters playfield from the left */
960 else if (x > BX2) /* object enters playfield from the right */
966 else if (x==BX1 && dx < 0) /* object leaves playfield to the left */
972 else if (x==BX2 && dx > 0) /* object leaves playfield to the right */
974 else if (dx) /* general horizontal movement */
975 MarkTileDirty(x + SIGN(dx), y);
977 if (y < BY1) /* object enters playfield from the top */
979 if (cut_mode==CUT_BELOW) /* object completely above top border */
987 else if (y > BY2) /* object enters playfield from the bottom */
993 else if (y==BY1 && dy < 0) /* object leaves playfield to the top */
999 else if (dy > 0 && cut_mode == CUT_ABOVE)
1001 if (y == BY2) /* object completely above bottom border */
1007 MarkTileDirty(x, y + 1);
1008 } /* object leaves playfield to the bottom */
1009 else if (dy > 0 && (y == BY2 || cut_mode == CUT_BELOW))
1011 else if (dy) /* general vertical movement */
1012 MarkTileDirty(x, y + SIGN(dy));
1016 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1018 src_bitmap = graphic_info[graphic].bitmap;
1019 src_x = graphic_info[graphic].src_x;
1020 src_y = graphic_info[graphic].src_y;
1021 offset_x = graphic_info[graphic].offset_x;
1022 offset_y = graphic_info[graphic].offset_y;
1024 src_x += frame * offset_x;
1025 src_y += frame * offset_y;
1028 drawing_gc = src_bitmap->stored_clip_gc;
1033 dest_x = FX + x * TILEX + dx;
1034 dest_y = FY + y * TILEY + dy;
1037 if (!IN_SCR_FIELD(x,y))
1039 printf("DrawGraphicShifted(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
1040 printf("DrawGraphicShifted(): This should never happen!\n");
1045 if (mask_mode == USE_MASKING)
1047 SetClipOrigin(src_bitmap, drawing_gc, dest_x - src_x, dest_y - src_y);
1048 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1052 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1058 void DrawGraphicShiftedThruMask(int x, int y, int dx, int dy, int graphic,
1059 int frame, int cut_mode)
1061 DrawGraphicShifted(x,y, dx,dy, graphic, frame, cut_mode, USE_MASKING);
1064 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
1065 int cut_mode, int mask_mode)
1067 int lx = LEVELX(x), ly = LEVELY(y);
1071 if (IN_LEV_FIELD(lx, ly))
1073 SetRandomAnimationValue(lx, ly);
1075 graphic = el_act_dir2img(element, GfxAction[lx][ly], MovDir[lx][ly]);
1076 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1078 else /* border element */
1080 graphic = el2img(element);
1081 frame = getGraphicAnimationFrame(graphic, -1);
1084 if (element == EL_EXPANDABLE_WALL)
1086 boolean left_stopped = FALSE, right_stopped = FALSE;
1088 if (!IN_LEV_FIELD(lx - 1, ly) || IS_WALL(Feld[lx - 1][ly]))
1089 left_stopped = TRUE;
1090 if (!IN_LEV_FIELD(lx + 1, ly) || IS_WALL(Feld[lx + 1][ly]))
1091 right_stopped = TRUE;
1093 if (left_stopped && right_stopped)
1095 else if (left_stopped)
1097 graphic = IMG_EXPANDABLE_WALL_GROWING_RIGHT;
1098 frame = graphic_info[graphic].anim_frames - 1;
1100 else if (right_stopped)
1102 graphic = IMG_EXPANDABLE_WALL_GROWING_LEFT;
1103 frame = graphic_info[graphic].anim_frames - 1;
1108 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, mask_mode);
1109 else if (mask_mode == USE_MASKING)
1110 DrawGraphicThruMask(x, y, graphic, frame);
1112 DrawGraphic(x, y, graphic, frame);
1115 void DrawLevelElementExt(int x, int y, int dx, int dy, int element,
1116 int cut_mode, int mask_mode)
1118 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1119 DrawScreenElementExt(SCREENX(x), SCREENY(y), dx, dy, element,
1120 cut_mode, mask_mode);
1123 void DrawScreenElementShifted(int x, int y, int dx, int dy, int element,
1126 DrawScreenElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1129 void DrawLevelElementShifted(int x, int y, int dx, int dy, int element,
1132 DrawLevelElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1135 void DrawLevelElementThruMask(int x, int y, int element)
1137 DrawLevelElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1140 void DrawLevelFieldThruMask(int x, int y)
1142 DrawLevelElementExt(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
1145 static void DrawLevelFieldCrumbledSandExt(int x, int y, int graphic, int frame)
1149 int sx = SCREENX(x), sy = SCREENY(y);
1151 int width, height, cx, cy, i;
1153 int crumbled_border_size = graphic_info[graphic].border_size;
1155 int snip = TILEX / 8; /* number of border pixels from "crumbled graphic" */
1157 static int xy[4][2] =
1166 if (x == 0 && y == 7)
1167 printf("::: %d, %d [%d]\n", GfxElement[x][y], Feld[x][y],
1168 crumbled_border_size);
1171 if (!IN_LEV_FIELD(x, y))
1174 element = (GfxElement[x][y] != EL_UNDEFINED && Feld[x][y] != EL_EXPLOSION ?
1175 GfxElement[x][y] : Feld[x][y]);
1177 /* crumble field itself */
1178 if (GFX_CRUMBLED(element) && !IS_MOVING(x, y))
1180 if (!IN_SCR_FIELD(sx, sy))
1183 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1187 int xx = x + xy[i][0];
1188 int yy = y + xy[i][1];
1190 element = (IN_LEV_FIELD(xx, yy) ? Feld[xx][yy] : BorderElement);
1192 /* check if neighbour field is of same type */
1193 if (GFX_CRUMBLED(element) && !IS_MOVING(xx, yy))
1197 if (Feld[x][y] == EL_CUSTOM_START + 123)
1198 printf("::: crumble [%d] THE CHAOS ENGINE (%d, %d): %d, %d\n",
1199 i, Feld[x][y], element,
1200 GFX_CRUMBLED(element), IS_MOVING(x, y));
1203 if (i == 1 || i == 2)
1205 width = crumbled_border_size;
1207 cx = (i == 2 ? TILEX - crumbled_border_size : 0);
1213 height = crumbled_border_size;
1215 cy = (i == 3 ? TILEY - crumbled_border_size : 0);
1218 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1219 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
1222 MarkTileDirty(sx, sy);
1224 else /* crumble neighbour fields */
1227 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1232 int xx = x + xy[i][0];
1233 int yy = y + xy[i][1];
1234 int sxx = sx + xy[i][0];
1235 int syy = sy + xy[i][1];
1237 if (!IN_LEV_FIELD(xx, yy) ||
1238 !IN_SCR_FIELD(sxx, syy) ||
1239 !GFX_CRUMBLED(Feld[xx][yy]) ||
1244 graphic = el_act2crm(Feld[xx][yy], ACTION_DEFAULT);
1245 crumbled_border_size = graphic_info[graphic].border_size;
1247 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1250 if (i == 1 || i == 2)
1252 width = crumbled_border_size;
1254 cx = (i == 1 ? TILEX - crumbled_border_size : 0);
1260 height = crumbled_border_size;
1262 cy = (i == 0 ? TILEY - crumbled_border_size : 0);
1265 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1266 width, height, FX + sxx * TILEX + cx, FY + syy * TILEY + cy);
1268 MarkTileDirty(sxx, syy);
1273 void DrawLevelFieldCrumbledSand(int x, int y)
1278 if (!IN_LEV_FIELD(x, y))
1281 graphic = el_act2crm(Feld[x][y], ACTION_DEFAULT);
1283 DrawLevelFieldCrumbledSandExt(x, y, graphic, 0);
1285 DrawLevelFieldCrumbledSandExt(x, y, IMG_SAND_CRUMBLED, 0);
1289 void DrawLevelFieldCrumbledSandDigging(int x, int y, int direction,
1293 int graphic1 = el_act_dir2img(GfxElement[x][y], ACTION_DIGGING, direction);
1294 int graphic2 = el_act_dir2crm(GfxElement[x][y], ACTION_DIGGING, direction);
1296 int graphic1 = el_act_dir2img(EL_SAND, ACTION_DIGGING, direction);
1297 int graphic2 = el_act_dir2img(EL_SAND_CRUMBLED, ACTION_DIGGING, direction);
1299 int frame1 = getGraphicAnimationFrame(graphic1, step_frame);
1300 int frame2 = getGraphicAnimationFrame(graphic2, step_frame);
1301 int sx = SCREENX(x), sy = SCREENY(y);
1303 DrawGraphic(sx, sy, graphic1, frame1);
1304 DrawLevelFieldCrumbledSandExt(x, y, graphic2, frame2);
1307 void DrawLevelFieldCrumbledSandNeighbours(int x, int y)
1309 int sx = SCREENX(x), sy = SCREENY(y);
1310 static int xy[4][2] =
1321 int xx = x + xy[i][0];
1322 int yy = y + xy[i][1];
1323 int sxx = sx + xy[i][0];
1324 int syy = sy + xy[i][1];
1326 if (!IN_LEV_FIELD(xx, yy) ||
1327 !IN_SCR_FIELD(sxx, syy) ||
1328 !GFX_CRUMBLED(Feld[xx][yy]) ||
1332 DrawLevelField(xx, yy);
1336 static int getBorderElement(int x, int y)
1340 { EL_STEELWALL_TOPLEFT, EL_INVISIBLE_STEELWALL_TOPLEFT },
1341 { EL_STEELWALL_TOPRIGHT, EL_INVISIBLE_STEELWALL_TOPRIGHT },
1342 { EL_STEELWALL_BOTTOMLEFT, EL_INVISIBLE_STEELWALL_BOTTOMLEFT },
1343 { EL_STEELWALL_BOTTOMRIGHT, EL_INVISIBLE_STEELWALL_BOTTOMRIGHT },
1344 { EL_STEELWALL_VERTICAL, EL_INVISIBLE_STEELWALL_VERTICAL },
1345 { EL_STEELWALL_HORIZONTAL, EL_INVISIBLE_STEELWALL_HORIZONTAL },
1346 { EL_STEELWALL, EL_INVISIBLE_STEELWALL }
1348 int steel_type = (BorderElement == EL_STEELWALL ? 0 : 1);
1349 int steel_position = (x == -1 && y == -1 ? 0 :
1350 x == lev_fieldx && y == -1 ? 1 :
1351 x == -1 && y == lev_fieldy ? 2 :
1352 x == lev_fieldx && y == lev_fieldy ? 3 :
1353 x == -1 || x == lev_fieldx ? 4 :
1354 y == -1 || y == lev_fieldy ? 5 : 6);
1356 return border[steel_position][steel_type];
1359 void DrawScreenElement(int x, int y, int element)
1361 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
1362 DrawLevelFieldCrumbledSand(LEVELX(x), LEVELY(y));
1365 void DrawLevelElement(int x, int y, int element)
1367 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1368 DrawScreenElement(SCREENX(x), SCREENY(y), element);
1371 void DrawScreenField(int x, int y)
1373 int lx = LEVELX(x), ly = LEVELY(y);
1374 int element, content;
1376 if (!IN_LEV_FIELD(lx, ly))
1378 if (lx < -1 || lx > lev_fieldx || ly < -1 || ly > lev_fieldy)
1381 element = getBorderElement(lx, ly);
1383 DrawScreenElement(x, y, element);
1387 element = Feld[lx][ly];
1388 content = Store[lx][ly];
1390 if (IS_MOVING(lx, ly))
1392 int horiz_move = (MovDir[lx][ly] == MV_LEFT || MovDir[lx][ly] == MV_RIGHT);
1393 boolean cut_mode = NO_CUTTING;
1395 if (element == EL_QUICKSAND_EMPTYING ||
1396 element == EL_MAGIC_WALL_EMPTYING ||
1397 element == EL_BD_MAGIC_WALL_EMPTYING ||
1398 element == EL_AMOEBA_DROPPING)
1399 cut_mode = CUT_ABOVE;
1400 else if (element == EL_QUICKSAND_FILLING ||
1401 element == EL_MAGIC_WALL_FILLING ||
1402 element == EL_BD_MAGIC_WALL_FILLING)
1403 cut_mode = CUT_BELOW;
1405 if (cut_mode == CUT_ABOVE)
1406 DrawScreenElementShifted(x, y, 0, 0, element, NO_CUTTING);
1408 DrawScreenElement(x, y, EL_EMPTY);
1411 DrawScreenElementShifted(x, y, MovPos[lx][ly], 0, element, NO_CUTTING);
1412 else if (cut_mode == NO_CUTTING)
1413 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], element, cut_mode);
1415 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], content, cut_mode);
1417 if (content == EL_ACID)
1418 DrawLevelElementThruMask(lx, ly + 1, EL_ACID);
1420 else if (IS_BLOCKED(lx, ly))
1425 boolean cut_mode = NO_CUTTING;
1426 int element_old, content_old;
1428 Blocked2Moving(lx, ly, &oldx, &oldy);
1431 horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
1432 MovDir[oldx][oldy] == MV_RIGHT);
1434 element_old = Feld[oldx][oldy];
1435 content_old = Store[oldx][oldy];
1437 if (element_old == EL_QUICKSAND_EMPTYING ||
1438 element_old == EL_MAGIC_WALL_EMPTYING ||
1439 element_old == EL_BD_MAGIC_WALL_EMPTYING ||
1440 element_old == EL_AMOEBA_DROPPING)
1441 cut_mode = CUT_ABOVE;
1443 DrawScreenElement(x, y, EL_EMPTY);
1446 DrawScreenElementShifted(sx, sy, MovPos[oldx][oldy], 0, element_old,
1448 else if (cut_mode == NO_CUTTING)
1449 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], element_old,
1452 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], content_old,
1455 else if (IS_DRAWABLE(element))
1456 DrawScreenElement(x, y, element);
1458 DrawScreenElement(x, y, EL_EMPTY);
1461 void DrawLevelField(int x, int y)
1463 if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1464 DrawScreenField(SCREENX(x), SCREENY(y));
1465 else if (IS_MOVING(x, y))
1469 Moving2Blocked(x, y, &newx, &newy);
1470 if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
1471 DrawScreenField(SCREENX(newx), SCREENY(newy));
1473 else if (IS_BLOCKED(x, y))
1477 Blocked2Moving(x, y, &oldx, &oldy);
1478 if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
1479 DrawScreenField(SCREENX(oldx), SCREENY(oldy));
1483 void DrawMiniElement(int x, int y, int element)
1487 graphic = el2edimg(element);
1488 DrawMiniGraphic(x, y, graphic);
1491 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
1493 int x = sx + scroll_x, y = sy + scroll_y;
1495 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
1496 DrawMiniElement(sx, sy, EL_EMPTY);
1497 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
1498 DrawMiniElement(sx, sy, Feld[x][y]);
1500 DrawMiniGraphic(sx, sy, el2edimg(getBorderElement(x, y)));
1503 void DrawEnvelopeBackground(int envelope_nr, int startx, int starty,
1504 int x, int y, int xsize, int ysize, int font_nr)
1506 int font_width = getFontWidth(font_nr);
1507 int font_height = getFontHeight(font_nr);
1508 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1511 int dst_x = SX + startx + x * font_width;
1512 int dst_y = SY + starty + y * font_height;
1513 int width = graphic_info[graphic].width;
1514 int height = graphic_info[graphic].height;
1515 int inner_width = MAX(width - 2 * font_width, font_width);
1516 int inner_height = MAX(height - 2 * font_height, font_height);
1517 int inner_sx = (width >= 3 * font_width ? font_width : 0);
1518 int inner_sy = (height >= 3 * font_height ? font_height : 0);
1519 boolean draw_masked = graphic_info[graphic].draw_masked;
1521 getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
1523 if (src_bitmap == NULL || width < font_width || height < font_height)
1525 ClearRectangle(drawto, dst_x, dst_y, font_width, font_height);
1529 src_x += (x == 0 ? 0 : x == xsize - 1 ? width - font_width :
1530 inner_sx + (x - 1) * font_width % inner_width);
1531 src_y += (y == 0 ? 0 : y == ysize - 1 ? height - font_height :
1532 inner_sy + (y - 1) * font_height % inner_height);
1536 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1537 dst_x - src_x, dst_y - src_y);
1538 BlitBitmapMasked(src_bitmap, drawto, src_x, src_y, font_width, font_height,
1542 BlitBitmap(src_bitmap, drawto, src_x, src_y, font_width, font_height,
1546 void AnimateEnvelope(int envelope_nr, int anim_mode, int action)
1548 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1549 boolean draw_masked = graphic_info[graphic].draw_masked;
1550 int mask_mode = (draw_masked ? BLIT_MASKED : BLIT_ON_BACKGROUND);
1551 boolean ffwd_delay = (tape.playing && tape.fast_forward);
1552 unsigned long anim_delay = 0;
1553 int anim_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
1554 int font_nr = FONT_ENVELOPE_1 + envelope_nr;
1555 int font_width = getFontWidth(font_nr);
1556 int font_height = getFontHeight(font_nr);
1557 int max_xsize = level.envelope_xsize[envelope_nr];
1558 int max_ysize = level.envelope_ysize[envelope_nr];
1559 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize : 0);
1560 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize : 0);
1561 int xend = max_xsize;
1562 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize : 0);
1563 int xstep = (xstart < xend ? 1 : 0);
1564 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
1567 for (x=xstart, y=ystart; x <= xend && y <= yend; x += xstep, y += ystep)
1569 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
1570 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
1571 int sx = (SXSIZE - xsize * font_width) / 2;
1572 int sy = (SYSIZE - ysize * font_height) / 2;
1575 SetDrawtoField(DRAW_BUFFERED);
1577 BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
1579 SetDrawtoField(DRAW_BACKBUFFER);
1581 for (yy=0; yy < ysize; yy++) for (xx=0; xx < xsize; xx++)
1582 DrawEnvelopeBackground(envelope_nr, sx,sy, xx,yy, xsize, ysize, font_nr);
1584 DrawTextToTextArea(SX + sx + font_width, SY + sy + font_height,
1585 level.envelope_text[envelope_nr], font_nr, max_xsize,
1586 xsize - 2, ysize - 2, mask_mode);
1588 redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
1591 WaitUntilDelayReached(&anim_delay, anim_delay_value / 2);
1595 void ShowEnvelope(int envelope_nr)
1597 int element = EL_ENVELOPE_1 + envelope_nr;
1598 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1599 int sound_opening = element_info[element].sound[ACTION_OPENING];
1600 int sound_closing = element_info[element].sound[ACTION_CLOSING];
1601 boolean ffwd_delay = (tape.playing && tape.fast_forward);
1602 int wait_delay_value = (ffwd_delay ? 500 : 1000);
1603 int anim_mode = graphic_info[graphic].anim_mode;
1604 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
1605 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
1607 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
1609 PlaySoundStereo(sound_opening, SOUND_MIDDLE);
1611 if (anim_mode == ANIM_DEFAULT)
1612 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_OPENING);
1614 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_OPENING);
1617 Delay(wait_delay_value);
1619 WaitForEventToContinue();
1621 PlaySoundStereo(sound_closing, SOUND_MIDDLE);
1623 if (anim_mode != ANIM_NONE)
1624 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_CLOSING);
1626 if (anim_mode == ANIM_DEFAULT)
1627 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_CLOSING);
1629 game.envelope_active = FALSE;
1631 SetDrawtoField(DRAW_BUFFERED);
1633 redraw_mask |= REDRAW_FIELD;
1637 void getMicroGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
1639 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
1640 int mini_startx = src_bitmap->width * 3 / 4;
1641 int mini_starty = src_bitmap->height * 2 / 3;
1642 int src_x = mini_startx + graphic_info[graphic].src_x / 8;
1643 int src_y = mini_starty + graphic_info[graphic].src_y / 8;
1645 *bitmap = src_bitmap;
1650 void DrawMicroElement(int xpos, int ypos, int element)
1654 int graphic = el2preimg(element);
1656 getMicroGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
1657 BlitBitmap(src_bitmap, drawto, src_x, src_y, MICRO_TILEX, MICRO_TILEY,
1665 SetDrawBackgroundMask(REDRAW_NONE);
1668 for(x=BX1; x<=BX2; x++)
1669 for(y=BY1; y<=BY2; y++)
1670 DrawScreenField(x, y);
1672 redraw_mask |= REDRAW_FIELD;
1675 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
1679 for(x=0; x<size_x; x++)
1680 for(y=0; y<size_y; y++)
1681 DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
1683 redraw_mask |= REDRAW_FIELD;
1686 static void DrawMicroLevelExt(int xpos, int ypos, int from_x, int from_y)
1690 DrawBackground(xpos, ypos, MICROLEV_XSIZE, MICROLEV_YSIZE);
1692 if (lev_fieldx < STD_LEV_FIELDX)
1693 xpos += (STD_LEV_FIELDX - lev_fieldx) / 2 * MICRO_TILEX;
1694 if (lev_fieldy < STD_LEV_FIELDY)
1695 ypos += (STD_LEV_FIELDY - lev_fieldy) / 2 * MICRO_TILEY;
1697 xpos += MICRO_TILEX;
1698 ypos += MICRO_TILEY;
1700 for(x=-1; x<=STD_LEV_FIELDX; x++)
1702 for(y=-1; y<=STD_LEV_FIELDY; y++)
1704 int lx = from_x + x, ly = from_y + y;
1706 if (lx >= 0 && lx < lev_fieldx && ly >= 0 && ly < lev_fieldy)
1707 DrawMicroElement(xpos + x * MICRO_TILEX, ypos + y * MICRO_TILEY,
1708 level.field[lx][ly]);
1709 else if (lx >= -1 && lx < lev_fieldx+1 && ly >= -1 && ly < lev_fieldy+1
1710 && BorderElement != EL_EMPTY)
1711 DrawMicroElement(xpos + x * MICRO_TILEX, ypos + y * MICRO_TILEY,
1712 getBorderElement(lx, ly));
1716 redraw_mask |= REDRAW_MICROLEVEL;
1719 #define MICROLABEL_EMPTY 0
1720 #define MICROLABEL_LEVEL_NAME 1
1721 #define MICROLABEL_CREATED_BY 2
1722 #define MICROLABEL_LEVEL_AUTHOR 3
1723 #define MICROLABEL_IMPORTED_FROM 4
1724 #define MICROLABEL_LEVEL_IMPORT_INFO 5
1726 static void DrawMicroLevelLabelExt(int mode)
1728 char label_text[MAX_OUTPUT_LINESIZE + 1];
1729 int max_len_label_text;
1730 int font_nr = FONT_TEXT_2;
1732 if (mode == MICROLABEL_CREATED_BY || mode == MICROLABEL_IMPORTED_FROM)
1733 font_nr = FONT_TEXT_3;
1735 max_len_label_text = SXSIZE / getFontWidth(font_nr);
1737 DrawBackground(SX, MICROLABEL_YPOS, SXSIZE, getFontHeight(font_nr));
1739 strncpy(label_text, (mode == MICROLABEL_LEVEL_NAME ? level.name :
1740 mode == MICROLABEL_CREATED_BY ? "created by" :
1741 mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
1742 mode == MICROLABEL_IMPORTED_FROM ? "imported from" :
1743 mode == MICROLABEL_LEVEL_IMPORT_INFO ?
1744 leveldir_current->imported_from : ""),
1745 max_len_label_text);
1746 label_text[max_len_label_text] = '\0';
1748 if (strlen(label_text) > 0)
1750 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
1751 int lypos = MICROLABEL_YPOS;
1753 DrawText(lxpos, lypos, label_text, font_nr);
1756 redraw_mask |= REDRAW_MICROLEVEL;
1759 void DrawMicroLevel(int xpos, int ypos, boolean restart)
1761 static unsigned long scroll_delay = 0;
1762 static unsigned long label_delay = 0;
1763 static int from_x, from_y, scroll_direction;
1764 static int label_state, label_counter;
1765 int last_game_status = game_status; /* save current game status */
1767 /* force PREVIEW font on preview level */
1768 game_status = GAME_MODE_PSEUDO_PREVIEW;
1772 from_x = from_y = 0;
1773 scroll_direction = MV_RIGHT;
1777 DrawMicroLevelExt(xpos, ypos, from_x, from_y);
1778 DrawMicroLevelLabelExt(label_state);
1780 /* initialize delay counters */
1781 DelayReached(&scroll_delay, 0);
1782 DelayReached(&label_delay, 0);
1784 if (leveldir_current->name)
1786 int text_width = getTextWidth(leveldir_current->name, FONT_TEXT_1);
1787 int lxpos = SX + (SXSIZE - text_width) / 2;
1788 int lypos = SY + 352;
1790 DrawText(lxpos, lypos, leveldir_current->name, FONT_TEXT_1);
1793 game_status = last_game_status; /* restore current game status */
1798 /* scroll micro level, if needed */
1799 if ((lev_fieldx > STD_LEV_FIELDX || lev_fieldy > STD_LEV_FIELDY) &&
1800 DelayReached(&scroll_delay, MICROLEVEL_SCROLL_DELAY))
1802 switch (scroll_direction)
1808 scroll_direction = MV_UP;
1812 if (from_x < lev_fieldx - STD_LEV_FIELDX)
1815 scroll_direction = MV_DOWN;
1822 scroll_direction = MV_RIGHT;
1826 if (from_y < lev_fieldy - STD_LEV_FIELDY)
1829 scroll_direction = MV_LEFT;
1836 DrawMicroLevelExt(xpos, ypos, from_x, from_y);
1839 /* redraw micro level label, if needed */
1840 if (strcmp(level.name, NAMELESS_LEVEL_NAME) != 0 &&
1841 strcmp(level.author, ANONYMOUS_NAME) != 0 &&
1842 strcmp(level.author, leveldir_current->name) != 0 &&
1843 DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
1845 int max_label_counter = 23;
1847 if (leveldir_current->imported_from != NULL)
1848 max_label_counter += 14;
1850 label_counter = (label_counter + 1) % max_label_counter;
1851 label_state = (label_counter >= 0 && label_counter <= 7 ?
1852 MICROLABEL_LEVEL_NAME :
1853 label_counter >= 9 && label_counter <= 12 ?
1854 MICROLABEL_CREATED_BY :
1855 label_counter >= 14 && label_counter <= 21 ?
1856 MICROLABEL_LEVEL_AUTHOR :
1857 label_counter >= 23 && label_counter <= 26 ?
1858 MICROLABEL_IMPORTED_FROM :
1859 label_counter >= 28 && label_counter <= 35 ?
1860 MICROLABEL_LEVEL_IMPORT_INFO : MICROLABEL_EMPTY);
1861 DrawMicroLevelLabelExt(label_state);
1864 game_status = last_game_status; /* restore current game status */
1867 void WaitForEventToContinue()
1869 boolean still_wait = TRUE;
1871 /* simulate releasing mouse button over last gadget, if still pressed */
1873 HandleGadgets(-1, -1, 0);
1875 button_status = MB_RELEASED;
1887 case EVENT_BUTTONPRESS:
1888 case EVENT_KEYPRESS:
1892 case EVENT_KEYRELEASE:
1893 ClearPlayerAction();
1897 HandleOtherEvents(&event);
1901 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
1908 /* don't eat all CPU time */
1913 #define MAX_REQUEST_LINES 13
1914 #define MAX_REQUEST_LINE_LEN 7
1916 boolean Request(char *text, unsigned int req_state)
1918 int mx, my, ty, result = -1;
1919 unsigned int old_door_state;
1920 int last_game_status = game_status; /* save current game status */
1923 SetMouseCursor(CURSOR_DEFAULT);
1926 #if defined(PLATFORM_UNIX)
1927 /* pause network game while waiting for request to answer */
1928 if (options.network &&
1929 game_status == GAME_MODE_PLAYING &&
1930 req_state & REQUEST_WAIT_FOR)
1931 SendToServer_PausePlaying();
1934 old_door_state = GetDoorState();
1936 /* simulate releasing mouse button over last gadget, if still pressed */
1938 HandleGadgets(-1, -1, 0);
1942 CloseDoor(DOOR_CLOSE_1);
1944 /* save old door content */
1945 BlitBitmap(bitmap_db_door, bitmap_db_door,
1946 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
1947 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
1949 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
1951 /* clear door drawing field */
1952 DrawBackground(DX, DY, DXSIZE, DYSIZE);
1954 /* force DOOR font on preview level */
1955 game_status = GAME_MODE_PSEUDO_DOOR;
1957 /* write text for request */
1958 for(ty=0; ty < MAX_REQUEST_LINES; ty++)
1960 char text_line[MAX_REQUEST_LINE_LEN + 1];
1966 for(tl=0,tx=0; tx < MAX_REQUEST_LINE_LEN; tl++,tx++)
1969 if (!tc || tc == ' ')
1980 strncpy(text_line, text, tl);
1983 DrawText(DX + (DXSIZE - tl * getFontWidth(FONT_TEXT_2)) / 2,
1984 DY + 8 + ty * (getFontHeight(FONT_TEXT_2) + 2),
1985 text_line, FONT_TEXT_2);
1987 text += tl + (tc == ' ' ? 1 : 0);
1990 game_status = last_game_status; /* restore current game status */
1992 if (req_state & REQ_ASK)
1994 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
1995 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
1997 else if (req_state & REQ_CONFIRM)
1999 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
2001 else if (req_state & REQ_PLAYER)
2003 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
2004 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
2005 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
2006 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
2009 /* copy request gadgets to door backbuffer */
2010 BlitBitmap(drawto, bitmap_db_door,
2011 DX, DY, DXSIZE, DYSIZE,
2012 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2014 OpenDoor(DOOR_OPEN_1);
2020 if (!(req_state & REQUEST_WAIT_FOR))
2022 SetDrawBackgroundMask(REDRAW_FIELD);
2027 if (game_status != GAME_MODE_MAIN)
2030 button_status = MB_RELEASED;
2032 request_gadget_id = -1;
2034 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
2037 SetMouseCursor(CURSOR_DEFAULT);
2050 case EVENT_BUTTONPRESS:
2051 case EVENT_BUTTONRELEASE:
2052 case EVENT_MOTIONNOTIFY:
2054 if (event.type == EVENT_MOTIONNOTIFY)
2056 if (!PointerInWindow(window))
2057 continue; /* window and pointer are on different screens */
2062 motion_status = TRUE;
2063 mx = ((MotionEvent *) &event)->x;
2064 my = ((MotionEvent *) &event)->y;
2068 motion_status = FALSE;
2069 mx = ((ButtonEvent *) &event)->x;
2070 my = ((ButtonEvent *) &event)->y;
2071 if (event.type == EVENT_BUTTONPRESS)
2072 button_status = ((ButtonEvent *) &event)->button;
2074 button_status = MB_RELEASED;
2077 /* this sets 'request_gadget_id' */
2078 HandleGadgets(mx, my, button_status);
2080 switch(request_gadget_id)
2082 case TOOL_CTRL_ID_YES:
2085 case TOOL_CTRL_ID_NO:
2088 case TOOL_CTRL_ID_CONFIRM:
2089 result = TRUE | FALSE;
2092 case TOOL_CTRL_ID_PLAYER_1:
2095 case TOOL_CTRL_ID_PLAYER_2:
2098 case TOOL_CTRL_ID_PLAYER_3:
2101 case TOOL_CTRL_ID_PLAYER_4:
2112 case EVENT_KEYPRESS:
2113 switch(GetEventKey((KeyEvent *)&event, TRUE))
2126 if (req_state & REQ_PLAYER)
2130 case EVENT_KEYRELEASE:
2131 ClearPlayerAction();
2135 HandleOtherEvents(&event);
2139 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
2141 int joy = AnyJoystick();
2143 if (joy & JOY_BUTTON_1)
2145 else if (joy & JOY_BUTTON_2)
2151 /* don't eat all CPU time */
2155 if (game_status != GAME_MODE_MAIN)
2160 if (!(req_state & REQ_STAY_OPEN))
2162 CloseDoor(DOOR_CLOSE_1);
2164 if (!(req_state & REQ_STAY_CLOSED) && (old_door_state & DOOR_OPEN_1))
2166 BlitBitmap(bitmap_db_door, bitmap_db_door,
2167 DOOR_GFX_PAGEX2,DOOR_GFX_PAGEY1, DXSIZE,DYSIZE,
2168 DOOR_GFX_PAGEX1,DOOR_GFX_PAGEY1);
2169 OpenDoor(DOOR_OPEN_1);
2175 SetDrawBackgroundMask(REDRAW_FIELD);
2177 #if defined(PLATFORM_UNIX)
2178 /* continue network game after request */
2179 if (options.network &&
2180 game_status == GAME_MODE_PLAYING &&
2181 req_state & REQUEST_WAIT_FOR)
2182 SendToServer_ContinuePlaying();
2188 unsigned int OpenDoor(unsigned int door_state)
2190 unsigned int new_door_state;
2192 if (door_state & DOOR_COPY_BACK)
2194 BlitBitmap(bitmap_db_door, bitmap_db_door,
2195 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE + VYSIZE,
2196 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2197 door_state &= ~DOOR_COPY_BACK;
2200 new_door_state = MoveDoor(door_state);
2202 return(new_door_state);
2205 unsigned int CloseDoor(unsigned int door_state)
2207 unsigned int new_door_state;
2209 BlitBitmap(backbuffer, bitmap_db_door,
2210 DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2211 BlitBitmap(backbuffer, bitmap_db_door,
2212 VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
2214 new_door_state = MoveDoor(door_state);
2216 return(new_door_state);
2219 unsigned int GetDoorState()
2221 return MoveDoor(DOOR_GET_STATE);
2224 unsigned int SetDoorState(unsigned int door_state)
2226 return MoveDoor(door_state | DOOR_SET_STATE);
2229 unsigned int MoveDoor(unsigned int door_state)
2231 static int door1 = DOOR_OPEN_1;
2232 static int door2 = DOOR_CLOSE_2;
2233 unsigned long door_delay = 0;
2234 unsigned long door_delay_value;
2237 if (door_state == DOOR_GET_STATE)
2238 return(door1 | door2);
2240 if (door_state & DOOR_SET_STATE)
2242 if (door_state & DOOR_ACTION_1)
2243 door1 = door_state & DOOR_ACTION_1;
2244 if (door_state & DOOR_ACTION_2)
2245 door2 = door_state & DOOR_ACTION_2;
2247 return(door1 | door2);
2250 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
2251 door_state &= ~DOOR_OPEN_1;
2252 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
2253 door_state &= ~DOOR_CLOSE_1;
2254 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
2255 door_state &= ~DOOR_OPEN_2;
2256 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
2257 door_state &= ~DOOR_CLOSE_2;
2259 door_delay_value = (door_state & DOOR_ACTION_1 ? door_1.step_delay :
2262 if (setup.quick_doors)
2264 stepsize = 20; /* must be choosen to always draw last frame */
2265 door_delay_value = 0;
2267 StopSound(SND_DOOR_OPENING);
2268 StopSound(SND_DOOR_CLOSING);
2271 if (global.autoplay_leveldir)
2273 door_state |= DOOR_NO_DELAY;
2274 door_state &= ~DOOR_CLOSE_ALL;
2277 if (door_state & DOOR_ACTION)
2279 boolean door_1_done = !(door_state & DOOR_ACTION_1);
2280 boolean door_2_done = !(door_state & DOOR_ACTION_2);
2281 int start = ((door_state & DOOR_NO_DELAY) ? DXSIZE : 0);
2282 int end = (door_state & DOOR_ACTION_1 &&
2283 door_1.anim_mode == ANIM_VERTICAL ? DYSIZE : DXSIZE);
2286 if (!(door_state & DOOR_NO_DELAY))
2288 /* opening door sound has priority over simultaneously closing door */
2289 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
2290 PlaySoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
2291 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
2292 PlaySoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
2295 for(x = start; x <= end && !(door_1_done && door_2_done); x += stepsize)
2297 Bitmap *bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
2298 GC gc = bitmap->stored_clip_gc;
2300 if (door_state & DOOR_ACTION_1)
2302 int a = MIN(x * door_1.step_offset, end);
2303 int i = (door_state & DOOR_OPEN_1 ? end - a : a);
2307 BlitBitmap(bitmap_db_door, drawto,
2308 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + i / 2,
2309 DXSIZE,DYSIZE - i / 2, DX, DY);
2311 ClearRectangle(drawto, DX, DY + DYSIZE - i / 2, DXSIZE, i / 2);
2314 if (door_1.anim_mode == ANIM_HORIZONTAL && x <= DXSIZE)
2316 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
2317 int dst1_x = DX + DXSIZE - i, dst1_y = DY;
2318 int src2_x = DXSIZE - i, src2_y = DOOR_GFX_PAGEY1;
2319 int dst2_x = DX, dst2_y = DY;
2320 int width = i, height = DYSIZE;
2322 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2323 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2326 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2327 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2330 else if (door_1.anim_mode == ANIM_VERTICAL && x <= DYSIZE)
2332 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
2333 int dst1_x = DX, dst1_y = DY + DYSIZE - i;
2334 int src2_x = 0, src2_y = DOOR_GFX_PAGEY1 + DYSIZE - i;
2335 int dst2_x = DX, dst2_y = DY;
2336 int width = DXSIZE, height = i;
2338 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2339 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2342 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2343 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2346 else if (x <= DXSIZE) /* ANIM_DEFAULT */
2348 int j = (door_1.anim_mode == ANIM_DEFAULT ? (DXSIZE - i) / 3 : 0);
2350 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2351 BlitBitmapMasked(bitmap, drawto,
2352 DXSIZE, DOOR_GFX_PAGEY1, i, 77,
2353 DX + DXSIZE - i, DY + j);
2354 BlitBitmapMasked(bitmap, drawto,
2355 DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63,
2356 DX + DXSIZE - i, DY + 140 + j);
2357 SetClipOrigin(bitmap, gc, DX - DXSIZE + i,
2358 DY - (DOOR_GFX_PAGEY1 + j));
2359 BlitBitmapMasked(bitmap, drawto,
2360 DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j,
2362 BlitBitmapMasked(bitmap, drawto,
2363 DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63,
2366 BlitBitmapMasked(bitmap, drawto,
2367 DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
2369 BlitBitmapMasked(bitmap, drawto,
2370 DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
2372 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2373 BlitBitmapMasked(bitmap, drawto,
2374 DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
2375 DX + DXSIZE - i, DY + 77 + j);
2376 BlitBitmapMasked(bitmap, drawto,
2377 DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
2378 DX + DXSIZE - i, DY + 203 + j);
2381 redraw_mask |= REDRAW_DOOR_1;
2382 door_1_done = (a == end);
2385 if (door_state & DOOR_ACTION_2)
2387 int a = MIN(x * door_2.step_offset, VXSIZE);
2388 int i = (door_state & DOOR_OPEN_2 ? VXSIZE - a : a);
2392 BlitBitmap(bitmap_db_door, drawto,
2393 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + i / 2,
2394 VXSIZE, VYSIZE - i / 2, VX, VY);
2396 ClearRectangle(drawto, VX, VY + VYSIZE - i / 2, VXSIZE, i / 2);
2399 if (door_2.anim_mode == ANIM_HORIZONTAL && x <= VXSIZE)
2401 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
2402 int dst1_x = VX + VXSIZE - i, dst1_y = VY;
2403 int src2_x = VXSIZE - i, src2_y = DOOR_GFX_PAGEY2;
2404 int dst2_x = VX, dst2_y = VY;
2405 int width = i, height = VYSIZE;
2407 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2408 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2411 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2412 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2415 else if (door_2.anim_mode == ANIM_VERTICAL && x <= VYSIZE)
2417 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
2418 int dst1_x = VX, dst1_y = VY + VYSIZE - i;
2419 int src2_x = 0, src2_y = DOOR_GFX_PAGEY2 + VYSIZE - i;
2420 int dst2_x = VX, dst2_y = VY;
2421 int width = VXSIZE, height = i;
2423 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2424 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2427 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2428 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2431 else if (x <= VXSIZE) /* ANIM_DEFAULT */
2433 int j = (door_2.anim_mode == ANIM_DEFAULT ? (VXSIZE - i) / 3 : 0);
2435 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2436 BlitBitmapMasked(bitmap, drawto,
2437 VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2,
2438 VX + VXSIZE - i, VY + j);
2439 SetClipOrigin(bitmap, gc,
2440 VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
2441 BlitBitmapMasked(bitmap, drawto,
2442 VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j,
2445 BlitBitmapMasked(bitmap, drawto,
2446 VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2,
2447 i, VYSIZE / 2, VX, VY + VYSIZE / 2 - j);
2448 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2449 BlitBitmapMasked(bitmap, drawto,
2450 VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2,
2452 VX + VXSIZE - i, VY + VYSIZE / 2 + j);
2455 redraw_mask |= REDRAW_DOOR_2;
2456 door_2_done = (a == VXSIZE);
2461 if (game_status == GAME_MODE_MAIN)
2464 if (!(door_state & DOOR_NO_DELAY))
2465 WaitUntilDelayReached(&door_delay, door_delay_value);
2469 if (setup.quick_doors)
2471 StopSound(SND_DOOR_OPENING);
2472 StopSound(SND_DOOR_CLOSING);
2475 if (door_state & DOOR_ACTION_1)
2476 door1 = door_state & DOOR_ACTION_1;
2477 if (door_state & DOOR_ACTION_2)
2478 door2 = door_state & DOOR_ACTION_2;
2480 return (door1 | door2);
2483 void DrawSpecialEditorDoor()
2485 /* draw bigger toolbox window */
2486 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
2487 DOOR_GFX_PAGEX7, 0, EXSIZE + 8, 8,
2489 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
2490 EX - 4, VY - 4, EXSIZE + 8, EYSIZE - VYSIZE + 4,
2493 redraw_mask |= REDRAW_ALL;
2496 void UndrawSpecialEditorDoor()
2498 /* draw normal tape recorder window */
2499 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
2500 EX - 4, EY - 12, EXSIZE + 8, EYSIZE - VYSIZE + 12,
2503 redraw_mask |= REDRAW_ALL;
2507 /* ---------- new tool button stuff ---------------------------------------- */
2509 /* graphic position values for tool buttons */
2510 #define TOOL_BUTTON_YES_XPOS 2
2511 #define TOOL_BUTTON_YES_YPOS 250
2512 #define TOOL_BUTTON_YES_GFX_YPOS 0
2513 #define TOOL_BUTTON_YES_XSIZE 46
2514 #define TOOL_BUTTON_YES_YSIZE 28
2515 #define TOOL_BUTTON_NO_XPOS 52
2516 #define TOOL_BUTTON_NO_YPOS TOOL_BUTTON_YES_YPOS
2517 #define TOOL_BUTTON_NO_GFX_YPOS TOOL_BUTTON_YES_GFX_YPOS
2518 #define TOOL_BUTTON_NO_XSIZE TOOL_BUTTON_YES_XSIZE
2519 #define TOOL_BUTTON_NO_YSIZE TOOL_BUTTON_YES_YSIZE
2520 #define TOOL_BUTTON_CONFIRM_XPOS TOOL_BUTTON_YES_XPOS
2521 #define TOOL_BUTTON_CONFIRM_YPOS TOOL_BUTTON_YES_YPOS
2522 #define TOOL_BUTTON_CONFIRM_GFX_YPOS 30
2523 #define TOOL_BUTTON_CONFIRM_XSIZE 96
2524 #define TOOL_BUTTON_CONFIRM_YSIZE TOOL_BUTTON_YES_YSIZE
2525 #define TOOL_BUTTON_PLAYER_XSIZE 30
2526 #define TOOL_BUTTON_PLAYER_YSIZE 30
2527 #define TOOL_BUTTON_PLAYER_GFX_XPOS 5
2528 #define TOOL_BUTTON_PLAYER_GFX_YPOS 185
2529 #define TOOL_BUTTON_PLAYER_XPOS (5 + TOOL_BUTTON_PLAYER_XSIZE / 2)
2530 #define TOOL_BUTTON_PLAYER_YPOS (215 - TOOL_BUTTON_PLAYER_YSIZE / 2)
2531 #define TOOL_BUTTON_PLAYER1_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2532 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2533 #define TOOL_BUTTON_PLAYER2_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2534 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2535 #define TOOL_BUTTON_PLAYER3_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2536 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2537 #define TOOL_BUTTON_PLAYER4_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2538 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2539 #define TOOL_BUTTON_PLAYER1_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2540 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2541 #define TOOL_BUTTON_PLAYER2_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2542 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2543 #define TOOL_BUTTON_PLAYER3_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2544 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2545 #define TOOL_BUTTON_PLAYER4_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2546 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2555 } toolbutton_info[NUM_TOOL_BUTTONS] =
2558 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_GFX_YPOS,
2559 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_YPOS,
2560 TOOL_BUTTON_YES_XSIZE, TOOL_BUTTON_YES_YSIZE,
2565 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_GFX_YPOS,
2566 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_YPOS,
2567 TOOL_BUTTON_NO_XSIZE, TOOL_BUTTON_NO_YSIZE,
2572 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_GFX_YPOS,
2573 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_YPOS,
2574 TOOL_BUTTON_CONFIRM_XSIZE, TOOL_BUTTON_CONFIRM_YSIZE,
2575 TOOL_CTRL_ID_CONFIRM,
2579 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2580 TOOL_BUTTON_PLAYER1_XPOS, TOOL_BUTTON_PLAYER1_YPOS,
2581 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2582 TOOL_CTRL_ID_PLAYER_1,
2586 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2587 TOOL_BUTTON_PLAYER2_XPOS, TOOL_BUTTON_PLAYER2_YPOS,
2588 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2589 TOOL_CTRL_ID_PLAYER_2,
2593 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2594 TOOL_BUTTON_PLAYER3_XPOS, TOOL_BUTTON_PLAYER3_YPOS,
2595 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2596 TOOL_CTRL_ID_PLAYER_3,
2600 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2601 TOOL_BUTTON_PLAYER4_XPOS, TOOL_BUTTON_PLAYER4_YPOS,
2602 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2603 TOOL_CTRL_ID_PLAYER_4,
2608 void CreateToolButtons()
2612 for (i=0; i<NUM_TOOL_BUTTONS; i++)
2614 Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
2615 Bitmap *deco_bitmap = None;
2616 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
2617 struct GadgetInfo *gi;
2618 unsigned long event_mask;
2619 int gd_xoffset, gd_yoffset;
2620 int gd_x1, gd_x2, gd_y;
2623 event_mask = GD_EVENT_RELEASED;
2625 gd_xoffset = toolbutton_info[i].xpos;
2626 gd_yoffset = toolbutton_info[i].ypos;
2627 gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
2628 gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
2629 gd_y = DOOR_GFX_PAGEY1 + gd_yoffset;
2631 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
2633 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
2635 getMiniGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr),
2636 &deco_bitmap, &deco_x, &deco_y);
2637 deco_xpos = (toolbutton_info[i].width - MINI_TILEX) / 2;
2638 deco_ypos = (toolbutton_info[i].height - MINI_TILEY) / 2;
2641 gi = CreateGadget(GDI_CUSTOM_ID, id,
2642 GDI_INFO_TEXT, toolbutton_info[i].infotext,
2643 GDI_X, DX + toolbutton_info[i].x,
2644 GDI_Y, DY + toolbutton_info[i].y,
2645 GDI_WIDTH, toolbutton_info[i].width,
2646 GDI_HEIGHT, toolbutton_info[i].height,
2647 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
2648 GDI_STATE, GD_BUTTON_UNPRESSED,
2649 GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
2650 GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
2651 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
2652 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
2653 GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
2654 GDI_DECORATION_SHIFTING, 1, 1,
2655 GDI_EVENT_MASK, event_mask,
2656 GDI_CALLBACK_ACTION, HandleToolButtons,
2660 Error(ERR_EXIT, "cannot create gadget");
2662 tool_gadget[id] = gi;
2666 void FreeToolButtons()
2670 for (i=0; i<NUM_TOOL_BUTTONS; i++)
2671 FreeGadget(tool_gadget[i]);
2674 static void UnmapToolButtons()
2678 for (i=0; i<NUM_TOOL_BUTTONS; i++)
2679 UnmapGadget(tool_gadget[i]);
2682 static void HandleToolButtons(struct GadgetInfo *gi)
2684 request_gadget_id = gi->custom_id;
2687 int get_next_element(int element)
2691 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
2692 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
2693 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
2694 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
2695 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
2696 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
2697 case EL_AMOEBA_DROPPING: return EL_AMOEBA_WET;
2699 default: return element;
2703 int el_act_dir2img(int element, int action, int direction)
2705 element = GFX_ELEMENT(element);
2706 direction = MV_DIR_BIT(direction);
2708 return element_info[element].direction_graphic[action][direction];
2711 static int el_act_dir2crm(int element, int action, int direction)
2713 element = GFX_ELEMENT(element);
2714 direction = MV_DIR_BIT(direction);
2716 return element_info[element].direction_crumbled[action][direction];
2719 int el_act2img(int element, int action)
2721 element = GFX_ELEMENT(element);
2723 return element_info[element].graphic[action];
2726 int el_act2crm(int element, int action)
2728 element = GFX_ELEMENT(element);
2730 return element_info[element].crumbled[action];
2733 int el_dir2img(int element, int direction)
2735 element = GFX_ELEMENT(element);
2737 return el_act_dir2img(element, ACTION_DEFAULT, direction);
2740 int el2img(int element)
2742 element = GFX_ELEMENT(element);
2744 return element_info[element].graphic[ACTION_DEFAULT];
2747 int el2edimg(int element)
2749 element = GFX_ELEMENT(element);
2751 return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
2754 int el2preimg(int element)
2756 element = GFX_ELEMENT(element);
2758 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];