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);
39 static struct GadgetInfo *tool_gadget[NUM_TOOL_BUTTONS];
40 static int request_gadget_id = -1;
42 void SetDrawtoField(int mode)
44 if (mode == DRAW_BUFFERED && setup.soft_scrolling)
55 drawto_field = fieldbuffer;
57 else /* DRAW_DIRECT, DRAW_BACKBUFFER */
68 drawto_field = (mode == DRAW_DIRECT ? window : backbuffer);
72 void RedrawPlayfield(boolean force_redraw, int x, int y, int width, int height)
74 if (game_status == GAME_MODE_PLAYING)
80 width = gfx.sxsize + 2 * TILEX;
81 height = gfx.sysize + 2 * TILEY;
84 if (force_redraw || setup.direct_draw)
87 int x1 = (x - SX) / TILEX, y1 = (y - SY) / TILEY;
88 int x2 = (x - SX + width) / TILEX, y2 = (y - SY + height) / TILEY;
90 if (setup.direct_draw)
91 SetDrawtoField(DRAW_BACKBUFFER);
93 for(xx=BX1; xx<=BX2; xx++)
94 for(yy=BY1; yy<=BY2; yy++)
95 if (xx >= x1 && xx <= x2 && yy >= y1 && yy <= y2)
96 DrawScreenField(xx, yy);
99 if (setup.direct_draw)
100 SetDrawtoField(DRAW_DIRECT);
103 if (setup.soft_scrolling)
105 int fx = FX, fy = FY;
107 fx += (ScreenMovDir & (MV_LEFT|MV_RIGHT) ? ScreenGfxPos : 0);
108 fy += (ScreenMovDir & (MV_UP|MV_DOWN) ? ScreenGfxPos : 0);
110 BlitBitmap(fieldbuffer, backbuffer, fx,fy, SXSIZE,SYSIZE, SX,SY);
114 BlitBitmap(drawto, window, x, y, width, height, x, y);
120 DrawBuffer *buffer = (drawto_field == window ? backbuffer : drawto_field);
122 if (setup.direct_draw && game_status == GAME_MODE_PLAYING)
123 redraw_mask &= ~REDRAW_MAIN;
125 if (redraw_mask & REDRAW_TILES && redraw_tiles > REDRAWTILES_THRESHOLD)
126 redraw_mask |= REDRAW_FIELD;
128 if (redraw_mask & REDRAW_FIELD)
129 redraw_mask &= ~REDRAW_TILES;
131 if (redraw_mask == REDRAW_NONE)
134 if (global.fps_slowdown && game_status == GAME_MODE_PLAYING)
136 static boolean last_frame_skipped = FALSE;
137 boolean skip_even_when_not_scrolling = TRUE;
138 boolean just_scrolling = (ScreenMovDir != 0);
139 boolean verbose = FALSE;
141 if (global.fps_slowdown_factor > 1 &&
142 (FrameCounter % global.fps_slowdown_factor) &&
143 (just_scrolling || skip_even_when_not_scrolling))
145 redraw_mask &= ~REDRAW_MAIN;
147 last_frame_skipped = TRUE;
150 printf("FRAME SKIPPED\n");
154 if (last_frame_skipped)
155 redraw_mask |= REDRAW_FIELD;
157 last_frame_skipped = FALSE;
160 printf("frame not skipped\n");
164 /* synchronize X11 graphics at this point; if we would synchronize the
165 display immediately after the buffer switching (after the XFlush),
166 this could mean that we have to wait for the graphics to complete,
167 although we could go on doing calculations for the next frame */
171 if (redraw_mask & REDRAW_ALL)
173 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
177 if (redraw_mask & REDRAW_FIELD)
179 if (game_status != GAME_MODE_PLAYING ||
180 redraw_mask & REDRAW_FROM_BACKBUFFER)
182 BlitBitmap(backbuffer, window,
183 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE, REAL_SX, REAL_SY);
187 int fx = FX, fy = FY;
189 if (setup.soft_scrolling)
191 fx += (ScreenMovDir & (MV_LEFT | MV_RIGHT) ? ScreenGfxPos : 0);
192 fy += (ScreenMovDir & (MV_UP | MV_DOWN) ? ScreenGfxPos : 0);
195 if (setup.soft_scrolling ||
196 ABS(ScreenMovPos) + ScrollStepSize == TILEX ||
197 ABS(ScreenMovPos) == ScrollStepSize ||
198 redraw_tiles > REDRAWTILES_THRESHOLD)
200 BlitBitmap(buffer, window, fx, fy, SXSIZE, SYSIZE, SX, SY);
204 printf("redrawing all (ScreenGfxPos == %d) because %s\n",
206 (setup.soft_scrolling ?
207 "setup.soft_scrolling" :
208 ABS(ScreenGfxPos) + ScrollStepSize == TILEX ?
209 "ABS(ScreenGfxPos) + ScrollStepSize == TILEX" :
210 ABS(ScreenGfxPos) == ScrollStepSize ?
211 "ABS(ScreenGfxPos) == ScrollStepSize" :
212 "redraw_tiles > REDRAWTILES_THRESHOLD"));
218 redraw_mask &= ~REDRAW_MAIN;
221 if (redraw_mask & REDRAW_DOORS)
223 if (redraw_mask & REDRAW_DOOR_1)
224 BlitBitmap(backbuffer, window, DX, DY, DXSIZE, DYSIZE, DX, DY);
225 if (redraw_mask & REDRAW_DOOR_2)
227 if ((redraw_mask & REDRAW_DOOR_2) == REDRAW_DOOR_2)
228 BlitBitmap(backbuffer, window, VX,VY, VXSIZE,VYSIZE, VX,VY);
231 if (redraw_mask & REDRAW_VIDEO_1)
232 BlitBitmap(backbuffer, window,
233 VX+VIDEO_DISPLAY1_XPOS,VY+VIDEO_DISPLAY1_YPOS,
234 VIDEO_DISPLAY_XSIZE,VIDEO_DISPLAY_YSIZE,
235 VX+VIDEO_DISPLAY1_XPOS,VY+VIDEO_DISPLAY1_YPOS);
236 if (redraw_mask & REDRAW_VIDEO_2)
237 BlitBitmap(backbuffer, window,
238 VX+VIDEO_DISPLAY2_XPOS,VY+VIDEO_DISPLAY2_YPOS,
239 VIDEO_DISPLAY_XSIZE,VIDEO_DISPLAY_YSIZE,
240 VX+VIDEO_DISPLAY2_XPOS,VY+VIDEO_DISPLAY2_YPOS);
241 if (redraw_mask & REDRAW_VIDEO_3)
242 BlitBitmap(backbuffer, window,
243 VX+VIDEO_CONTROL_XPOS,VY+VIDEO_CONTROL_YPOS,
244 VIDEO_CONTROL_XSIZE,VIDEO_CONTROL_YSIZE,
245 VX+VIDEO_CONTROL_XPOS,VY+VIDEO_CONTROL_YPOS);
249 if (redraw_mask & REDRAW_DOOR_3)
250 BlitBitmap(backbuffer, window, EX, EY, EXSIZE, EYSIZE, EX, EY);
252 redraw_mask &= ~REDRAW_DOORS;
255 if (redraw_mask & REDRAW_MICROLEVEL)
257 BlitBitmap(backbuffer, window, SX, SY + 10 * TILEY, SXSIZE, 7 * TILEY,
258 SX, SY + 10 * TILEY);
260 redraw_mask &= ~REDRAW_MICROLEVEL;
263 if (redraw_mask & REDRAW_TILES)
265 for(x=0; x<SCR_FIELDX; x++)
266 for(y=0; y<SCR_FIELDY; y++)
267 if (redraw[redraw_x1 + x][redraw_y1 + y])
268 BlitBitmap(buffer, window,
269 FX + x * TILEX, FX + y * TILEY, TILEX, TILEY,
270 SX + x * TILEX, SY + y * TILEY);
273 if (redraw_mask & REDRAW_FPS) /* display frames per second */
278 sprintf(info1, " (only every %d. frame)", global.fps_slowdown_factor);
279 if (!global.fps_slowdown)
282 sprintf(text, "%.1f fps%s", global.frames_per_second, info1);
283 DrawTextExt(window, SX, SY, text, FONT_TEXT_2, BLIT_OPAQUE);
288 for(x=0; x<MAX_BUF_XSIZE; x++)
289 for(y=0; y<MAX_BUF_YSIZE; y++)
292 redraw_mask = REDRAW_NONE;
298 long fading_delay = 300;
300 if (setup.fading && (redraw_mask & REDRAW_FIELD))
307 ClearRectangle(window, REAL_SX,REAL_SY,FULL_SXSIZE,FULL_SYSIZE);
310 for(i=0;i<2*FULL_SYSIZE;i++)
312 for(y=0;y<FULL_SYSIZE;y++)
314 BlitBitmap(backbuffer, window,
315 REAL_SX,REAL_SY+i, FULL_SXSIZE,1, REAL_SX,REAL_SY+i);
323 for(i=1;i<FULL_SYSIZE;i+=2)
324 BlitBitmap(backbuffer, window,
325 REAL_SX,REAL_SY+i, FULL_SXSIZE,1, REAL_SX,REAL_SY+i);
331 SetClipOrigin(clip_gc[PIX_FADEMASK], 0, 0);
332 BlitBitmapMasked(backbuffer, window,
333 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
338 SetClipOrigin(clip_gc[PIX_FADEMASK], -1, -1);
339 BlitBitmapMasked(backbuffer, window,
340 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
345 SetClipOrigin(clip_gc[PIX_FADEMASK], 0, -1);
346 BlitBitmapMasked(backbuffer, window,
347 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
352 SetClipOrigin(clip_gc[PIX_FADEMASK], -1, 0);
353 BlitBitmapMasked(backbuffer, window,
354 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
359 redraw_mask &= ~REDRAW_MAIN;
366 void SetMainBackgroundImage(int graphic)
368 SetMainBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
369 graphic_info[graphic].bitmap ?
370 graphic_info[graphic].bitmap :
371 graphic_info[IMG_BACKGROUND].bitmap);
374 void SetDoorBackgroundImage(int graphic)
376 SetDoorBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
377 graphic_info[graphic].bitmap ?
378 graphic_info[graphic].bitmap :
379 graphic_info[IMG_BACKGROUND].bitmap);
382 void DrawBackground(int dest_x, int dest_y, int width, int height)
384 ClearRectangleOnBackground(backbuffer, dest_x, dest_y, width, height);
386 redraw_mask |= REDRAW_FIELD;
391 DrawBackground(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
393 if (setup.soft_scrolling && game_status == GAME_MODE_PLAYING)
395 ClearRectangle(fieldbuffer, 0, 0, FXSIZE, FYSIZE);
396 SetDrawtoField(DRAW_BUFFERED);
399 SetDrawtoField(DRAW_BACKBUFFER);
401 if (setup.direct_draw && game_status == GAME_MODE_PLAYING)
403 ClearRectangle(window, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
404 SetDrawtoField(DRAW_DIRECT);
408 void MarkTileDirty(int x, int y)
410 int xx = redraw_x1 + x;
411 int yy = redraw_y1 + y;
416 redraw[xx][yy] = TRUE;
417 redraw_mask |= REDRAW_TILES;
420 void SetBorderElement()
424 BorderElement = EL_EMPTY;
426 for(y=0; y<lev_fieldy && BorderElement == EL_EMPTY; y++)
428 for(x=0; x<lev_fieldx; x++)
430 if (!IS_INDESTRUCTIBLE(Feld[x][y]))
431 BorderElement = EL_STEELWALL;
433 if (y != 0 && y != lev_fieldy - 1 && x != lev_fieldx - 1)
439 void SetRandomAnimationValue(int x, int y)
441 gfx.anim_random_frame = GfxRandom[x][y];
444 inline int getGraphicAnimationFrame(int graphic, int sync_frame)
446 /* animation synchronized with global frame counter, not move position */
447 if (graphic_info[graphic].anim_global_sync || sync_frame < 0)
448 sync_frame = FrameCounter;
450 return getAnimationFrame(graphic_info[graphic].anim_frames,
451 graphic_info[graphic].anim_delay,
452 graphic_info[graphic].anim_mode,
453 graphic_info[graphic].anim_start_frame,
457 inline void DrawGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
458 int graphic, int sync_frame, int mask_mode)
460 int frame = getGraphicAnimationFrame(graphic, sync_frame);
462 if (mask_mode == USE_MASKING)
463 DrawGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
465 DrawGraphicExt(dst_bitmap, x, y, graphic, frame);
468 inline void DrawGraphicAnimation(int x, int y, int graphic)
470 int lx = LEVELX(x), ly = LEVELY(y);
472 if (!IN_SCR_FIELD(x, y))
475 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
476 graphic, GfxFrame[lx][ly], NO_MASKING);
480 void DrawLevelGraphicAnimation(int x, int y, int graphic)
482 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
485 void DrawLevelElementAnimation(int x, int y, int element)
488 int graphic = el_act_dir2img(element, GfxAction[x][y], MovDir[x][y]);
490 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
492 DrawGraphicAnimation(SCREENX(x), SCREENY(y), el2img(element));
496 inline void DrawLevelGraphicAnimationIfNeeded(int x, int y, int graphic)
498 int sx = SCREENX(x), sy = SCREENY(y);
500 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
503 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
506 DrawGraphicAnimation(sx, sy, graphic);
508 if (CAN_BE_CRUMBLED(Feld[x][y]))
509 DrawLevelFieldCrumbledSand(x, y);
512 void DrawLevelElementAnimationIfNeeded(int x, int y, int element)
514 int sx = SCREENX(x), sy = SCREENY(y);
517 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
520 graphic = el_act_dir2img(element, GfxAction[x][y], MovDir[x][y]);
522 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
525 DrawGraphicAnimation(sx, sy, graphic);
527 if (CAN_BE_CRUMBLED(element))
528 DrawLevelFieldCrumbledSand(x, y);
531 void DrawAllPlayers()
535 for(i=0; i<MAX_PLAYERS; i++)
536 if (stored_player[i].active)
537 DrawPlayer(&stored_player[i]);
540 void DrawPlayerField(int x, int y)
542 if (!IS_PLAYER(x, y))
545 DrawPlayer(PLAYERINFO(x, y));
548 void DrawPlayer(struct PlayerInfo *player)
551 int jx = player->jx, jy = player->jy;
552 int last_jx = player->last_jx, last_jy = player->last_jy;
553 int next_jx = jx + (jx - last_jx), next_jy = jy + (jy - last_jy);
554 int sx = SCREENX(jx), sy = SCREENY(jy);
555 int sxx = 0, syy = 0;
556 int element = Feld[jx][jy], last_element = Feld[last_jx][last_jy];
559 boolean player_is_moving = (last_jx != jx || last_jy != jy ? TRUE : FALSE);
560 int move_dir = player->MovDir;
561 int action = ACTION_DEFAULT;
563 int jx = player->jx, jy = player->jy;
564 int move_dir = player->MovDir;
565 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? +1 : 0);
566 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? +1 : 0);
567 int last_jx = (player->is_moving ? jx - dx : jx);
568 int last_jy = (player->is_moving ? jy - dy : jy);
569 int next_jx = jx + dx;
570 int next_jy = jy + dy;
571 int sx = SCREENX(jx), sy = SCREENY(jy);
572 int sxx = 0, syy = 0;
573 int element = Feld[jx][jy], last_element = Feld[last_jx][last_jy];
576 boolean player_is_moving = (player->MovPos ? TRUE : FALSE);
577 int action = ACTION_DEFAULT;
580 if (!player->active || !IN_SCR_FIELD(SCREENX(last_jx), SCREENY(last_jy)))
584 if (!IN_LEV_FIELD(jx,jy))
586 printf("DrawPlayerField(): x = %d, y = %d\n",jx,jy);
587 printf("DrawPlayerField(): sx = %d, sy = %d\n",sx,sy);
588 printf("DrawPlayerField(): This should never happen!\n");
593 if (element == EL_EXPLOSION)
596 action = (player->Pushing ? ACTION_PUSHING :
597 player->is_digging ? ACTION_DIGGING :
598 player->is_collecting ? ACTION_COLLECTING :
599 player->is_moving ? ACTION_MOVING :
600 player->snapped ? ACTION_SNAPPING : ACTION_DEFAULT);
603 printf("::: '%s'\n", element_action_info[action].suffix);
606 InitPlayerGfxAnimation(player, action, move_dir);
608 /* ----------------------------------------------------------------------- */
609 /* draw things in the field the player is leaving, if needed */
610 /* ----------------------------------------------------------------------- */
613 if (player->is_moving)
615 if (player_is_moving)
618 if (Back[last_jx][last_jy] && IS_DRAWABLE(last_element))
620 DrawLevelElement(last_jx, last_jy, Back[last_jx][last_jy]);
622 if (last_element == EL_DYNAMITE_ACTIVE ||
623 last_element == EL_SP_DISK_RED_ACTIVE)
624 DrawDynamite(last_jx, last_jy);
626 DrawLevelFieldThruMask(last_jx, last_jy);
628 else if (last_element == EL_DYNAMITE_ACTIVE ||
629 last_element == EL_SP_DISK_RED_ACTIVE)
630 DrawDynamite(last_jx, last_jy);
632 DrawLevelField(last_jx, last_jy);
634 if (player->Pushing && IN_SCR_FIELD(SCREENX(next_jx), SCREENY(next_jy)))
638 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
642 if (Feld[next_jx][next_jy] == EL_SOKOBAN_FIELD_FULL)
643 DrawLevelElement(next_jx, next_jy, EL_SOKOBAN_FIELD_EMPTY);
645 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
648 DrawLevelField(next_jx, next_jy);
654 if (!IN_SCR_FIELD(sx, sy))
657 if (setup.direct_draw)
658 SetDrawtoField(DRAW_BUFFERED);
660 /* ----------------------------------------------------------------------- */
661 /* draw things behind the player, if needed */
662 /* ----------------------------------------------------------------------- */
665 DrawLevelElement(jx, jy, Back[jx][jy]);
666 else if (IS_ACTIVE_BOMB(element))
667 DrawLevelElement(jx, jy, EL_EMPTY);
670 if (player_is_moving && GfxElement[jx][jy] != EL_UNDEFINED)
673 if (CAN_BE_CRUMBLED(GfxElement[jx][jy]))
674 DrawLevelFieldCrumbledSandDigging(jx, jy, move_dir, player->StepFrame);
676 if (GfxElement[jx][jy] == EL_SAND)
677 DrawLevelFieldCrumbledSandDigging(jx, jy, move_dir, player->StepFrame);
681 int old_element = GfxElement[jx][jy];
682 int old_graphic = el_act_dir2img(old_element, action, move_dir);
683 int frame = getGraphicAnimationFrame(old_graphic, player->StepFrame);
685 DrawGraphic(sx, sy, old_graphic, frame);
690 GfxElement[jx][jy] = EL_UNDEFINED;
692 DrawLevelField(jx, jy);
696 /* ----------------------------------------------------------------------- */
697 /* draw player himself */
698 /* ----------------------------------------------------------------------- */
700 if (player->use_murphy_graphic)
702 static int last_horizontal_dir = MV_LEFT;
705 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
706 last_horizontal_dir = move_dir;
708 direction = (player->snapped ? move_dir : last_horizontal_dir);
710 graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, direction);
713 graphic = el_act_dir2img(player->element_nr, player->GfxAction, move_dir);
715 frame = getGraphicAnimationFrame(graphic, player->Frame);
719 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
720 sxx = player->GfxPos;
722 syy = player->GfxPos;
725 if (!setup.soft_scrolling && ScreenMovPos)
728 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
730 if (SHIELD_ON(player))
732 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
733 IMG_SHIELD_NORMAL_ACTIVE);
734 int frame = getGraphicAnimationFrame(graphic, -1);
736 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
739 /* ----------------------------------------------------------------------- */
740 /* draw things the player is pushing, if needed */
741 /* ----------------------------------------------------------------------- */
744 printf("::: %d, %d [%d, %d] [%d]\n",
745 player->Pushing, player_is_moving, player->GfxAction,
746 player->is_moving, player_is_moving);
750 if (player->Pushing && player->is_moving)
752 if (player->Pushing && player_is_moving)
755 int px = SCREENX(next_jx), py = SCREENY(next_jy);
757 if (Back[next_jx][next_jy])
758 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
761 if ((sxx || syy) && element == EL_SOKOBAN_OBJECT)
762 DrawGraphicShiftedThruMask(px, py, sxx, syy, IMG_SOKOBAN_OBJECT, 0,
766 (element == EL_SOKOBAN_FIELD_EMPTY ||
767 Feld[next_jx][next_jy] == EL_SOKOBAN_FIELD_FULL))
768 DrawGraphicShiftedThruMask(px, py, sxx, syy, IMG_SOKOBAN_OBJECT, 0,
774 int element = MovingOrBlocked2Element(next_jx, next_jy);
777 int element = Feld[jx][jy];
779 int element = Feld[next_jx][next_jy];
784 int graphic = el2img(element);
788 if ((sxx || syy) && IS_PUSHABLE(element))
791 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
792 frame = getGraphicAnimationFrame(graphic, player->Frame);
796 printf("::: pushing %d: %d ...\n", sxx, frame);
799 DrawGraphicShifted(px, py, sxx, syy, graphic, frame,
800 NO_CUTTING, NO_MASKING);
805 /* ----------------------------------------------------------------------- */
806 /* draw things in front of player (active dynamite or dynabombs) */
807 /* ----------------------------------------------------------------------- */
809 if (IS_ACTIVE_BOMB(element))
811 graphic = el2img(element);
812 frame = getGraphicAnimationFrame(graphic, GfxFrame[jx][jy]);
814 if (game.emulation == EMU_SUPAPLEX)
815 DrawGraphic(sx, sy, IMG_SP_DISK_RED, frame);
817 DrawGraphicThruMask(sx, sy, graphic, frame);
820 if (player_is_moving && last_element == EL_EXPLOSION)
823 int graphic = el_act2img(GfxElement[last_jx][last_jy], ACTION_EXPLODING);
825 int stored = Store[last_jx][last_jy];
826 int graphic = (game.emulation != EMU_SUPAPLEX ? IMG_EXPLOSION :
827 stored == EL_SP_INFOTRON ? IMG_SP_EXPLOSION_INFOTRON :
830 int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
831 int phase = ExplodePhase[last_jx][last_jy] - 1;
832 int frame = getGraphicAnimationFrame(graphic, phase - delay);
835 DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy), graphic, frame);
838 /* ----------------------------------------------------------------------- */
839 /* draw elements the player is just walking/passing through/under */
840 /* ----------------------------------------------------------------------- */
842 /* handle the field the player is leaving ... */
843 if (player_is_moving && IS_ACCESSIBLE_INSIDE(last_element))
844 DrawLevelField(last_jx, last_jy);
845 else if (player_is_moving && IS_ACCESSIBLE_UNDER(last_element))
846 DrawLevelFieldThruMask(last_jx, last_jy);
848 /* ... and the field the player is entering */
849 if (IS_ACCESSIBLE_INSIDE(element))
850 DrawLevelField(jx, jy);
851 else if (IS_ACCESSIBLE_UNDER(element))
852 DrawLevelFieldThruMask(jx, jy);
854 if (setup.direct_draw)
856 int dest_x = SX + SCREENX(MIN(jx, last_jx)) * TILEX;
857 int dest_y = SY + SCREENY(MIN(jy, last_jy)) * TILEY;
858 int x_size = TILEX * (1 + ABS(jx - last_jx));
859 int y_size = TILEY * (1 + ABS(jy - last_jy));
861 BlitBitmap(drawto_field, window,
862 dest_x, dest_y, x_size, y_size, dest_x, dest_y);
863 SetDrawtoField(DRAW_DIRECT);
866 MarkTileDirty(sx,sy);
869 void getGraphicSource(int graphic, int frame, Bitmap **bitmap, int *x, int *y)
871 struct GraphicInfo *g = &graphic_info[graphic];
875 if (g->offset_y == 0) /* frames are ordered horizontally */
877 int max_width = g->anim_frames_per_line * g->width;
879 *x = (g->src_x + frame * g->offset_x) % max_width;
880 *y = g->src_y + (g->src_x + frame * g->offset_x) / max_width * g->height;
882 else if (g->offset_x == 0) /* frames are ordered vertically */
884 int max_height = g->anim_frames_per_line * g->height;
886 *x = g->src_x + (g->src_y + frame * g->offset_y) / max_height * g->width;
887 *y = (g->src_y + frame * g->offset_y) % max_height;
889 else /* frames are ordered diagonally */
891 *x = g->src_x + frame * g->offset_x;
892 *y = g->src_y + frame * g->offset_y;
896 void DrawGraphic(int x, int y, int graphic, int frame)
899 if (!IN_SCR_FIELD(x, y))
901 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
902 printf("DrawGraphic(): This should never happen!\n");
907 DrawGraphicExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic, frame);
911 void DrawGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
917 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
918 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
921 void DrawGraphicThruMask(int x, int y, int graphic, int frame)
924 if (!IN_SCR_FIELD(x, y))
926 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
927 printf("DrawGraphicThruMask(): This should never happen!\n");
932 DrawGraphicThruMaskExt(drawto_field, FX + x * TILEX, FY + y *TILEY, graphic,
937 void DrawGraphicThruMaskExt(DrawBuffer *d, int dest_x, int dest_y, int graphic,
945 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
946 drawing_gc = src_bitmap->stored_clip_gc;
948 GC drawing_gc = src_bitmap->stored_clip_gc;
949 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
950 int src_x = graphic_info[graphic].src_x;
951 int src_y = graphic_info[graphic].src_y;
952 int offset_x = graphic_info[graphic].offset_x;
953 int offset_y = graphic_info[graphic].offset_y;
955 src_x += frame * offset_x;
956 src_y += frame * offset_y;
960 SetClipOrigin(src_bitmap, drawing_gc, dest_x - src_x, dest_y - src_y);
961 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX, TILEY, dest_x, dest_y);
964 void DrawMiniGraphic(int x, int y, int graphic)
966 DrawMiniGraphicExt(drawto, SX + x * MINI_TILEX,SY + y * MINI_TILEY, graphic);
967 MarkTileDirty(x / 2, y / 2);
970 void getMiniGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
972 struct GraphicInfo *g = &graphic_info[graphic];
974 int mini_starty = g->bitmap->height * 2 / 3;
977 *x = mini_startx + g->src_x / 2;
978 *y = mini_starty + g->src_y / 2;
981 void DrawMiniGraphicExt(DrawBuffer *d, int x, int y, int graphic)
986 getMiniGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
987 BlitBitmap(src_bitmap, d, src_x, src_y, MINI_TILEX, MINI_TILEY, x, y);
990 void DrawGraphicShifted(int x,int y, int dx,int dy, int graphic, int frame,
991 int cut_mode, int mask_mode)
996 int width = TILEX, height = TILEY;
1002 DrawGraphic(x, y, graphic, frame);
1006 if (dx || dy) /* shifted graphic */
1008 if (x < BX1) /* object enters playfield from the left */
1015 else if (x > BX2) /* object enters playfield from the right */
1021 else if (x==BX1 && dx < 0) /* object leaves playfield to the left */
1027 else if (x==BX2 && dx > 0) /* object leaves playfield to the right */
1029 else if (dx) /* general horizontal movement */
1030 MarkTileDirty(x + SIGN(dx), y);
1032 if (y < BY1) /* object enters playfield from the top */
1034 if (cut_mode==CUT_BELOW) /* object completely above top border */
1042 else if (y > BY2) /* object enters playfield from the bottom */
1048 else if (y==BY1 && dy < 0) /* object leaves playfield to the top */
1054 else if (dy > 0 && cut_mode == CUT_ABOVE)
1056 if (y == BY2) /* object completely above bottom border */
1062 MarkTileDirty(x, y + 1);
1063 } /* object leaves playfield to the bottom */
1064 else if (dy > 0 && (y == BY2 || cut_mode == CUT_BELOW))
1066 else if (dy) /* general vertical movement */
1067 MarkTileDirty(x, y + SIGN(dy));
1071 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1073 src_bitmap = graphic_info[graphic].bitmap;
1074 src_x = graphic_info[graphic].src_x;
1075 src_y = graphic_info[graphic].src_y;
1076 offset_x = graphic_info[graphic].offset_x;
1077 offset_y = graphic_info[graphic].offset_y;
1079 src_x += frame * offset_x;
1080 src_y += frame * offset_y;
1083 drawing_gc = src_bitmap->stored_clip_gc;
1088 dest_x = FX + x * TILEX + dx;
1089 dest_y = FY + y * TILEY + dy;
1092 if (!IN_SCR_FIELD(x,y))
1094 printf("DrawGraphicShifted(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
1095 printf("DrawGraphicShifted(): This should never happen!\n");
1100 if (mask_mode == USE_MASKING)
1102 SetClipOrigin(src_bitmap, drawing_gc, dest_x - src_x, dest_y - src_y);
1103 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1107 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1113 void DrawGraphicShiftedThruMask(int x, int y, int dx, int dy, int graphic,
1114 int frame, int cut_mode)
1116 DrawGraphicShifted(x,y, dx,dy, graphic, frame, cut_mode, USE_MASKING);
1119 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
1120 int cut_mode, int mask_mode)
1122 int lx = LEVELX(x), ly = LEVELY(y);
1126 if (IN_LEV_FIELD(lx, ly))
1128 SetRandomAnimationValue(lx, ly);
1130 graphic = el_act_dir2img(element, GfxAction[lx][ly], MovDir[lx][ly]);
1131 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1133 else /* border element */
1135 graphic = el2img(element);
1136 frame = getGraphicAnimationFrame(graphic, -1);
1139 if (element == EL_EXPANDABLE_WALL)
1141 boolean left_stopped = FALSE, right_stopped = FALSE;
1143 if (!IN_LEV_FIELD(lx - 1, ly) || IS_WALL(Feld[lx - 1][ly]))
1144 left_stopped = TRUE;
1145 if (!IN_LEV_FIELD(lx + 1, ly) || IS_WALL(Feld[lx + 1][ly]))
1146 right_stopped = TRUE;
1148 if (left_stopped && right_stopped)
1150 else if (left_stopped)
1152 graphic = IMG_EXPANDABLE_WALL_GROWING_RIGHT;
1153 frame = graphic_info[graphic].anim_frames - 1;
1155 else if (right_stopped)
1157 graphic = IMG_EXPANDABLE_WALL_GROWING_LEFT;
1158 frame = graphic_info[graphic].anim_frames - 1;
1163 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, mask_mode);
1164 else if (mask_mode == USE_MASKING)
1165 DrawGraphicThruMask(x, y, graphic, frame);
1167 DrawGraphic(x, y, graphic, frame);
1170 void DrawLevelElementExt(int x, int y, int dx, int dy, int element,
1171 int cut_mode, int mask_mode)
1173 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1174 DrawScreenElementExt(SCREENX(x), SCREENY(y), dx, dy, element,
1175 cut_mode, mask_mode);
1178 void DrawScreenElementShifted(int x, int y, int dx, int dy, int element,
1181 DrawScreenElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1184 void DrawLevelElementShifted(int x, int y, int dx, int dy, int element,
1187 DrawLevelElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1190 void DrawLevelElementThruMask(int x, int y, int element)
1192 DrawLevelElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1195 void DrawLevelFieldThruMask(int x, int y)
1197 DrawLevelElementExt(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
1200 static void DrawLevelFieldCrumbledSandExt(int x, int y, int graphic, int frame)
1204 int sx = SCREENX(x), sy = SCREENY(y);
1206 int width, height, cx, cy, i;
1208 int crumbled_border_size = graphic_info[graphic].border_size;
1210 int snip = TILEX / 8; /* number of border pixels from "crumbled graphic" */
1212 static int xy[4][2] =
1220 if (!IN_LEV_FIELD(x, y))
1223 element = (GfxElement[x][y] != EL_UNDEFINED && Feld[x][y] != EL_EXPLOSION ?
1224 GfxElement[x][y] : Feld[x][y]);
1226 /* crumble field itself */
1227 if (CAN_BE_CRUMBLED(element) && !IS_MOVING(x, y))
1229 if (!IN_SCR_FIELD(sx, sy))
1232 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1236 int xx = x + xy[i][0];
1237 int yy = y + xy[i][1];
1239 element = (IN_LEV_FIELD(xx, yy) ? Feld[xx][yy] : BorderElement);
1241 /* check if neighbour field is of same type */
1242 if (CAN_BE_CRUMBLED(element) && !IS_MOVING(xx, yy))
1246 if (Feld[x][y] == EL_CUSTOM_START + 123)
1247 printf("::: crumble [%d] THE CHAOS ENGINE (%d, %d): %d, %d\n",
1248 i, Feld[x][y], element,
1249 CAN_BE_CRUMBLED(element), IS_MOVING(x, y));
1252 if (i == 1 || i == 2)
1254 width = crumbled_border_size;
1256 cx = (i == 2 ? TILEX - crumbled_border_size : 0);
1262 height = crumbled_border_size;
1264 cy = (i == 3 ? TILEY - crumbled_border_size : 0);
1267 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1268 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
1271 MarkTileDirty(sx, sy);
1273 else /* crumble neighbour fields */
1275 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1279 int xx = x + xy[i][0];
1280 int yy = y + xy[i][1];
1281 int sxx = sx + xy[i][0];
1282 int syy = sy + xy[i][1];
1284 if (!IN_LEV_FIELD(xx, yy) ||
1285 !IN_SCR_FIELD(sxx, syy) ||
1286 !CAN_BE_CRUMBLED(Feld[xx][yy]) ||
1290 if (i == 1 || i == 2)
1292 width = crumbled_border_size;
1294 cx = (i == 1 ? TILEX - crumbled_border_size : 0);
1300 height = crumbled_border_size;
1302 cy = (i == 0 ? TILEY - crumbled_border_size : 0);
1305 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1306 width, height, FX + sxx * TILEX + cx, FY + syy * TILEY + cy);
1308 MarkTileDirty(sxx, syy);
1313 void DrawLevelFieldCrumbledSand(int x, int y)
1315 DrawLevelFieldCrumbledSandExt(x, y, IMG_SAND_CRUMBLED, 0);
1318 void DrawLevelFieldCrumbledSandDigging(int x, int y, int direction,
1322 int graphic1 = el_act_dir2img(GfxElement[x][y], ACTION_DIGGING, direction);
1323 int graphic2 = el_act_dir2crm(GfxElement[x][y], ACTION_DIGGING, direction);
1325 int graphic1 = el_act_dir2img(EL_SAND, ACTION_DIGGING, direction);
1326 int graphic2 = el_act_dir2img(EL_SAND_CRUMBLED, ACTION_DIGGING, direction);
1328 int frame1 = getGraphicAnimationFrame(graphic1, step_frame);
1329 int frame2 = getGraphicAnimationFrame(graphic2, step_frame);
1330 int sx = SCREENX(x), sy = SCREENY(y);
1332 DrawGraphic(sx, sy, graphic1, frame1);
1333 DrawLevelFieldCrumbledSandExt(x, y, graphic2, frame2);
1336 void DrawLevelFieldCrumbledSandNeighbours(int x, int y)
1338 int sx = SCREENX(x), sy = SCREENY(y);
1339 static int xy[4][2] =
1350 int xx = x + xy[i][0];
1351 int yy = y + xy[i][1];
1352 int sxx = sx + xy[i][0];
1353 int syy = sy + xy[i][1];
1355 if (!IN_LEV_FIELD(xx, yy) ||
1356 !IN_SCR_FIELD(sxx, syy) ||
1357 !CAN_BE_CRUMBLED(Feld[xx][yy]) ||
1361 DrawLevelField(xx, yy);
1365 static int getBorderElement(int x, int y)
1369 { EL_STEELWALL_TOPLEFT, EL_INVISIBLE_STEELWALL_TOPLEFT },
1370 { EL_STEELWALL_TOPRIGHT, EL_INVISIBLE_STEELWALL_TOPRIGHT },
1371 { EL_STEELWALL_BOTTOMLEFT, EL_INVISIBLE_STEELWALL_BOTTOMLEFT },
1372 { EL_STEELWALL_BOTTOMRIGHT, EL_INVISIBLE_STEELWALL_BOTTOMRIGHT },
1373 { EL_STEELWALL_VERTICAL, EL_INVISIBLE_STEELWALL_VERTICAL },
1374 { EL_STEELWALL_HORIZONTAL, EL_INVISIBLE_STEELWALL_HORIZONTAL },
1375 { EL_STEELWALL, EL_INVISIBLE_STEELWALL }
1377 int steel_type = (BorderElement == EL_STEELWALL ? 0 : 1);
1378 int steel_position = (x == -1 && y == -1 ? 0 :
1379 x == lev_fieldx && y == -1 ? 1 :
1380 x == -1 && y == lev_fieldy ? 2 :
1381 x == lev_fieldx && y == lev_fieldy ? 3 :
1382 x == -1 || x == lev_fieldx ? 4 :
1383 y == -1 || y == lev_fieldy ? 5 : 6);
1385 return border[steel_position][steel_type];
1388 void DrawScreenElement(int x, int y, int element)
1390 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
1391 DrawLevelFieldCrumbledSand(LEVELX(x), LEVELY(y));
1394 void DrawLevelElement(int x, int y, int element)
1396 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1397 DrawScreenElement(SCREENX(x), SCREENY(y), element);
1400 void DrawScreenField(int x, int y)
1402 int lx = LEVELX(x), ly = LEVELY(y);
1403 int element, content;
1405 if (!IN_LEV_FIELD(lx, ly))
1407 if (lx < -1 || lx > lev_fieldx || ly < -1 || ly > lev_fieldy)
1410 element = getBorderElement(lx, ly);
1412 DrawScreenElement(x, y, element);
1416 element = Feld[lx][ly];
1417 content = Store[lx][ly];
1419 if (IS_MOVING(lx, ly))
1421 int horiz_move = (MovDir[lx][ly] == MV_LEFT || MovDir[lx][ly] == MV_RIGHT);
1422 boolean cut_mode = NO_CUTTING;
1424 if (element == EL_QUICKSAND_EMPTYING ||
1425 element == EL_MAGIC_WALL_EMPTYING ||
1426 element == EL_BD_MAGIC_WALL_EMPTYING ||
1427 element == EL_AMOEBA_DROPPING)
1428 cut_mode = CUT_ABOVE;
1429 else if (element == EL_QUICKSAND_FILLING ||
1430 element == EL_MAGIC_WALL_FILLING ||
1431 element == EL_BD_MAGIC_WALL_FILLING)
1432 cut_mode = CUT_BELOW;
1434 if (cut_mode == CUT_ABOVE)
1435 DrawScreenElementShifted(x, y, 0, 0, element, NO_CUTTING);
1437 DrawScreenElement(x, y, EL_EMPTY);
1440 DrawScreenElementShifted(x, y, MovPos[lx][ly], 0, element, NO_CUTTING);
1441 else if (cut_mode == NO_CUTTING)
1442 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], element, cut_mode);
1444 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], content, cut_mode);
1446 if (content == EL_ACID)
1447 DrawLevelElementThruMask(lx, ly + 1, EL_ACID);
1449 else if (IS_BLOCKED(lx, ly))
1454 boolean cut_mode = NO_CUTTING;
1455 int element_old, content_old;
1457 Blocked2Moving(lx, ly, &oldx, &oldy);
1460 horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
1461 MovDir[oldx][oldy] == MV_RIGHT);
1463 element_old = Feld[oldx][oldy];
1464 content_old = Store[oldx][oldy];
1466 if (element_old == EL_QUICKSAND_EMPTYING ||
1467 element_old == EL_MAGIC_WALL_EMPTYING ||
1468 element_old == EL_BD_MAGIC_WALL_EMPTYING ||
1469 element_old == EL_AMOEBA_DROPPING)
1470 cut_mode = CUT_ABOVE;
1472 DrawScreenElement(x, y, EL_EMPTY);
1475 DrawScreenElementShifted(sx, sy, MovPos[oldx][oldy], 0, element_old,
1477 else if (cut_mode == NO_CUTTING)
1478 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], element_old,
1481 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], content_old,
1484 else if (IS_DRAWABLE(element))
1485 DrawScreenElement(x, y, element);
1487 DrawScreenElement(x, y, EL_EMPTY);
1490 void DrawLevelField(int x, int y)
1492 if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1493 DrawScreenField(SCREENX(x), SCREENY(y));
1494 else if (IS_MOVING(x, y))
1498 Moving2Blocked(x, y, &newx, &newy);
1499 if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
1500 DrawScreenField(SCREENX(newx), SCREENY(newy));
1502 else if (IS_BLOCKED(x, y))
1506 Blocked2Moving(x, y, &oldx, &oldy);
1507 if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
1508 DrawScreenField(SCREENX(oldx), SCREENY(oldy));
1512 void DrawMiniElement(int x, int y, int element)
1516 graphic = el2edimg(element);
1517 DrawMiniGraphic(x, y, graphic);
1520 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
1522 int x = sx + scroll_x, y = sy + scroll_y;
1524 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
1525 DrawMiniElement(sx, sy, EL_EMPTY);
1526 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
1527 DrawMiniElement(sx, sy, Feld[x][y]);
1529 DrawMiniGraphic(sx, sy, el2edimg(getBorderElement(x, y)));
1533 void DrawEnvelopeBackground(int startx, int starty, int x, int y,
1534 int xsize, int ysize, int font_nr)
1536 int font_width = getFontWidth(font_nr);
1537 int font_height = getFontHeight(font_nr);
1538 int graphic = IMG_GAME_ENVELOPE_BACKGROUND;
1541 int dst_x = SX + startx + x * font_width;
1542 int dst_y = SY + starty + y * font_height;
1543 int width = graphic_info[graphic].width;
1544 int height = graphic_info[graphic].height;
1545 int inner_width = MAX(width - 2 * font_width, font_width);
1546 int inner_height = MAX(height - 2 * font_height, font_height);
1547 int inner_sx = (width >= 3 * font_width ? font_width : 0);
1548 int inner_sy = (height >= 3 * font_height ? font_height : 0);
1549 boolean draw_masked = graphic_info[graphic].draw_masked;
1551 getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
1553 if (src_bitmap == NULL || width < font_width || height < font_height)
1555 ClearRectangle(drawto, dst_x, dst_y, font_width, font_height);
1559 src_x += (x == 0 ? 0 : x == xsize - 1 ? width - font_width :
1560 inner_sx + (x - 1) * font_width % inner_width);
1561 src_y += (y == 0 ? 0 : y == ysize - 1 ? height - font_height :
1562 inner_sy + (y - 1) * font_height % inner_height);
1566 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1567 dst_x - src_x, dst_y - src_y);
1568 BlitBitmapMasked(src_bitmap, drawto, src_x, src_y, font_width, font_height,
1572 BlitBitmap(src_bitmap, drawto, src_x, src_y, font_width, font_height,
1578 void DrawEnvelopeBackground(int dst_x, int dst_y, int ex, int ey, int font_nr)
1580 int font_width = getFontWidth(font_nr);
1581 int font_height = getFontHeight(font_nr);
1582 int graphic = IMG_GAME_ENVELOPE_BACKGROUND;
1585 int width = graphic_info[graphic].width;
1586 int height = graphic_info[graphic].height;
1587 boolean draw_masked = graphic_info[graphic].draw_masked;
1589 getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
1591 if (src_bitmap == NULL)
1593 ClearRectangle(drawto, dst_x, dst_y, font_width, font_height);
1597 src_x += (ex == -1 ? 0 : ex == +1 ? width - font_width : font_width);
1598 src_y += (ey == -1 ? 0 : ey == +1 ? height - font_height : font_height);
1602 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1603 dst_x - src_x, dst_y - src_y);
1604 BlitBitmapMasked(src_bitmap, drawto, src_x, src_y, font_width, font_height,
1608 BlitBitmap(src_bitmap, drawto, src_x, src_y, font_width, font_height,
1615 int graphic = IMG_GAME_ENVELOPE_BACKGROUND;
1616 boolean draw_masked = graphic_info[graphic].draw_masked;
1617 int mask_mode = (draw_masked ? BLIT_MASKED : BLIT_ON_BACKGROUND);
1618 int font_nr = FONT_TEXT_1;
1619 int font_width = getFontWidth(font_nr);
1620 int font_height = getFontHeight(font_nr);
1621 boolean ffwd_delay = (tape.playing && tape.fast_forward);
1622 int anim_delay = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
1623 int wait_delay = (ffwd_delay ? 500 : 1000);
1626 /* open envelope window horizontally */
1627 for (i = 0; i <= level.envelope_xsize; i++)
1631 int startx = (SXSIZE - xsize * font_width) / 2;
1632 int starty = (SYSIZE - ysize * font_height) / 2;
1634 SetDrawtoField(DRAW_BUFFERED);
1636 BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
1638 SetDrawtoField(DRAW_BACKBUFFER);
1641 for (y=0; y < ysize; y++) for (x=0; x < xsize; x++)
1642 DrawEnvelopeBackground(startx, starty, x, y, xsize, ysize, font_nr);
1644 for (y=0; y < ysize; y++) for (x=0; x < xsize; x++)
1646 int sx = SX + startx + x * font_width;
1647 int sy = SY + starty + y * font_height;
1648 int ex = (x == 0 ? -1 : x == xsize - 1 ? +1 : 0);
1649 int ey = (y == 0 ? -1 : y == ysize - 1 ? +1 : 0);
1651 DrawEnvelopeBackground(sx, sy, ex, ey, font_nr);
1655 redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
1661 /* open envelope window vertically */
1662 for (i = 0; i <= level.envelope_ysize; i++)
1664 int xsize = level.envelope_xsize + 2;
1666 int startx = (SXSIZE - xsize * font_width) / 2;
1667 int starty = (SYSIZE - ysize * font_height) / 2;
1669 SetDrawtoField(DRAW_BUFFERED);
1671 BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
1673 SetDrawtoField(DRAW_BACKBUFFER);
1676 for (y=0; y < ysize; y++) for (x=0; x < xsize; x++)
1677 DrawEnvelopeBackground(startx, starty, x, y, xsize, ysize, font_nr);
1679 for (y=0; y < ysize; y++) for (x=0; x < xsize; x++)
1681 int sx = SX + startx + x * font_width;
1682 int sy = SY + starty + y * font_height;
1683 int ex = (x == 0 ? -1 : x == xsize - 1 ? +1 : 0);
1684 int ey = (y == 0 ? -1 : y == ysize - 1 ? +1 : 0);
1686 DrawEnvelopeBackground(sx, sy, ex, ey, font_nr);
1690 DrawTextToTextArea(SX + startx + font_width,
1691 SY + starty + font_height, level.envelope,
1692 FONT_TEXT_1, level.envelope_xsize, i, mask_mode);
1694 redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
1703 WaitForEventToContinue();
1705 /* close envelope window vertically */
1706 for (i = level.envelope_ysize; i >= 0; i--)
1708 int xsize = level.envelope_xsize + 2;
1710 int startx = (SXSIZE - xsize * font_width) / 2;
1711 int starty = (SYSIZE - ysize * font_height) / 2;
1713 SetDrawtoField(DRAW_BUFFERED);
1715 BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
1717 SetDrawtoField(DRAW_BACKBUFFER);
1720 for (y=0; y < ysize; y++) for (x=0; x < xsize; x++)
1721 DrawEnvelopeBackground(startx, starty, x, y, xsize, ysize, font_nr);
1723 for (y=0; y < ysize; y++) for (x=0; x < xsize; x++)
1725 int sx = SX + startx + x * font_width;
1726 int sy = SY + starty + y * font_height;
1727 int ex = (x == 0 ? -1 : x == xsize - 1 ? +1 : 0);
1728 int ey = (y == 0 ? -1 : y == ysize - 1 ? +1 : 0);
1730 DrawEnvelopeBackground(sx, sy, ex, ey, font_nr);
1734 DrawTextToTextArea(SX + startx + font_width,
1735 SY + starty + font_height, level.envelope,
1736 FONT_TEXT_1, level.envelope_xsize, i, mask_mode);
1738 redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
1744 /* close envelope window horizontally */
1745 for (i = level.envelope_xsize; i >= 0; i--)
1749 int startx = (SXSIZE - xsize * font_width) / 2;
1750 int starty = (SYSIZE - ysize * font_height) / 2;
1752 SetDrawtoField(DRAW_BUFFERED);
1754 BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
1756 SetDrawtoField(DRAW_BACKBUFFER);
1759 for (y=0; y < ysize; y++) for (x=0; x < xsize; x++)
1760 DrawEnvelopeBackground(startx, starty, x, y, xsize, ysize, font_nr);
1762 for (y=0; y < ysize; y++) for (x=0; x < xsize; x++)
1764 int sx = SX + startx + x * font_width;
1765 int sy = SY + starty + y * font_height;
1766 int ex = (x == 0 ? -1 : x == xsize - 1 ? +1 : 0);
1767 int ey = (y == 0 ? -1 : y == ysize - 1 ? +1 : 0);
1769 DrawEnvelopeBackground(sx, sy, ex, ey, font_nr);
1773 redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
1779 SetDrawtoField(DRAW_BUFFERED);
1781 redraw_mask |= REDRAW_FIELD;
1785 void getMicroGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
1787 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
1788 int mini_startx = src_bitmap->width * 3 / 4;
1789 int mini_starty = src_bitmap->height * 2 / 3;
1790 int src_x = mini_startx + graphic_info[graphic].src_x / 8;
1791 int src_y = mini_starty + graphic_info[graphic].src_y / 8;
1793 *bitmap = src_bitmap;
1798 void DrawMicroElement(int xpos, int ypos, int element)
1802 int graphic = el2preimg(element);
1804 getMicroGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
1805 BlitBitmap(src_bitmap, drawto, src_x, src_y, MICRO_TILEX, MICRO_TILEY,
1813 SetDrawBackgroundMask(REDRAW_NONE);
1816 for(x=BX1; x<=BX2; x++)
1817 for(y=BY1; y<=BY2; y++)
1818 DrawScreenField(x, y);
1820 redraw_mask |= REDRAW_FIELD;
1823 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
1827 for(x=0; x<size_x; x++)
1828 for(y=0; y<size_y; y++)
1829 DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
1831 redraw_mask |= REDRAW_FIELD;
1834 static void DrawMicroLevelExt(int xpos, int ypos, int from_x, int from_y)
1838 DrawBackground(xpos, ypos, MICROLEV_XSIZE, MICROLEV_YSIZE);
1840 if (lev_fieldx < STD_LEV_FIELDX)
1841 xpos += (STD_LEV_FIELDX - lev_fieldx) / 2 * MICRO_TILEX;
1842 if (lev_fieldy < STD_LEV_FIELDY)
1843 ypos += (STD_LEV_FIELDY - lev_fieldy) / 2 * MICRO_TILEY;
1845 xpos += MICRO_TILEX;
1846 ypos += MICRO_TILEY;
1848 for(x=-1; x<=STD_LEV_FIELDX; x++)
1850 for(y=-1; y<=STD_LEV_FIELDY; y++)
1852 int lx = from_x + x, ly = from_y + y;
1854 if (lx >= 0 && lx < lev_fieldx && ly >= 0 && ly < lev_fieldy)
1855 DrawMicroElement(xpos + x * MICRO_TILEX, ypos + y * MICRO_TILEY,
1856 level.field[lx][ly]);
1857 else if (lx >= -1 && lx < lev_fieldx+1 && ly >= -1 && ly < lev_fieldy+1
1858 && BorderElement != EL_EMPTY)
1859 DrawMicroElement(xpos + x * MICRO_TILEX, ypos + y * MICRO_TILEY,
1860 getBorderElement(lx, ly));
1864 redraw_mask |= REDRAW_MICROLEVEL;
1867 #define MICROLABEL_EMPTY 0
1868 #define MICROLABEL_LEVEL_NAME 1
1869 #define MICROLABEL_CREATED_BY 2
1870 #define MICROLABEL_LEVEL_AUTHOR 3
1871 #define MICROLABEL_IMPORTED_FROM 4
1872 #define MICROLABEL_LEVEL_IMPORT_INFO 5
1874 static void DrawMicroLevelLabelExt(int mode)
1876 char label_text[MAX_OUTPUT_LINESIZE + 1];
1877 int max_len_label_text;
1878 int font_nr = FONT_TEXT_2;
1880 if (mode == MICROLABEL_CREATED_BY || mode == MICROLABEL_IMPORTED_FROM)
1881 font_nr = FONT_TEXT_3;
1883 max_len_label_text = SXSIZE / getFontWidth(font_nr);
1885 DrawBackground(SX, MICROLABEL_YPOS, SXSIZE, getFontHeight(font_nr));
1887 strncpy(label_text, (mode == MICROLABEL_LEVEL_NAME ? level.name :
1888 mode == MICROLABEL_CREATED_BY ? "created by" :
1889 mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
1890 mode == MICROLABEL_IMPORTED_FROM ? "imported from" :
1891 mode == MICROLABEL_LEVEL_IMPORT_INFO ?
1892 leveldir_current->imported_from : ""),
1893 max_len_label_text);
1894 label_text[max_len_label_text] = '\0';
1896 if (strlen(label_text) > 0)
1898 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
1899 int lypos = MICROLABEL_YPOS;
1901 DrawText(lxpos, lypos, label_text, font_nr);
1904 redraw_mask |= REDRAW_MICROLEVEL;
1907 void DrawMicroLevel(int xpos, int ypos, boolean restart)
1909 static unsigned long scroll_delay = 0;
1910 static unsigned long label_delay = 0;
1911 static int from_x, from_y, scroll_direction;
1912 static int label_state, label_counter;
1913 int last_game_status = game_status; /* save current game status */
1915 /* force PREVIEW font on preview level */
1916 game_status = GAME_MODE_PSEUDO_PREVIEW;
1920 from_x = from_y = 0;
1921 scroll_direction = MV_RIGHT;
1925 DrawMicroLevelExt(xpos, ypos, from_x, from_y);
1926 DrawMicroLevelLabelExt(label_state);
1928 /* initialize delay counters */
1929 DelayReached(&scroll_delay, 0);
1930 DelayReached(&label_delay, 0);
1932 if (leveldir_current->name)
1934 int text_width = getTextWidth(leveldir_current->name, FONT_TEXT_1);
1935 int lxpos = SX + (SXSIZE - text_width) / 2;
1936 int lypos = SY + 352;
1938 DrawText(lxpos, lypos, leveldir_current->name, FONT_TEXT_1);
1941 game_status = last_game_status; /* restore current game status */
1946 /* scroll micro level, if needed */
1947 if ((lev_fieldx > STD_LEV_FIELDX || lev_fieldy > STD_LEV_FIELDY) &&
1948 DelayReached(&scroll_delay, MICROLEVEL_SCROLL_DELAY))
1950 switch (scroll_direction)
1956 scroll_direction = MV_UP;
1960 if (from_x < lev_fieldx - STD_LEV_FIELDX)
1963 scroll_direction = MV_DOWN;
1970 scroll_direction = MV_RIGHT;
1974 if (from_y < lev_fieldy - STD_LEV_FIELDY)
1977 scroll_direction = MV_LEFT;
1984 DrawMicroLevelExt(xpos, ypos, from_x, from_y);
1987 /* redraw micro level label, if needed */
1988 if (strcmp(level.name, NAMELESS_LEVEL_NAME) != 0 &&
1989 strcmp(level.author, ANONYMOUS_NAME) != 0 &&
1990 strcmp(level.author, leveldir_current->name) != 0 &&
1991 DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
1993 int max_label_counter = 23;
1995 if (leveldir_current->imported_from != NULL)
1996 max_label_counter += 14;
1998 label_counter = (label_counter + 1) % max_label_counter;
1999 label_state = (label_counter >= 0 && label_counter <= 7 ?
2000 MICROLABEL_LEVEL_NAME :
2001 label_counter >= 9 && label_counter <= 12 ?
2002 MICROLABEL_CREATED_BY :
2003 label_counter >= 14 && label_counter <= 21 ?
2004 MICROLABEL_LEVEL_AUTHOR :
2005 label_counter >= 23 && label_counter <= 26 ?
2006 MICROLABEL_IMPORTED_FROM :
2007 label_counter >= 28 && label_counter <= 35 ?
2008 MICROLABEL_LEVEL_IMPORT_INFO : MICROLABEL_EMPTY);
2009 DrawMicroLevelLabelExt(label_state);
2012 game_status = last_game_status; /* restore current game status */
2015 void WaitForEventToContinue()
2017 boolean still_wait = TRUE;
2019 /* simulate releasing mouse button over last gadget, if still pressed */
2021 HandleGadgets(-1, -1, 0);
2023 button_status = MB_RELEASED;
2035 case EVENT_BUTTONPRESS:
2036 case EVENT_KEYPRESS:
2040 case EVENT_KEYRELEASE:
2041 ClearPlayerAction();
2045 HandleOtherEvents(&event);
2049 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
2056 /* don't eat all CPU time */
2061 #define MAX_REQUEST_LINES 13
2062 #define MAX_REQUEST_LINE_LEN 7
2064 boolean Request(char *text, unsigned int req_state)
2066 int mx, my, ty, result = -1;
2067 unsigned int old_door_state;
2068 int last_game_status = game_status; /* save current game status */
2071 SetMouseCursor(CURSOR_DEFAULT);
2074 #if defined(PLATFORM_UNIX)
2075 /* pause network game while waiting for request to answer */
2076 if (options.network &&
2077 game_status == GAME_MODE_PLAYING &&
2078 req_state & REQUEST_WAIT_FOR)
2079 SendToServer_PausePlaying();
2082 old_door_state = GetDoorState();
2084 /* simulate releasing mouse button over last gadget, if still pressed */
2086 HandleGadgets(-1, -1, 0);
2090 CloseDoor(DOOR_CLOSE_1);
2092 /* save old door content */
2093 BlitBitmap(bitmap_db_door, bitmap_db_door,
2094 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
2095 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
2097 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
2099 /* clear door drawing field */
2100 DrawBackground(DX, DY, DXSIZE, DYSIZE);
2102 /* force DOOR font on preview level */
2103 game_status = GAME_MODE_PSEUDO_DOOR;
2105 /* write text for request */
2106 for(ty=0; ty < MAX_REQUEST_LINES; ty++)
2108 char text_line[MAX_REQUEST_LINE_LEN + 1];
2114 for(tl=0,tx=0; tx < MAX_REQUEST_LINE_LEN; tl++,tx++)
2117 if (!tc || tc == ' ')
2128 strncpy(text_line, text, tl);
2131 DrawText(DX + (DXSIZE - tl * getFontWidth(FONT_TEXT_2)) / 2,
2132 DY + 8 + ty * (getFontHeight(FONT_TEXT_2) + 2),
2133 text_line, FONT_TEXT_2);
2135 text += tl + (tc == ' ' ? 1 : 0);
2138 game_status = last_game_status; /* restore current game status */
2140 if (req_state & REQ_ASK)
2142 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
2143 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
2145 else if (req_state & REQ_CONFIRM)
2147 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
2149 else if (req_state & REQ_PLAYER)
2151 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
2152 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
2153 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
2154 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
2157 /* copy request gadgets to door backbuffer */
2158 BlitBitmap(drawto, bitmap_db_door,
2159 DX, DY, DXSIZE, DYSIZE,
2160 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2162 OpenDoor(DOOR_OPEN_1);
2168 if (!(req_state & REQUEST_WAIT_FOR))
2170 SetDrawBackgroundMask(REDRAW_FIELD);
2175 if (game_status != GAME_MODE_MAIN)
2178 button_status = MB_RELEASED;
2180 request_gadget_id = -1;
2182 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
2185 SetMouseCursor(CURSOR_DEFAULT);
2198 case EVENT_BUTTONPRESS:
2199 case EVENT_BUTTONRELEASE:
2200 case EVENT_MOTIONNOTIFY:
2202 if (event.type == EVENT_MOTIONNOTIFY)
2204 if (!PointerInWindow(window))
2205 continue; /* window and pointer are on different screens */
2210 motion_status = TRUE;
2211 mx = ((MotionEvent *) &event)->x;
2212 my = ((MotionEvent *) &event)->y;
2216 motion_status = FALSE;
2217 mx = ((ButtonEvent *) &event)->x;
2218 my = ((ButtonEvent *) &event)->y;
2219 if (event.type == EVENT_BUTTONPRESS)
2220 button_status = ((ButtonEvent *) &event)->button;
2222 button_status = MB_RELEASED;
2225 /* this sets 'request_gadget_id' */
2226 HandleGadgets(mx, my, button_status);
2228 switch(request_gadget_id)
2230 case TOOL_CTRL_ID_YES:
2233 case TOOL_CTRL_ID_NO:
2236 case TOOL_CTRL_ID_CONFIRM:
2237 result = TRUE | FALSE;
2240 case TOOL_CTRL_ID_PLAYER_1:
2243 case TOOL_CTRL_ID_PLAYER_2:
2246 case TOOL_CTRL_ID_PLAYER_3:
2249 case TOOL_CTRL_ID_PLAYER_4:
2260 case EVENT_KEYPRESS:
2261 switch(GetEventKey((KeyEvent *)&event, TRUE))
2274 if (req_state & REQ_PLAYER)
2278 case EVENT_KEYRELEASE:
2279 ClearPlayerAction();
2283 HandleOtherEvents(&event);
2287 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
2289 int joy = AnyJoystick();
2291 if (joy & JOY_BUTTON_1)
2293 else if (joy & JOY_BUTTON_2)
2299 /* don't eat all CPU time */
2303 if (game_status != GAME_MODE_MAIN)
2308 if (!(req_state & REQ_STAY_OPEN))
2310 CloseDoor(DOOR_CLOSE_1);
2312 if (!(req_state & REQ_STAY_CLOSED) && (old_door_state & DOOR_OPEN_1))
2314 BlitBitmap(bitmap_db_door, bitmap_db_door,
2315 DOOR_GFX_PAGEX2,DOOR_GFX_PAGEY1, DXSIZE,DYSIZE,
2316 DOOR_GFX_PAGEX1,DOOR_GFX_PAGEY1);
2317 OpenDoor(DOOR_OPEN_1);
2323 SetDrawBackgroundMask(REDRAW_FIELD);
2325 #if defined(PLATFORM_UNIX)
2326 /* continue network game after request */
2327 if (options.network &&
2328 game_status == GAME_MODE_PLAYING &&
2329 req_state & REQUEST_WAIT_FOR)
2330 SendToServer_ContinuePlaying();
2336 unsigned int OpenDoor(unsigned int door_state)
2338 unsigned int new_door_state;
2340 if (door_state & DOOR_COPY_BACK)
2342 BlitBitmap(bitmap_db_door, bitmap_db_door,
2343 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE + VYSIZE,
2344 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2345 door_state &= ~DOOR_COPY_BACK;
2348 new_door_state = MoveDoor(door_state);
2350 return(new_door_state);
2353 unsigned int CloseDoor(unsigned int door_state)
2355 unsigned int new_door_state;
2357 BlitBitmap(backbuffer, bitmap_db_door,
2358 DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2359 BlitBitmap(backbuffer, bitmap_db_door,
2360 VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
2362 new_door_state = MoveDoor(door_state);
2364 return(new_door_state);
2367 unsigned int GetDoorState()
2369 return MoveDoor(DOOR_GET_STATE);
2372 unsigned int SetDoorState(unsigned int door_state)
2374 return MoveDoor(door_state | DOOR_SET_STATE);
2377 unsigned int MoveDoor(unsigned int door_state)
2379 static int door1 = DOOR_OPEN_1;
2380 static int door2 = DOOR_CLOSE_2;
2381 static unsigned long door_delay = 0;
2382 int x, start, stepsize = door.step_offset;
2383 unsigned long door_delay_value = door.step_delay;
2385 if (door_state == DOOR_GET_STATE)
2386 return(door1 | door2);
2388 if (door_state & DOOR_SET_STATE)
2390 if (door_state & DOOR_ACTION_1)
2391 door1 = door_state & DOOR_ACTION_1;
2392 if (door_state & DOOR_ACTION_2)
2393 door2 = door_state & DOOR_ACTION_2;
2395 return(door1 | door2);
2398 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
2399 door_state &= ~DOOR_OPEN_1;
2400 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
2401 door_state &= ~DOOR_CLOSE_1;
2402 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
2403 door_state &= ~DOOR_OPEN_2;
2404 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
2405 door_state &= ~DOOR_CLOSE_2;
2407 if (setup.quick_doors)
2410 door_delay_value = 0;
2412 StopSound(SND_DOOR_OPENING);
2413 StopSound(SND_DOOR_CLOSING);
2416 if (global.autoplay_leveldir)
2418 door_state |= DOOR_NO_DELAY;
2419 door_state &= ~DOOR_CLOSE_ALL;
2422 if (door_state & DOOR_ACTION)
2424 if (!(door_state & DOOR_NO_DELAY))
2426 /* opening door sound has priority over simultaneously closing door */
2427 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
2428 PlaySoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
2429 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
2430 PlaySoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
2433 start = ((door_state & DOOR_NO_DELAY) ? DXSIZE : 0);
2435 for(x=start; x<=DXSIZE; x+=stepsize)
2437 Bitmap *bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
2438 GC gc = bitmap->stored_clip_gc;
2440 if (!(door_state & DOOR_NO_DELAY))
2441 WaitUntilDelayReached(&door_delay, door_delay_value);
2443 if (door_state & DOOR_ACTION_1)
2445 int i = (door_state & DOOR_OPEN_1 ? DXSIZE-x : x);
2446 int j = (DXSIZE - i) / 3;
2448 BlitBitmap(bitmap_db_door, drawto,
2449 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + i/2,
2450 DXSIZE,DYSIZE - i/2, DX, DY);
2452 ClearRectangle(drawto, DX, DY + DYSIZE - i/2, DXSIZE,i/2);
2454 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2455 BlitBitmapMasked(bitmap, drawto,
2456 DXSIZE, DOOR_GFX_PAGEY1, i, 77,
2457 DX + DXSIZE - i, DY + j);
2458 BlitBitmapMasked(bitmap, drawto,
2459 DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63,
2460 DX + DXSIZE - i, DY + 140 + j);
2461 SetClipOrigin(bitmap, gc, DX - DXSIZE + i, DY - (DOOR_GFX_PAGEY1 + j));
2462 BlitBitmapMasked(bitmap, drawto,
2463 DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j,
2465 BlitBitmapMasked(bitmap, drawto,
2466 DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63,
2469 BlitBitmapMasked(bitmap, drawto,
2470 DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
2472 BlitBitmapMasked(bitmap, drawto,
2473 DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
2475 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2476 BlitBitmapMasked(bitmap, drawto,
2477 DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
2478 DX + DXSIZE - i, DY + 77 + j);
2479 BlitBitmapMasked(bitmap, drawto,
2480 DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
2481 DX + DXSIZE - i, DY + 203 + j);
2483 redraw_mask |= REDRAW_DOOR_1;
2486 if (door_state & DOOR_ACTION_2)
2488 int i = (door_state & DOOR_OPEN_2 ? VXSIZE - x : x);
2489 int j = (VXSIZE - i) / 3;
2491 BlitBitmap(bitmap_db_door, drawto,
2492 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + i/2,
2493 VXSIZE, VYSIZE - i/2, VX, VY);
2495 ClearRectangle(drawto, VX, VY + VYSIZE-i/2, VXSIZE, i/2);
2497 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2498 BlitBitmapMasked(bitmap, drawto,
2499 VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2,
2500 VX + VXSIZE-i, VY+j);
2501 SetClipOrigin(bitmap, gc,
2502 VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
2503 BlitBitmapMasked(bitmap, drawto,
2504 VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j,
2507 BlitBitmapMasked(bitmap, drawto,
2508 VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2,
2509 i, VYSIZE / 2, VX, VY + VYSIZE / 2 - j);
2510 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2511 BlitBitmapMasked(bitmap, drawto,
2512 VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2,
2514 VX + VXSIZE - i, VY + VYSIZE / 2 + j);
2516 redraw_mask |= REDRAW_DOOR_2;
2521 if (game_status == GAME_MODE_MAIN)
2526 if (setup.quick_doors)
2528 StopSound(SND_DOOR_OPENING);
2529 StopSound(SND_DOOR_CLOSING);
2532 if (door_state & DOOR_ACTION_1)
2533 door1 = door_state & DOOR_ACTION_1;
2534 if (door_state & DOOR_ACTION_2)
2535 door2 = door_state & DOOR_ACTION_2;
2537 return (door1 | door2);
2540 void DrawSpecialEditorDoor()
2542 /* draw bigger toolbox window */
2543 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
2544 DOOR_GFX_PAGEX7, 0, EXSIZE + 8, 8,
2546 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
2547 EX - 4, VY - 4, EXSIZE + 8, EYSIZE - VYSIZE + 4,
2550 redraw_mask |= REDRAW_ALL;
2553 void UndrawSpecialEditorDoor()
2555 /* draw normal tape recorder window */
2556 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
2557 EX - 4, EY - 12, EXSIZE + 8, EYSIZE - VYSIZE + 12,
2560 redraw_mask |= REDRAW_ALL;
2564 /* ---------- new tool button stuff ---------------------------------------- */
2566 /* graphic position values for tool buttons */
2567 #define TOOL_BUTTON_YES_XPOS 2
2568 #define TOOL_BUTTON_YES_YPOS 250
2569 #define TOOL_BUTTON_YES_GFX_YPOS 0
2570 #define TOOL_BUTTON_YES_XSIZE 46
2571 #define TOOL_BUTTON_YES_YSIZE 28
2572 #define TOOL_BUTTON_NO_XPOS 52
2573 #define TOOL_BUTTON_NO_YPOS TOOL_BUTTON_YES_YPOS
2574 #define TOOL_BUTTON_NO_GFX_YPOS TOOL_BUTTON_YES_GFX_YPOS
2575 #define TOOL_BUTTON_NO_XSIZE TOOL_BUTTON_YES_XSIZE
2576 #define TOOL_BUTTON_NO_YSIZE TOOL_BUTTON_YES_YSIZE
2577 #define TOOL_BUTTON_CONFIRM_XPOS TOOL_BUTTON_YES_XPOS
2578 #define TOOL_BUTTON_CONFIRM_YPOS TOOL_BUTTON_YES_YPOS
2579 #define TOOL_BUTTON_CONFIRM_GFX_YPOS 30
2580 #define TOOL_BUTTON_CONFIRM_XSIZE 96
2581 #define TOOL_BUTTON_CONFIRM_YSIZE TOOL_BUTTON_YES_YSIZE
2582 #define TOOL_BUTTON_PLAYER_XSIZE 30
2583 #define TOOL_BUTTON_PLAYER_YSIZE 30
2584 #define TOOL_BUTTON_PLAYER_GFX_XPOS 5
2585 #define TOOL_BUTTON_PLAYER_GFX_YPOS 185
2586 #define TOOL_BUTTON_PLAYER_XPOS (5 + TOOL_BUTTON_PLAYER_XSIZE / 2)
2587 #define TOOL_BUTTON_PLAYER_YPOS (215 - TOOL_BUTTON_PLAYER_YSIZE / 2)
2588 #define TOOL_BUTTON_PLAYER1_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2589 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2590 #define TOOL_BUTTON_PLAYER2_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2591 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2592 #define TOOL_BUTTON_PLAYER3_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2593 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2594 #define TOOL_BUTTON_PLAYER4_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2595 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2596 #define TOOL_BUTTON_PLAYER1_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2597 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2598 #define TOOL_BUTTON_PLAYER2_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2599 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2600 #define TOOL_BUTTON_PLAYER3_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2601 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2602 #define TOOL_BUTTON_PLAYER4_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2603 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2612 } toolbutton_info[NUM_TOOL_BUTTONS] =
2615 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_GFX_YPOS,
2616 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_YPOS,
2617 TOOL_BUTTON_YES_XSIZE, TOOL_BUTTON_YES_YSIZE,
2622 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_GFX_YPOS,
2623 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_YPOS,
2624 TOOL_BUTTON_NO_XSIZE, TOOL_BUTTON_NO_YSIZE,
2629 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_GFX_YPOS,
2630 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_YPOS,
2631 TOOL_BUTTON_CONFIRM_XSIZE, TOOL_BUTTON_CONFIRM_YSIZE,
2632 TOOL_CTRL_ID_CONFIRM,
2636 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2637 TOOL_BUTTON_PLAYER1_XPOS, TOOL_BUTTON_PLAYER1_YPOS,
2638 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2639 TOOL_CTRL_ID_PLAYER_1,
2643 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2644 TOOL_BUTTON_PLAYER2_XPOS, TOOL_BUTTON_PLAYER2_YPOS,
2645 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2646 TOOL_CTRL_ID_PLAYER_2,
2650 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2651 TOOL_BUTTON_PLAYER3_XPOS, TOOL_BUTTON_PLAYER3_YPOS,
2652 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2653 TOOL_CTRL_ID_PLAYER_3,
2657 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2658 TOOL_BUTTON_PLAYER4_XPOS, TOOL_BUTTON_PLAYER4_YPOS,
2659 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2660 TOOL_CTRL_ID_PLAYER_4,
2665 void CreateToolButtons()
2669 for (i=0; i<NUM_TOOL_BUTTONS; i++)
2671 Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
2672 Bitmap *deco_bitmap = None;
2673 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
2674 struct GadgetInfo *gi;
2675 unsigned long event_mask;
2676 int gd_xoffset, gd_yoffset;
2677 int gd_x1, gd_x2, gd_y;
2680 event_mask = GD_EVENT_RELEASED;
2682 gd_xoffset = toolbutton_info[i].xpos;
2683 gd_yoffset = toolbutton_info[i].ypos;
2684 gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
2685 gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
2686 gd_y = DOOR_GFX_PAGEY1 + gd_yoffset;
2688 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
2690 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
2692 getMiniGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr),
2693 &deco_bitmap, &deco_x, &deco_y);
2694 deco_xpos = (toolbutton_info[i].width - MINI_TILEX) / 2;
2695 deco_ypos = (toolbutton_info[i].height - MINI_TILEY) / 2;
2698 gi = CreateGadget(GDI_CUSTOM_ID, id,
2699 GDI_INFO_TEXT, toolbutton_info[i].infotext,
2700 GDI_X, DX + toolbutton_info[i].x,
2701 GDI_Y, DY + toolbutton_info[i].y,
2702 GDI_WIDTH, toolbutton_info[i].width,
2703 GDI_HEIGHT, toolbutton_info[i].height,
2704 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
2705 GDI_STATE, GD_BUTTON_UNPRESSED,
2706 GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
2707 GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
2708 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
2709 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
2710 GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
2711 GDI_DECORATION_SHIFTING, 1, 1,
2712 GDI_EVENT_MASK, event_mask,
2713 GDI_CALLBACK_ACTION, HandleToolButtons,
2717 Error(ERR_EXIT, "cannot create gadget");
2719 tool_gadget[id] = gi;
2723 void FreeToolButtons()
2727 for (i=0; i<NUM_TOOL_BUTTONS; i++)
2728 FreeGadget(tool_gadget[i]);
2731 static void UnmapToolButtons()
2735 for (i=0; i<NUM_TOOL_BUTTONS; i++)
2736 UnmapGadget(tool_gadget[i]);
2739 static void HandleToolButtons(struct GadgetInfo *gi)
2741 request_gadget_id = gi->custom_id;
2744 int get_next_element(int element)
2748 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
2749 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
2750 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
2751 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
2752 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
2753 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
2754 case EL_AMOEBA_DROPPING: return EL_AMOEBA_WET;
2756 default: return element;
2760 int el_act_dir2img(int element, int action, int direction)
2762 element = GFX_ELEMENT(element);
2763 direction = MV_DIR_BIT(direction);
2765 return element_info[element].direction_graphic[action][direction];
2768 static int el_act_dir2crm(int element, int action, int direction)
2770 element = GFX_ELEMENT(element);
2771 direction = MV_DIR_BIT(direction);
2773 return element_info[element].direction_crumbled[action][direction];
2776 int el_act2img(int element, int action)
2778 element = GFX_ELEMENT(element);
2780 return element_info[element].graphic[action];
2783 int el_dir2img(int element, int direction)
2785 element = GFX_ELEMENT(element);
2787 return el_act_dir2img(element, ACTION_DEFAULT, direction);
2790 int el2img(int element)
2792 element = GFX_ELEMENT(element);
2794 return element_info[element].graphic[ACTION_DEFAULT];
2797 int el2edimg(int element)
2799 element = GFX_ELEMENT(element);
2801 return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
2804 int el2preimg(int element)
2806 element = GFX_ELEMENT(element);
2808 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];