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);
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->Pushing && IN_SCR_FIELD(SCREENX(next_jx), SCREENY(next_jy)))
634 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
638 if (Feld[next_jx][next_jy] == EL_SOKOBAN_FIELD_FULL)
639 DrawLevelElement(next_jx, next_jy, EL_SOKOBAN_FIELD_EMPTY);
641 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
644 DrawLevelField(next_jx, next_jy);
650 if (!IN_SCR_FIELD(sx, sy))
653 if (setup.direct_draw)
654 SetDrawtoField(DRAW_BUFFERED);
656 /* ----------------------------------------------------------------------- */
657 /* draw things behind the player, if needed */
658 /* ----------------------------------------------------------------------- */
661 DrawLevelElement(jx, jy, Back[jx][jy]);
662 else if (IS_ACTIVE_BOMB(element))
663 DrawLevelElement(jx, jy, EL_EMPTY);
666 if (player_is_moving && GfxElement[jx][jy] != EL_UNDEFINED)
669 if (CAN_BE_CRUMBLED(GfxElement[jx][jy]))
670 DrawLevelFieldCrumbledSandDigging(jx, jy, move_dir, player->StepFrame);
672 if (GfxElement[jx][jy] == EL_SAND)
673 DrawLevelFieldCrumbledSandDigging(jx, jy, move_dir, player->StepFrame);
677 int old_element = GfxElement[jx][jy];
678 int old_graphic = el_act_dir2img(old_element, action, move_dir);
679 int frame = getGraphicAnimationFrame(old_graphic, player->StepFrame);
681 DrawGraphic(sx, sy, old_graphic, frame);
686 GfxElement[jx][jy] = EL_UNDEFINED;
688 DrawLevelField(jx, jy);
692 /* ----------------------------------------------------------------------- */
693 /* draw player himself */
694 /* ----------------------------------------------------------------------- */
696 if (player->use_murphy_graphic)
698 static int last_horizontal_dir = MV_LEFT;
701 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
702 last_horizontal_dir = move_dir;
704 direction = (player->snapped ? move_dir : last_horizontal_dir);
706 graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, direction);
709 graphic = el_act_dir2img(player->element_nr, player->GfxAction, move_dir);
711 frame = getGraphicAnimationFrame(graphic, player->Frame);
715 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
716 sxx = player->GfxPos;
718 syy = player->GfxPos;
721 if (!setup.soft_scrolling && ScreenMovPos)
724 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
726 if (SHIELD_ON(player))
728 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
729 IMG_SHIELD_NORMAL_ACTIVE);
730 int frame = getGraphicAnimationFrame(graphic, -1);
732 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
735 /* ----------------------------------------------------------------------- */
736 /* draw things the player is pushing, if needed */
737 /* ----------------------------------------------------------------------- */
740 printf("::: %d, %d [%d, %d] [%d]\n",
741 player->Pushing, player_is_moving, player->GfxAction,
742 player->is_moving, player_is_moving);
746 if (player->Pushing && player->is_moving)
748 if (player->Pushing && player_is_moving)
751 int px = SCREENX(next_jx), py = SCREENY(next_jy);
753 if (Back[next_jx][next_jy])
754 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
757 if ((sxx || syy) && element == EL_SOKOBAN_OBJECT)
758 DrawGraphicShiftedThruMask(px, py, sxx, syy, IMG_SOKOBAN_OBJECT, 0,
762 (element == EL_SOKOBAN_FIELD_EMPTY ||
763 Feld[next_jx][next_jy] == EL_SOKOBAN_FIELD_FULL))
764 DrawGraphicShiftedThruMask(px, py, sxx, syy, IMG_SOKOBAN_OBJECT, 0,
770 int element = MovingOrBlocked2Element(next_jx, next_jy);
773 int element = Feld[jx][jy];
775 int element = Feld[next_jx][next_jy];
780 int graphic = el2img(element);
784 if ((sxx || syy) && IS_PUSHABLE(element))
787 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
788 frame = getGraphicAnimationFrame(graphic, player->Frame);
792 printf("::: pushing %d: %d ...\n", sxx, frame);
795 DrawGraphicShifted(px, py, sxx, syy, graphic, frame,
796 NO_CUTTING, NO_MASKING);
801 /* ----------------------------------------------------------------------- */
802 /* draw things in front of player (active dynamite or dynabombs) */
803 /* ----------------------------------------------------------------------- */
805 if (IS_ACTIVE_BOMB(element))
807 graphic = el2img(element);
808 frame = getGraphicAnimationFrame(graphic, GfxFrame[jx][jy]);
810 if (game.emulation == EMU_SUPAPLEX)
811 DrawGraphic(sx, sy, IMG_SP_DISK_RED, frame);
813 DrawGraphicThruMask(sx, sy, graphic, frame);
816 if (player_is_moving && last_element == EL_EXPLOSION)
819 int graphic = el_act2img(GfxElement[last_jx][last_jy], ACTION_EXPLODING);
821 int stored = Store[last_jx][last_jy];
822 int graphic = (game.emulation != EMU_SUPAPLEX ? IMG_EXPLOSION :
823 stored == EL_SP_INFOTRON ? IMG_SP_EXPLOSION_INFOTRON :
826 int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
827 int phase = ExplodePhase[last_jx][last_jy] - 1;
828 int frame = getGraphicAnimationFrame(graphic, phase - delay);
831 DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy), graphic, frame);
834 /* ----------------------------------------------------------------------- */
835 /* draw elements the player is just walking/passing through/under */
836 /* ----------------------------------------------------------------------- */
838 /* handle the field the player is leaving ... */
839 if (player_is_moving && IS_ACCESSIBLE_INSIDE(last_element))
840 DrawLevelField(last_jx, last_jy);
841 else if (player_is_moving && IS_ACCESSIBLE_UNDER(last_element))
842 DrawLevelFieldThruMask(last_jx, last_jy);
844 /* ... and the field the player is entering */
845 if (IS_ACCESSIBLE_INSIDE(element))
846 DrawLevelField(jx, jy);
847 else if (IS_ACCESSIBLE_UNDER(element))
848 DrawLevelFieldThruMask(jx, jy);
850 if (setup.direct_draw)
852 int dest_x = SX + SCREENX(MIN(jx, last_jx)) * TILEX;
853 int dest_y = SY + SCREENY(MIN(jy, last_jy)) * TILEY;
854 int x_size = TILEX * (1 + ABS(jx - last_jx));
855 int y_size = TILEY * (1 + ABS(jy - last_jy));
857 BlitBitmap(drawto_field, window,
858 dest_x, dest_y, x_size, y_size, dest_x, dest_y);
859 SetDrawtoField(DRAW_DIRECT);
862 MarkTileDirty(sx,sy);
865 void getGraphicSource(int graphic, int frame, Bitmap **bitmap, int *x, int *y)
867 struct GraphicInfo *g = &graphic_info[graphic];
871 if (g->offset_y == 0) /* frames are ordered horizontally */
873 int max_width = g->anim_frames_per_line * g->width;
875 *x = (g->src_x + frame * g->offset_x) % max_width;
876 *y = g->src_y + (g->src_x + frame * g->offset_x) / max_width * g->height;
878 else if (g->offset_x == 0) /* frames are ordered vertically */
880 int max_height = g->anim_frames_per_line * g->height;
882 *x = g->src_x + (g->src_y + frame * g->offset_y) / max_height * g->width;
883 *y = (g->src_y + frame * g->offset_y) % max_height;
885 else /* frames are ordered diagonally */
887 *x = g->src_x + frame * g->offset_x;
888 *y = g->src_y + frame * g->offset_y;
892 void DrawGraphic(int x, int y, int graphic, int frame)
895 if (!IN_SCR_FIELD(x, y))
897 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
898 printf("DrawGraphic(): This should never happen!\n");
903 DrawGraphicExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic, frame);
907 void DrawGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
913 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
914 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
917 void DrawGraphicThruMask(int x, int y, int graphic, int frame)
920 if (!IN_SCR_FIELD(x, y))
922 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
923 printf("DrawGraphicThruMask(): This should never happen!\n");
928 DrawGraphicThruMaskExt(drawto_field, FX + x * TILEX, FY + y *TILEY, graphic,
933 void DrawGraphicThruMaskExt(DrawBuffer *d, int dest_x, int dest_y, int graphic,
941 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
942 drawing_gc = src_bitmap->stored_clip_gc;
944 GC drawing_gc = src_bitmap->stored_clip_gc;
945 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
946 int src_x = graphic_info[graphic].src_x;
947 int src_y = graphic_info[graphic].src_y;
948 int offset_x = graphic_info[graphic].offset_x;
949 int offset_y = graphic_info[graphic].offset_y;
951 src_x += frame * offset_x;
952 src_y += frame * offset_y;
956 SetClipOrigin(src_bitmap, drawing_gc, dest_x - src_x, dest_y - src_y);
957 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX, TILEY, dest_x, dest_y);
960 void DrawMiniGraphic(int x, int y, int graphic)
962 DrawMiniGraphicExt(drawto, SX + x * MINI_TILEX,SY + y * MINI_TILEY, graphic);
963 MarkTileDirty(x / 2, y / 2);
966 void getMiniGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
968 struct GraphicInfo *g = &graphic_info[graphic];
970 int mini_starty = g->bitmap->height * 2 / 3;
973 *x = mini_startx + g->src_x / 2;
974 *y = mini_starty + g->src_y / 2;
977 void DrawMiniGraphicExt(DrawBuffer *d, int x, int y, int graphic)
982 getMiniGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
983 BlitBitmap(src_bitmap, d, src_x, src_y, MINI_TILEX, MINI_TILEY, x, y);
986 void DrawGraphicShifted(int x,int y, int dx,int dy, int graphic, int frame,
987 int cut_mode, int mask_mode)
992 int width = TILEX, height = TILEY;
998 DrawGraphic(x, y, graphic, frame);
1002 if (dx || dy) /* shifted graphic */
1004 if (x < BX1) /* object enters playfield from the left */
1011 else if (x > BX2) /* object enters playfield from the right */
1017 else if (x==BX1 && dx < 0) /* object leaves playfield to the left */
1023 else if (x==BX2 && dx > 0) /* object leaves playfield to the right */
1025 else if (dx) /* general horizontal movement */
1026 MarkTileDirty(x + SIGN(dx), y);
1028 if (y < BY1) /* object enters playfield from the top */
1030 if (cut_mode==CUT_BELOW) /* object completely above top border */
1038 else if (y > BY2) /* object enters playfield from the bottom */
1044 else if (y==BY1 && dy < 0) /* object leaves playfield to the top */
1050 else if (dy > 0 && cut_mode == CUT_ABOVE)
1052 if (y == BY2) /* object completely above bottom border */
1058 MarkTileDirty(x, y + 1);
1059 } /* object leaves playfield to the bottom */
1060 else if (dy > 0 && (y == BY2 || cut_mode == CUT_BELOW))
1062 else if (dy) /* general vertical movement */
1063 MarkTileDirty(x, y + SIGN(dy));
1067 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1069 src_bitmap = graphic_info[graphic].bitmap;
1070 src_x = graphic_info[graphic].src_x;
1071 src_y = graphic_info[graphic].src_y;
1072 offset_x = graphic_info[graphic].offset_x;
1073 offset_y = graphic_info[graphic].offset_y;
1075 src_x += frame * offset_x;
1076 src_y += frame * offset_y;
1079 drawing_gc = src_bitmap->stored_clip_gc;
1084 dest_x = FX + x * TILEX + dx;
1085 dest_y = FY + y * TILEY + dy;
1088 if (!IN_SCR_FIELD(x,y))
1090 printf("DrawGraphicShifted(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
1091 printf("DrawGraphicShifted(): This should never happen!\n");
1096 if (mask_mode == USE_MASKING)
1098 SetClipOrigin(src_bitmap, drawing_gc, dest_x - src_x, dest_y - src_y);
1099 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1103 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1109 void DrawGraphicShiftedThruMask(int x, int y, int dx, int dy, int graphic,
1110 int frame, int cut_mode)
1112 DrawGraphicShifted(x,y, dx,dy, graphic, frame, cut_mode, USE_MASKING);
1115 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
1116 int cut_mode, int mask_mode)
1118 int lx = LEVELX(x), ly = LEVELY(y);
1122 if (IN_LEV_FIELD(lx, ly))
1124 SetRandomAnimationValue(lx, ly);
1126 graphic = el_act_dir2img(element, GfxAction[lx][ly], MovDir[lx][ly]);
1127 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1129 else /* border element */
1131 graphic = el2img(element);
1132 frame = getGraphicAnimationFrame(graphic, -1);
1135 if (element == EL_EXPANDABLE_WALL)
1137 boolean left_stopped = FALSE, right_stopped = FALSE;
1139 if (!IN_LEV_FIELD(lx - 1, ly) || IS_WALL(Feld[lx - 1][ly]))
1140 left_stopped = TRUE;
1141 if (!IN_LEV_FIELD(lx + 1, ly) || IS_WALL(Feld[lx + 1][ly]))
1142 right_stopped = TRUE;
1144 if (left_stopped && right_stopped)
1146 else if (left_stopped)
1148 graphic = IMG_EXPANDABLE_WALL_GROWING_RIGHT;
1149 frame = graphic_info[graphic].anim_frames - 1;
1151 else if (right_stopped)
1153 graphic = IMG_EXPANDABLE_WALL_GROWING_LEFT;
1154 frame = graphic_info[graphic].anim_frames - 1;
1159 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, mask_mode);
1160 else if (mask_mode == USE_MASKING)
1161 DrawGraphicThruMask(x, y, graphic, frame);
1163 DrawGraphic(x, y, graphic, frame);
1166 void DrawLevelElementExt(int x, int y, int dx, int dy, int element,
1167 int cut_mode, int mask_mode)
1169 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1170 DrawScreenElementExt(SCREENX(x), SCREENY(y), dx, dy, element,
1171 cut_mode, mask_mode);
1174 void DrawScreenElementShifted(int x, int y, int dx, int dy, int element,
1177 DrawScreenElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1180 void DrawLevelElementShifted(int x, int y, int dx, int dy, int element,
1183 DrawLevelElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1186 void DrawLevelElementThruMask(int x, int y, int element)
1188 DrawLevelElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1191 void DrawLevelFieldThruMask(int x, int y)
1193 DrawLevelElementExt(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
1196 static void DrawLevelFieldCrumbledSandExt(int x, int y, int graphic, int frame)
1200 int sx = SCREENX(x), sy = SCREENY(y);
1202 int width, height, cx, cy, i;
1203 int snip = TILEX / 8; /* number of border pixels from "crumbled graphic" */
1204 static int xy[4][2] =
1212 if (!IN_LEV_FIELD(x, y))
1215 element = (GfxElement[x][y] != EL_UNDEFINED && Feld[x][y] != EL_EXPLOSION ?
1216 GfxElement[x][y] : Feld[x][y]);
1218 /* crumble field itself */
1219 if (CAN_BE_CRUMBLED(element) && !IS_MOVING(x, y))
1221 if (!IN_SCR_FIELD(sx, sy))
1224 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1228 int xx = x + xy[i][0];
1229 int yy = y + xy[i][1];
1231 element = (IN_LEV_FIELD(xx, yy) ? Feld[xx][yy] : BorderElement);
1233 /* check if neighbour field is of same type */
1234 if (CAN_BE_CRUMBLED(element) && !IS_MOVING(xx, yy))
1238 if (Feld[x][y] == EL_CUSTOM_START + 123)
1239 printf("::: crumble [%d] THE CHAOS ENGINE (%d, %d): %d, %d\n",
1240 i, Feld[x][y], element,
1241 CAN_BE_CRUMBLED(element), IS_MOVING(x, y));
1244 if (i == 1 || i == 2)
1248 cx = (i == 2 ? TILEX - snip : 0);
1256 cy = (i == 3 ? TILEY - snip : 0);
1259 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1260 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
1263 MarkTileDirty(sx, sy);
1265 else /* crumble neighbour fields */
1267 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1271 int xx = x + xy[i][0];
1272 int yy = y + xy[i][1];
1273 int sxx = sx + xy[i][0];
1274 int syy = sy + xy[i][1];
1276 if (!IN_LEV_FIELD(xx, yy) ||
1277 !IN_SCR_FIELD(sxx, syy) ||
1278 !CAN_BE_CRUMBLED(Feld[xx][yy]) ||
1282 if (i == 1 || i == 2)
1286 cx = (i == 1 ? TILEX - snip : 0);
1294 cy = (i==0 ? TILEY-snip : 0);
1297 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1298 width, height, FX + sxx * TILEX + cx, FY + syy * TILEY + cy);
1300 MarkTileDirty(sxx, syy);
1305 void DrawLevelFieldCrumbledSand(int x, int y)
1307 DrawLevelFieldCrumbledSandExt(x, y, IMG_SAND_CRUMBLED, 0);
1310 void DrawLevelFieldCrumbledSandDigging(int x, int y, int direction,
1314 int graphic1 = el_act_dir2img(GfxElement[x][y], ACTION_DIGGING, direction);
1315 int graphic2 = el_act_dir2crm(GfxElement[x][y], ACTION_DIGGING, direction);
1317 int graphic1 = el_act_dir2img(EL_SAND, ACTION_DIGGING, direction);
1318 int graphic2 = el_act_dir2img(EL_SAND_CRUMBLED, ACTION_DIGGING, direction);
1320 int frame1 = getGraphicAnimationFrame(graphic1, step_frame);
1321 int frame2 = getGraphicAnimationFrame(graphic2, step_frame);
1322 int sx = SCREENX(x), sy = SCREENY(y);
1324 DrawGraphic(sx, sy, graphic1, frame1);
1325 DrawLevelFieldCrumbledSandExt(x, y, graphic2, frame2);
1328 void DrawLevelFieldCrumbledSandNeighbours(int x, int y)
1330 int sx = SCREENX(x), sy = SCREENY(y);
1331 static int xy[4][2] =
1342 int xx = x + xy[i][0];
1343 int yy = y + xy[i][1];
1344 int sxx = sx + xy[i][0];
1345 int syy = sy + xy[i][1];
1347 if (!IN_LEV_FIELD(xx, yy) ||
1348 !IN_SCR_FIELD(sxx, syy) ||
1349 !CAN_BE_CRUMBLED(Feld[xx][yy]) ||
1353 DrawLevelField(xx, yy);
1357 static int getBorderElement(int x, int y)
1361 { EL_STEELWALL_TOPLEFT, EL_INVISIBLE_STEELWALL_TOPLEFT },
1362 { EL_STEELWALL_TOPRIGHT, EL_INVISIBLE_STEELWALL_TOPRIGHT },
1363 { EL_STEELWALL_BOTTOMLEFT, EL_INVISIBLE_STEELWALL_BOTTOMLEFT },
1364 { EL_STEELWALL_BOTTOMRIGHT, EL_INVISIBLE_STEELWALL_BOTTOMRIGHT },
1365 { EL_STEELWALL_VERTICAL, EL_INVISIBLE_STEELWALL_VERTICAL },
1366 { EL_STEELWALL_HORIZONTAL, EL_INVISIBLE_STEELWALL_HORIZONTAL },
1367 { EL_STEELWALL, EL_INVISIBLE_STEELWALL }
1369 int steel_type = (BorderElement == EL_STEELWALL ? 0 : 1);
1370 int steel_position = (x == -1 && y == -1 ? 0 :
1371 x == lev_fieldx && y == -1 ? 1 :
1372 x == -1 && y == lev_fieldy ? 2 :
1373 x == lev_fieldx && y == lev_fieldy ? 3 :
1374 x == -1 || x == lev_fieldx ? 4 :
1375 y == -1 || y == lev_fieldy ? 5 : 6);
1377 return border[steel_position][steel_type];
1380 void DrawScreenElement(int x, int y, int element)
1382 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
1383 DrawLevelFieldCrumbledSand(LEVELX(x), LEVELY(y));
1386 void DrawLevelElement(int x, int y, int element)
1388 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1389 DrawScreenElement(SCREENX(x), SCREENY(y), element);
1392 void DrawScreenField(int x, int y)
1394 int lx = LEVELX(x), ly = LEVELY(y);
1395 int element, content;
1397 if (!IN_LEV_FIELD(lx, ly))
1399 if (lx < -1 || lx > lev_fieldx || ly < -1 || ly > lev_fieldy)
1402 element = getBorderElement(lx, ly);
1404 DrawScreenElement(x, y, element);
1408 element = Feld[lx][ly];
1409 content = Store[lx][ly];
1411 if (IS_MOVING(lx, ly))
1413 int horiz_move = (MovDir[lx][ly] == MV_LEFT || MovDir[lx][ly] == MV_RIGHT);
1414 boolean cut_mode = NO_CUTTING;
1416 if (element == EL_QUICKSAND_EMPTYING ||
1417 element == EL_MAGIC_WALL_EMPTYING ||
1418 element == EL_BD_MAGIC_WALL_EMPTYING ||
1419 element == EL_AMOEBA_DROPPING)
1420 cut_mode = CUT_ABOVE;
1421 else if (element == EL_QUICKSAND_FILLING ||
1422 element == EL_MAGIC_WALL_FILLING ||
1423 element == EL_BD_MAGIC_WALL_FILLING)
1424 cut_mode = CUT_BELOW;
1426 if (cut_mode == CUT_ABOVE)
1427 DrawScreenElementShifted(x, y, 0, 0, element, NO_CUTTING);
1429 DrawScreenElement(x, y, EL_EMPTY);
1432 DrawScreenElementShifted(x, y, MovPos[lx][ly], 0, element, NO_CUTTING);
1433 else if (cut_mode == NO_CUTTING)
1434 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], element, cut_mode);
1436 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], content, cut_mode);
1438 if (content == EL_ACID)
1439 DrawLevelElementThruMask(lx, ly + 1, EL_ACID);
1441 else if (IS_BLOCKED(lx, ly))
1446 boolean cut_mode = NO_CUTTING;
1447 int element_old, content_old;
1449 Blocked2Moving(lx, ly, &oldx, &oldy);
1452 horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
1453 MovDir[oldx][oldy] == MV_RIGHT);
1455 element_old = Feld[oldx][oldy];
1456 content_old = Store[oldx][oldy];
1458 if (element_old == EL_QUICKSAND_EMPTYING ||
1459 element_old == EL_MAGIC_WALL_EMPTYING ||
1460 element_old == EL_BD_MAGIC_WALL_EMPTYING ||
1461 element_old == EL_AMOEBA_DROPPING)
1462 cut_mode = CUT_ABOVE;
1464 DrawScreenElement(x, y, EL_EMPTY);
1467 DrawScreenElementShifted(sx, sy, MovPos[oldx][oldy], 0, element_old,
1469 else if (cut_mode == NO_CUTTING)
1470 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], element_old,
1473 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], content_old,
1476 else if (IS_DRAWABLE(element))
1477 DrawScreenElement(x, y, element);
1479 DrawScreenElement(x, y, EL_EMPTY);
1482 void DrawLevelField(int x, int y)
1484 if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1485 DrawScreenField(SCREENX(x), SCREENY(y));
1486 else if (IS_MOVING(x, y))
1490 Moving2Blocked(x, y, &newx, &newy);
1491 if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
1492 DrawScreenField(SCREENX(newx), SCREENY(newy));
1494 else if (IS_BLOCKED(x, y))
1498 Blocked2Moving(x, y, &oldx, &oldy);
1499 if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
1500 DrawScreenField(SCREENX(oldx), SCREENY(oldy));
1504 void DrawMiniElement(int x, int y, int element)
1508 graphic = el2edimg(element);
1509 DrawMiniGraphic(x, y, graphic);
1512 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
1514 int x = sx + scroll_x, y = sy + scroll_y;
1516 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
1517 DrawMiniElement(sx, sy, EL_EMPTY);
1518 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
1519 DrawMiniElement(sx, sy, Feld[x][y]);
1521 DrawMiniGraphic(sx, sy, el2edimg(getBorderElement(x, y)));
1524 void getMicroGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
1526 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
1527 int mini_startx = src_bitmap->width * 3 / 4;
1528 int mini_starty = src_bitmap->height * 2 / 3;
1529 int src_x = mini_startx + graphic_info[graphic].src_x / 8;
1530 int src_y = mini_starty + graphic_info[graphic].src_y / 8;
1532 *bitmap = src_bitmap;
1537 void DrawMicroElement(int xpos, int ypos, int element)
1541 int graphic = el2preimg(element);
1543 getMicroGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
1544 BlitBitmap(src_bitmap, drawto, src_x, src_y, MICRO_TILEX, MICRO_TILEY,
1552 SetDrawBackgroundMask(REDRAW_NONE);
1555 for(x=BX1; x<=BX2; x++)
1556 for(y=BY1; y<=BY2; y++)
1557 DrawScreenField(x, y);
1559 redraw_mask |= REDRAW_FIELD;
1562 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
1566 for(x=0; x<size_x; x++)
1567 for(y=0; y<size_y; y++)
1568 DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
1570 redraw_mask |= REDRAW_FIELD;
1573 static void DrawMicroLevelExt(int xpos, int ypos, int from_x, int from_y)
1577 DrawBackground(xpos, ypos, MICROLEV_XSIZE, MICROLEV_YSIZE);
1579 if (lev_fieldx < STD_LEV_FIELDX)
1580 xpos += (STD_LEV_FIELDX - lev_fieldx) / 2 * MICRO_TILEX;
1581 if (lev_fieldy < STD_LEV_FIELDY)
1582 ypos += (STD_LEV_FIELDY - lev_fieldy) / 2 * MICRO_TILEY;
1584 xpos += MICRO_TILEX;
1585 ypos += MICRO_TILEY;
1587 for(x=-1; x<=STD_LEV_FIELDX; x++)
1589 for(y=-1; y<=STD_LEV_FIELDY; y++)
1591 int lx = from_x + x, ly = from_y + y;
1593 if (lx >= 0 && lx < lev_fieldx && ly >= 0 && ly < lev_fieldy)
1594 DrawMicroElement(xpos + x * MICRO_TILEX, ypos + y * MICRO_TILEY,
1595 level.field[lx][ly]);
1596 else if (lx >= -1 && lx < lev_fieldx+1 && ly >= -1 && ly < lev_fieldy+1
1597 && BorderElement != EL_EMPTY)
1598 DrawMicroElement(xpos + x * MICRO_TILEX, ypos + y * MICRO_TILEY,
1599 getBorderElement(lx, ly));
1603 redraw_mask |= REDRAW_MICROLEVEL;
1606 #define MICROLABEL_EMPTY 0
1607 #define MICROLABEL_LEVEL_NAME 1
1608 #define MICROLABEL_CREATED_BY 2
1609 #define MICROLABEL_LEVEL_AUTHOR 3
1610 #define MICROLABEL_IMPORTED_FROM 4
1611 #define MICROLABEL_LEVEL_IMPORT_INFO 5
1613 static void DrawMicroLevelLabelExt(int mode)
1615 char label_text[MAX_OUTPUT_LINESIZE + 1];
1616 int max_len_label_text;
1617 int font_nr = FONT_TEXT_2;
1619 if (mode == MICROLABEL_CREATED_BY || mode == MICROLABEL_IMPORTED_FROM)
1620 font_nr = FONT_TEXT_3;
1622 max_len_label_text = SXSIZE / getFontWidth(font_nr);
1624 DrawBackground(SX, MICROLABEL_YPOS, SXSIZE, getFontHeight(font_nr));
1626 strncpy(label_text, (mode == MICROLABEL_LEVEL_NAME ? level.name :
1627 mode == MICROLABEL_CREATED_BY ? "created by" :
1628 mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
1629 mode == MICROLABEL_IMPORTED_FROM ? "imported from" :
1630 mode == MICROLABEL_LEVEL_IMPORT_INFO ?
1631 leveldir_current->imported_from : ""),
1632 max_len_label_text);
1633 label_text[max_len_label_text] = '\0';
1635 if (strlen(label_text) > 0)
1637 int text_width = strlen(label_text) * getFontWidth(font_nr);
1638 int lxpos = SX + (SXSIZE - text_width) / 2;
1639 int lypos = MICROLABEL_YPOS;
1641 DrawText(lxpos, lypos, label_text, font_nr);
1644 redraw_mask |= REDRAW_MICROLEVEL;
1647 void DrawMicroLevel(int xpos, int ypos, boolean restart)
1649 static unsigned long scroll_delay = 0;
1650 static unsigned long label_delay = 0;
1651 static int from_x, from_y, scroll_direction;
1652 static int label_state, label_counter;
1653 int last_game_status = game_status; /* save current game status */
1655 /* force PREVIEW font on preview level */
1656 game_status = GAME_MODE_PSEUDO_PREVIEW;
1660 from_x = from_y = 0;
1661 scroll_direction = MV_RIGHT;
1665 DrawMicroLevelExt(xpos, ypos, from_x, from_y);
1666 DrawMicroLevelLabelExt(label_state);
1668 /* initialize delay counters */
1669 DelayReached(&scroll_delay, 0);
1670 DelayReached(&label_delay, 0);
1672 if (leveldir_current->name)
1674 int len = strlen(leveldir_current->name);
1675 int lxpos = SX + (SXSIZE - len * getFontWidth(FONT_TEXT_1)) / 2;
1676 int lypos = SY + 352;
1678 DrawText(lxpos, lypos, leveldir_current->name, FONT_TEXT_1);
1681 game_status = last_game_status; /* restore current game status */
1686 /* scroll micro level, if needed */
1687 if ((lev_fieldx > STD_LEV_FIELDX || lev_fieldy > STD_LEV_FIELDY) &&
1688 DelayReached(&scroll_delay, MICROLEVEL_SCROLL_DELAY))
1690 switch (scroll_direction)
1696 scroll_direction = MV_UP;
1700 if (from_x < lev_fieldx - STD_LEV_FIELDX)
1703 scroll_direction = MV_DOWN;
1710 scroll_direction = MV_RIGHT;
1714 if (from_y < lev_fieldy - STD_LEV_FIELDY)
1717 scroll_direction = MV_LEFT;
1724 DrawMicroLevelExt(xpos, ypos, from_x, from_y);
1727 /* redraw micro level label, if needed */
1728 if (strcmp(level.name, NAMELESS_LEVEL_NAME) != 0 &&
1729 strcmp(level.author, ANONYMOUS_NAME) != 0 &&
1730 strcmp(level.author, leveldir_current->name) != 0 &&
1731 DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
1733 int max_label_counter = 23;
1735 if (leveldir_current->imported_from != NULL)
1736 max_label_counter += 14;
1738 label_counter = (label_counter + 1) % max_label_counter;
1739 label_state = (label_counter >= 0 && label_counter <= 7 ?
1740 MICROLABEL_LEVEL_NAME :
1741 label_counter >= 9 && label_counter <= 12 ?
1742 MICROLABEL_CREATED_BY :
1743 label_counter >= 14 && label_counter <= 21 ?
1744 MICROLABEL_LEVEL_AUTHOR :
1745 label_counter >= 23 && label_counter <= 26 ?
1746 MICROLABEL_IMPORTED_FROM :
1747 label_counter >= 28 && label_counter <= 35 ?
1748 MICROLABEL_LEVEL_IMPORT_INFO : MICROLABEL_EMPTY);
1749 DrawMicroLevelLabelExt(label_state);
1752 game_status = last_game_status; /* restore current game status */
1755 int REQ_in_range(int x, int y)
1757 if (y > DY+249 && y < DY+278)
1759 if (x > DX+1 && x < DX+48)
1761 else if (x > DX+51 && x < DX+98)
1767 #define MAX_REQUEST_LINES 13
1768 #define MAX_REQUEST_LINE_LEN 7
1770 boolean Request(char *text, unsigned int req_state)
1772 int mx, my, ty, result = -1;
1773 unsigned int old_door_state;
1774 int last_game_status = game_status; /* save current game status */
1776 #if defined(PLATFORM_UNIX)
1777 /* pause network game while waiting for request to answer */
1778 if (options.network &&
1779 game_status == GAME_MODE_PLAYING &&
1780 req_state & REQUEST_WAIT_FOR)
1781 SendToServer_PausePlaying();
1784 old_door_state = GetDoorState();
1786 /* simulate releasing mouse button over last gadget, if still pressed */
1788 HandleGadgets(-1, -1, 0);
1792 CloseDoor(DOOR_CLOSE_1);
1794 /* save old door content */
1795 BlitBitmap(bitmap_db_door, bitmap_db_door,
1796 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
1797 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
1799 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
1801 /* clear door drawing field */
1802 DrawBackground(DX, DY, DXSIZE, DYSIZE);
1804 /* force DOOR font on preview level */
1805 game_status = GAME_MODE_PSEUDO_DOOR;
1807 /* write text for request */
1808 for(ty=0; ty < MAX_REQUEST_LINES; ty++)
1810 char text_line[MAX_REQUEST_LINE_LEN + 1];
1816 for(tl=0,tx=0; tx < MAX_REQUEST_LINE_LEN; tl++,tx++)
1819 if (!tc || tc == ' ')
1830 strncpy(text_line, text, tl);
1833 DrawText(DX + (DXSIZE - tl * getFontWidth(FONT_TEXT_2)) / 2,
1834 DY + 8 + ty * (getFontHeight(FONT_TEXT_2) + 2),
1835 text_line, FONT_TEXT_2);
1837 text += tl + (tc == ' ' ? 1 : 0);
1840 game_status = last_game_status; /* restore current game status */
1842 if (req_state & REQ_ASK)
1844 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
1845 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
1847 else if (req_state & REQ_CONFIRM)
1849 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
1851 else if (req_state & REQ_PLAYER)
1853 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
1854 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
1855 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
1856 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
1859 /* copy request gadgets to door backbuffer */
1860 BlitBitmap(drawto, bitmap_db_door,
1861 DX, DY, DXSIZE, DYSIZE,
1862 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
1864 OpenDoor(DOOR_OPEN_1);
1870 if (!(req_state & REQUEST_WAIT_FOR))
1872 SetDrawBackgroundMask(REDRAW_FIELD);
1877 if (game_status != GAME_MODE_MAIN)
1880 button_status = MB_RELEASED;
1882 request_gadget_id = -1;
1884 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
1896 case EVENT_BUTTONPRESS:
1897 case EVENT_BUTTONRELEASE:
1898 case EVENT_MOTIONNOTIFY:
1900 if (event.type == EVENT_MOTIONNOTIFY)
1902 if (!PointerInWindow(window))
1903 continue; /* window and pointer are on different screens */
1908 motion_status = TRUE;
1909 mx = ((MotionEvent *) &event)->x;
1910 my = ((MotionEvent *) &event)->y;
1914 motion_status = FALSE;
1915 mx = ((ButtonEvent *) &event)->x;
1916 my = ((ButtonEvent *) &event)->y;
1917 if (event.type == EVENT_BUTTONPRESS)
1918 button_status = ((ButtonEvent *) &event)->button;
1920 button_status = MB_RELEASED;
1923 /* this sets 'request_gadget_id' */
1924 HandleGadgets(mx, my, button_status);
1926 switch(request_gadget_id)
1928 case TOOL_CTRL_ID_YES:
1931 case TOOL_CTRL_ID_NO:
1934 case TOOL_CTRL_ID_CONFIRM:
1935 result = TRUE | FALSE;
1938 case TOOL_CTRL_ID_PLAYER_1:
1941 case TOOL_CTRL_ID_PLAYER_2:
1944 case TOOL_CTRL_ID_PLAYER_3:
1947 case TOOL_CTRL_ID_PLAYER_4:
1958 case EVENT_KEYPRESS:
1959 switch(GetEventKey((KeyEvent *)&event, TRUE))
1972 if (req_state & REQ_PLAYER)
1976 case EVENT_KEYRELEASE:
1977 ClearPlayerAction();
1981 HandleOtherEvents(&event);
1985 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
1987 int joy = AnyJoystick();
1989 if (joy & JOY_BUTTON_1)
1991 else if (joy & JOY_BUTTON_2)
1997 /* don't eat all CPU time */
2001 if (game_status != GAME_MODE_MAIN)
2006 if (!(req_state & REQ_STAY_OPEN))
2008 CloseDoor(DOOR_CLOSE_1);
2010 if (!(req_state & REQ_STAY_CLOSED) && (old_door_state & DOOR_OPEN_1))
2012 BlitBitmap(bitmap_db_door, bitmap_db_door,
2013 DOOR_GFX_PAGEX2,DOOR_GFX_PAGEY1, DXSIZE,DYSIZE,
2014 DOOR_GFX_PAGEX1,DOOR_GFX_PAGEY1);
2015 OpenDoor(DOOR_OPEN_1);
2021 SetDrawBackgroundMask(REDRAW_FIELD);
2023 #if defined(PLATFORM_UNIX)
2024 /* continue network game after request */
2025 if (options.network &&
2026 game_status == GAME_MODE_PLAYING &&
2027 req_state & REQUEST_WAIT_FOR)
2028 SendToServer_ContinuePlaying();
2034 unsigned int OpenDoor(unsigned int door_state)
2036 unsigned int new_door_state;
2038 if (door_state & DOOR_COPY_BACK)
2040 BlitBitmap(bitmap_db_door, bitmap_db_door,
2041 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE + VYSIZE,
2042 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2043 door_state &= ~DOOR_COPY_BACK;
2046 new_door_state = MoveDoor(door_state);
2048 return(new_door_state);
2051 unsigned int CloseDoor(unsigned int door_state)
2053 unsigned int new_door_state;
2055 BlitBitmap(backbuffer, bitmap_db_door,
2056 DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2057 BlitBitmap(backbuffer, bitmap_db_door,
2058 VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
2060 new_door_state = MoveDoor(door_state);
2062 return(new_door_state);
2065 unsigned int GetDoorState()
2067 return MoveDoor(DOOR_GET_STATE);
2070 unsigned int SetDoorState(unsigned int door_state)
2072 return MoveDoor(door_state | DOOR_SET_STATE);
2075 unsigned int MoveDoor(unsigned int door_state)
2077 static int door1 = DOOR_OPEN_1;
2078 static int door2 = DOOR_CLOSE_2;
2079 static unsigned long door_delay = 0;
2080 int x, start, stepsize = door.step_offset;
2081 unsigned long door_delay_value = door.step_delay;
2083 if (door_state == DOOR_GET_STATE)
2084 return(door1 | door2);
2086 if (door_state & DOOR_SET_STATE)
2088 if (door_state & DOOR_ACTION_1)
2089 door1 = door_state & DOOR_ACTION_1;
2090 if (door_state & DOOR_ACTION_2)
2091 door2 = door_state & DOOR_ACTION_2;
2093 return(door1 | door2);
2096 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
2097 door_state &= ~DOOR_OPEN_1;
2098 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
2099 door_state &= ~DOOR_CLOSE_1;
2100 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
2101 door_state &= ~DOOR_OPEN_2;
2102 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
2103 door_state &= ~DOOR_CLOSE_2;
2105 if (setup.quick_doors)
2108 door_delay_value = 0;
2110 StopSound(SND_DOOR_OPENING);
2111 StopSound(SND_DOOR_CLOSING);
2114 if (global.autoplay_leveldir)
2116 door_state |= DOOR_NO_DELAY;
2117 door_state &= ~DOOR_CLOSE_ALL;
2120 if (door_state & DOOR_ACTION)
2122 if (!(door_state & DOOR_NO_DELAY))
2124 /* opening door sound has priority over simultaneously closing door */
2125 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
2126 PlaySoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
2127 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
2128 PlaySoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
2131 start = ((door_state & DOOR_NO_DELAY) ? DXSIZE : 0);
2133 for(x=start; x<=DXSIZE; x+=stepsize)
2135 Bitmap *bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
2136 GC gc = bitmap->stored_clip_gc;
2138 if (!(door_state & DOOR_NO_DELAY))
2139 WaitUntilDelayReached(&door_delay, door_delay_value);
2141 if (door_state & DOOR_ACTION_1)
2143 int i = (door_state & DOOR_OPEN_1 ? DXSIZE-x : x);
2144 int j = (DXSIZE - i) / 3;
2146 BlitBitmap(bitmap_db_door, drawto,
2147 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + i/2,
2148 DXSIZE,DYSIZE - i/2, DX, DY);
2150 ClearRectangle(drawto, DX, DY + DYSIZE - i/2, DXSIZE,i/2);
2152 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2153 BlitBitmapMasked(bitmap, drawto,
2154 DXSIZE, DOOR_GFX_PAGEY1, i, 77,
2155 DX + DXSIZE - i, DY + j);
2156 BlitBitmapMasked(bitmap, drawto,
2157 DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63,
2158 DX + DXSIZE - i, DY + 140 + j);
2159 SetClipOrigin(bitmap, gc, DX - DXSIZE + i, DY - (DOOR_GFX_PAGEY1 + j));
2160 BlitBitmapMasked(bitmap, drawto,
2161 DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j,
2163 BlitBitmapMasked(bitmap, drawto,
2164 DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63,
2167 BlitBitmapMasked(bitmap, drawto,
2168 DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
2170 BlitBitmapMasked(bitmap, drawto,
2171 DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
2173 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2174 BlitBitmapMasked(bitmap, drawto,
2175 DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
2176 DX + DXSIZE - i, DY + 77 + j);
2177 BlitBitmapMasked(bitmap, drawto,
2178 DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
2179 DX + DXSIZE - i, DY + 203 + j);
2181 redraw_mask |= REDRAW_DOOR_1;
2184 if (door_state & DOOR_ACTION_2)
2186 int i = (door_state & DOOR_OPEN_2 ? VXSIZE - x : x);
2187 int j = (VXSIZE - i) / 3;
2189 BlitBitmap(bitmap_db_door, drawto,
2190 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + i/2,
2191 VXSIZE, VYSIZE - i/2, VX, VY);
2193 ClearRectangle(drawto, VX, VY + VYSIZE-i/2, VXSIZE, i/2);
2195 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2196 BlitBitmapMasked(bitmap, drawto,
2197 VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2,
2198 VX + VXSIZE-i, VY+j);
2199 SetClipOrigin(bitmap, gc,
2200 VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
2201 BlitBitmapMasked(bitmap, drawto,
2202 VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j,
2205 BlitBitmapMasked(bitmap, drawto,
2206 VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2,
2207 i, VYSIZE / 2, VX, VY + VYSIZE / 2 - j);
2208 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2209 BlitBitmapMasked(bitmap, drawto,
2210 VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2,
2212 VX + VXSIZE - i, VY + VYSIZE / 2 + j);
2214 redraw_mask |= REDRAW_DOOR_2;
2219 if (game_status == GAME_MODE_MAIN)
2224 if (setup.quick_doors)
2226 StopSound(SND_DOOR_OPENING);
2227 StopSound(SND_DOOR_CLOSING);
2230 if (door_state & DOOR_ACTION_1)
2231 door1 = door_state & DOOR_ACTION_1;
2232 if (door_state & DOOR_ACTION_2)
2233 door2 = door_state & DOOR_ACTION_2;
2235 return (door1 | door2);
2238 void DrawSpecialEditorDoor()
2240 /* draw bigger toolbox window */
2241 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
2242 DOOR_GFX_PAGEX7, 0, EXSIZE + 8, 8,
2244 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
2245 EX - 4, VY - 4, EXSIZE + 8, EYSIZE - VYSIZE + 4,
2248 redraw_mask |= REDRAW_ALL;
2251 void UndrawSpecialEditorDoor()
2253 /* draw normal tape recorder window */
2254 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
2255 EX - 4, EY - 12, EXSIZE + 8, EYSIZE - VYSIZE + 12,
2258 redraw_mask |= REDRAW_ALL;
2262 /* ---------- new tool button stuff ---------------------------------------- */
2264 /* graphic position values for tool buttons */
2265 #define TOOL_BUTTON_YES_XPOS 2
2266 #define TOOL_BUTTON_YES_YPOS 250
2267 #define TOOL_BUTTON_YES_GFX_YPOS 0
2268 #define TOOL_BUTTON_YES_XSIZE 46
2269 #define TOOL_BUTTON_YES_YSIZE 28
2270 #define TOOL_BUTTON_NO_XPOS 52
2271 #define TOOL_BUTTON_NO_YPOS TOOL_BUTTON_YES_YPOS
2272 #define TOOL_BUTTON_NO_GFX_YPOS TOOL_BUTTON_YES_GFX_YPOS
2273 #define TOOL_BUTTON_NO_XSIZE TOOL_BUTTON_YES_XSIZE
2274 #define TOOL_BUTTON_NO_YSIZE TOOL_BUTTON_YES_YSIZE
2275 #define TOOL_BUTTON_CONFIRM_XPOS TOOL_BUTTON_YES_XPOS
2276 #define TOOL_BUTTON_CONFIRM_YPOS TOOL_BUTTON_YES_YPOS
2277 #define TOOL_BUTTON_CONFIRM_GFX_YPOS 30
2278 #define TOOL_BUTTON_CONFIRM_XSIZE 96
2279 #define TOOL_BUTTON_CONFIRM_YSIZE TOOL_BUTTON_YES_YSIZE
2280 #define TOOL_BUTTON_PLAYER_XSIZE 30
2281 #define TOOL_BUTTON_PLAYER_YSIZE 30
2282 #define TOOL_BUTTON_PLAYER_GFX_XPOS 5
2283 #define TOOL_BUTTON_PLAYER_GFX_YPOS 185
2284 #define TOOL_BUTTON_PLAYER_XPOS (5 + TOOL_BUTTON_PLAYER_XSIZE / 2)
2285 #define TOOL_BUTTON_PLAYER_YPOS (215 - TOOL_BUTTON_PLAYER_YSIZE / 2)
2286 #define TOOL_BUTTON_PLAYER1_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2287 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2288 #define TOOL_BUTTON_PLAYER2_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2289 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2290 #define TOOL_BUTTON_PLAYER3_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2291 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2292 #define TOOL_BUTTON_PLAYER4_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2293 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2294 #define TOOL_BUTTON_PLAYER1_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2295 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2296 #define TOOL_BUTTON_PLAYER2_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2297 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2298 #define TOOL_BUTTON_PLAYER3_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2299 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2300 #define TOOL_BUTTON_PLAYER4_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2301 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2310 } toolbutton_info[NUM_TOOL_BUTTONS] =
2313 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_GFX_YPOS,
2314 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_YPOS,
2315 TOOL_BUTTON_YES_XSIZE, TOOL_BUTTON_YES_YSIZE,
2320 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_GFX_YPOS,
2321 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_YPOS,
2322 TOOL_BUTTON_NO_XSIZE, TOOL_BUTTON_NO_YSIZE,
2327 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_GFX_YPOS,
2328 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_YPOS,
2329 TOOL_BUTTON_CONFIRM_XSIZE, TOOL_BUTTON_CONFIRM_YSIZE,
2330 TOOL_CTRL_ID_CONFIRM,
2334 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2335 TOOL_BUTTON_PLAYER1_XPOS, TOOL_BUTTON_PLAYER1_YPOS,
2336 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2337 TOOL_CTRL_ID_PLAYER_1,
2341 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2342 TOOL_BUTTON_PLAYER2_XPOS, TOOL_BUTTON_PLAYER2_YPOS,
2343 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2344 TOOL_CTRL_ID_PLAYER_2,
2348 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2349 TOOL_BUTTON_PLAYER3_XPOS, TOOL_BUTTON_PLAYER3_YPOS,
2350 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2351 TOOL_CTRL_ID_PLAYER_3,
2355 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2356 TOOL_BUTTON_PLAYER4_XPOS, TOOL_BUTTON_PLAYER4_YPOS,
2357 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2358 TOOL_CTRL_ID_PLAYER_4,
2363 void CreateToolButtons()
2367 for (i=0; i<NUM_TOOL_BUTTONS; i++)
2369 Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
2370 Bitmap *deco_bitmap = None;
2371 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
2372 struct GadgetInfo *gi;
2373 unsigned long event_mask;
2374 int gd_xoffset, gd_yoffset;
2375 int gd_x1, gd_x2, gd_y;
2378 event_mask = GD_EVENT_RELEASED;
2380 gd_xoffset = toolbutton_info[i].xpos;
2381 gd_yoffset = toolbutton_info[i].ypos;
2382 gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
2383 gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
2384 gd_y = DOOR_GFX_PAGEY1 + gd_yoffset;
2386 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
2388 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
2390 getMiniGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr),
2391 &deco_bitmap, &deco_x, &deco_y);
2392 deco_xpos = (toolbutton_info[i].width - MINI_TILEX) / 2;
2393 deco_ypos = (toolbutton_info[i].height - MINI_TILEY) / 2;
2396 gi = CreateGadget(GDI_CUSTOM_ID, id,
2397 GDI_INFO_TEXT, toolbutton_info[i].infotext,
2398 GDI_X, DX + toolbutton_info[i].x,
2399 GDI_Y, DY + toolbutton_info[i].y,
2400 GDI_WIDTH, toolbutton_info[i].width,
2401 GDI_HEIGHT, toolbutton_info[i].height,
2402 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
2403 GDI_STATE, GD_BUTTON_UNPRESSED,
2404 GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
2405 GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
2406 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
2407 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
2408 GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
2409 GDI_DECORATION_SHIFTING, 1, 1,
2410 GDI_EVENT_MASK, event_mask,
2411 GDI_CALLBACK_ACTION, HandleToolButtons,
2415 Error(ERR_EXIT, "cannot create gadget");
2417 tool_gadget[id] = gi;
2421 void FreeToolButtons()
2425 for (i=0; i<NUM_TOOL_BUTTONS; i++)
2426 FreeGadget(tool_gadget[i]);
2429 static void UnmapToolButtons()
2433 for (i=0; i<NUM_TOOL_BUTTONS; i++)
2434 UnmapGadget(tool_gadget[i]);
2437 static void HandleToolButtons(struct GadgetInfo *gi)
2439 request_gadget_id = gi->custom_id;
2442 int get_next_element(int element)
2446 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
2447 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
2448 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
2449 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
2450 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
2451 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
2452 case EL_AMOEBA_DROPPING: return EL_AMOEBA_WET;
2454 default: return element;
2458 int el_act_dir2img(int element, int action, int direction)
2460 element = GFX_ELEMENT(element);
2461 direction = MV_DIR_BIT(direction);
2463 return element_info[element].direction_graphic[action][direction];
2466 static int el_act_dir2crm(int element, int action, int direction)
2468 element = GFX_ELEMENT(element);
2469 direction = MV_DIR_BIT(direction);
2471 return element_info[element].direction_crumbled[action][direction];
2474 int el_act2img(int element, int action)
2476 element = GFX_ELEMENT(element);
2478 return element_info[element].graphic[action];
2481 int el_dir2img(int element, int direction)
2483 element = GFX_ELEMENT(element);
2485 return el_act_dir2img(element, ACTION_DEFAULT, direction);
2488 int el2img(int element)
2490 element = GFX_ELEMENT(element);
2492 return element_info[element].graphic[ACTION_DEFAULT];
2495 int el2edimg(int element)
2497 element = GFX_ELEMENT(element);
2499 return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
2502 int el2preimg(int element)
2504 element = GFX_ELEMENT(element);
2506 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];