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 lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
1638 int lypos = MICROLABEL_YPOS;
1640 DrawText(lxpos, lypos, label_text, font_nr);
1643 redraw_mask |= REDRAW_MICROLEVEL;
1646 void DrawMicroLevel(int xpos, int ypos, boolean restart)
1648 static unsigned long scroll_delay = 0;
1649 static unsigned long label_delay = 0;
1650 static int from_x, from_y, scroll_direction;
1651 static int label_state, label_counter;
1652 int last_game_status = game_status; /* save current game status */
1654 /* force PREVIEW font on preview level */
1655 game_status = GAME_MODE_PSEUDO_PREVIEW;
1659 from_x = from_y = 0;
1660 scroll_direction = MV_RIGHT;
1664 DrawMicroLevelExt(xpos, ypos, from_x, from_y);
1665 DrawMicroLevelLabelExt(label_state);
1667 /* initialize delay counters */
1668 DelayReached(&scroll_delay, 0);
1669 DelayReached(&label_delay, 0);
1671 if (leveldir_current->name)
1673 int text_width = getTextWidth(leveldir_current->name, FONT_TEXT_1);
1674 int lxpos = SX + (SXSIZE - text_width) / 2;
1675 int lypos = SY + 352;
1677 DrawText(lxpos, lypos, leveldir_current->name, FONT_TEXT_1);
1680 game_status = last_game_status; /* restore current game status */
1685 /* scroll micro level, if needed */
1686 if ((lev_fieldx > STD_LEV_FIELDX || lev_fieldy > STD_LEV_FIELDY) &&
1687 DelayReached(&scroll_delay, MICROLEVEL_SCROLL_DELAY))
1689 switch (scroll_direction)
1695 scroll_direction = MV_UP;
1699 if (from_x < lev_fieldx - STD_LEV_FIELDX)
1702 scroll_direction = MV_DOWN;
1709 scroll_direction = MV_RIGHT;
1713 if (from_y < lev_fieldy - STD_LEV_FIELDY)
1716 scroll_direction = MV_LEFT;
1723 DrawMicroLevelExt(xpos, ypos, from_x, from_y);
1726 /* redraw micro level label, if needed */
1727 if (strcmp(level.name, NAMELESS_LEVEL_NAME) != 0 &&
1728 strcmp(level.author, ANONYMOUS_NAME) != 0 &&
1729 strcmp(level.author, leveldir_current->name) != 0 &&
1730 DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
1732 int max_label_counter = 23;
1734 if (leveldir_current->imported_from != NULL)
1735 max_label_counter += 14;
1737 label_counter = (label_counter + 1) % max_label_counter;
1738 label_state = (label_counter >= 0 && label_counter <= 7 ?
1739 MICROLABEL_LEVEL_NAME :
1740 label_counter >= 9 && label_counter <= 12 ?
1741 MICROLABEL_CREATED_BY :
1742 label_counter >= 14 && label_counter <= 21 ?
1743 MICROLABEL_LEVEL_AUTHOR :
1744 label_counter >= 23 && label_counter <= 26 ?
1745 MICROLABEL_IMPORTED_FROM :
1746 label_counter >= 28 && label_counter <= 35 ?
1747 MICROLABEL_LEVEL_IMPORT_INFO : MICROLABEL_EMPTY);
1748 DrawMicroLevelLabelExt(label_state);
1751 game_status = last_game_status; /* restore current game status */
1754 int REQ_in_range(int x, int y)
1756 if (y > DY+249 && y < DY+278)
1758 if (x > DX+1 && x < DX+48)
1760 else if (x > DX+51 && x < DX+98)
1766 #define MAX_REQUEST_LINES 13
1767 #define MAX_REQUEST_LINE_LEN 7
1769 boolean Request(char *text, unsigned int req_state)
1771 int mx, my, ty, result = -1;
1772 unsigned int old_door_state;
1773 int last_game_status = game_status; /* save current game status */
1775 #if defined(PLATFORM_UNIX)
1776 /* pause network game while waiting for request to answer */
1777 if (options.network &&
1778 game_status == GAME_MODE_PLAYING &&
1779 req_state & REQUEST_WAIT_FOR)
1780 SendToServer_PausePlaying();
1783 old_door_state = GetDoorState();
1785 /* simulate releasing mouse button over last gadget, if still pressed */
1787 HandleGadgets(-1, -1, 0);
1791 CloseDoor(DOOR_CLOSE_1);
1793 /* save old door content */
1794 BlitBitmap(bitmap_db_door, bitmap_db_door,
1795 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
1796 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
1798 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
1800 /* clear door drawing field */
1801 DrawBackground(DX, DY, DXSIZE, DYSIZE);
1803 /* force DOOR font on preview level */
1804 game_status = GAME_MODE_PSEUDO_DOOR;
1806 /* write text for request */
1807 for(ty=0; ty < MAX_REQUEST_LINES; ty++)
1809 char text_line[MAX_REQUEST_LINE_LEN + 1];
1815 for(tl=0,tx=0; tx < MAX_REQUEST_LINE_LEN; tl++,tx++)
1818 if (!tc || tc == ' ')
1829 strncpy(text_line, text, tl);
1832 DrawText(DX + (DXSIZE - tl * getFontWidth(FONT_TEXT_2)) / 2,
1833 DY + 8 + ty * (getFontHeight(FONT_TEXT_2) + 2),
1834 text_line, FONT_TEXT_2);
1836 text += tl + (tc == ' ' ? 1 : 0);
1839 game_status = last_game_status; /* restore current game status */
1841 if (req_state & REQ_ASK)
1843 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
1844 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
1846 else if (req_state & REQ_CONFIRM)
1848 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
1850 else if (req_state & REQ_PLAYER)
1852 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
1853 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
1854 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
1855 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
1858 /* copy request gadgets to door backbuffer */
1859 BlitBitmap(drawto, bitmap_db_door,
1860 DX, DY, DXSIZE, DYSIZE,
1861 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
1863 OpenDoor(DOOR_OPEN_1);
1869 if (!(req_state & REQUEST_WAIT_FOR))
1871 SetDrawBackgroundMask(REDRAW_FIELD);
1876 if (game_status != GAME_MODE_MAIN)
1879 button_status = MB_RELEASED;
1881 request_gadget_id = -1;
1883 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
1895 case EVENT_BUTTONPRESS:
1896 case EVENT_BUTTONRELEASE:
1897 case EVENT_MOTIONNOTIFY:
1899 if (event.type == EVENT_MOTIONNOTIFY)
1901 if (!PointerInWindow(window))
1902 continue; /* window and pointer are on different screens */
1907 motion_status = TRUE;
1908 mx = ((MotionEvent *) &event)->x;
1909 my = ((MotionEvent *) &event)->y;
1913 motion_status = FALSE;
1914 mx = ((ButtonEvent *) &event)->x;
1915 my = ((ButtonEvent *) &event)->y;
1916 if (event.type == EVENT_BUTTONPRESS)
1917 button_status = ((ButtonEvent *) &event)->button;
1919 button_status = MB_RELEASED;
1922 /* this sets 'request_gadget_id' */
1923 HandleGadgets(mx, my, button_status);
1925 switch(request_gadget_id)
1927 case TOOL_CTRL_ID_YES:
1930 case TOOL_CTRL_ID_NO:
1933 case TOOL_CTRL_ID_CONFIRM:
1934 result = TRUE | FALSE;
1937 case TOOL_CTRL_ID_PLAYER_1:
1940 case TOOL_CTRL_ID_PLAYER_2:
1943 case TOOL_CTRL_ID_PLAYER_3:
1946 case TOOL_CTRL_ID_PLAYER_4:
1957 case EVENT_KEYPRESS:
1958 switch(GetEventKey((KeyEvent *)&event, TRUE))
1971 if (req_state & REQ_PLAYER)
1975 case EVENT_KEYRELEASE:
1976 ClearPlayerAction();
1980 HandleOtherEvents(&event);
1984 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
1986 int joy = AnyJoystick();
1988 if (joy & JOY_BUTTON_1)
1990 else if (joy & JOY_BUTTON_2)
1996 /* don't eat all CPU time */
2000 if (game_status != GAME_MODE_MAIN)
2005 if (!(req_state & REQ_STAY_OPEN))
2007 CloseDoor(DOOR_CLOSE_1);
2009 if (!(req_state & REQ_STAY_CLOSED) && (old_door_state & DOOR_OPEN_1))
2011 BlitBitmap(bitmap_db_door, bitmap_db_door,
2012 DOOR_GFX_PAGEX2,DOOR_GFX_PAGEY1, DXSIZE,DYSIZE,
2013 DOOR_GFX_PAGEX1,DOOR_GFX_PAGEY1);
2014 OpenDoor(DOOR_OPEN_1);
2020 SetDrawBackgroundMask(REDRAW_FIELD);
2022 #if defined(PLATFORM_UNIX)
2023 /* continue network game after request */
2024 if (options.network &&
2025 game_status == GAME_MODE_PLAYING &&
2026 req_state & REQUEST_WAIT_FOR)
2027 SendToServer_ContinuePlaying();
2033 unsigned int OpenDoor(unsigned int door_state)
2035 unsigned int new_door_state;
2037 if (door_state & DOOR_COPY_BACK)
2039 BlitBitmap(bitmap_db_door, bitmap_db_door,
2040 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE + VYSIZE,
2041 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2042 door_state &= ~DOOR_COPY_BACK;
2045 new_door_state = MoveDoor(door_state);
2047 return(new_door_state);
2050 unsigned int CloseDoor(unsigned int door_state)
2052 unsigned int new_door_state;
2054 BlitBitmap(backbuffer, bitmap_db_door,
2055 DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2056 BlitBitmap(backbuffer, bitmap_db_door,
2057 VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
2059 new_door_state = MoveDoor(door_state);
2061 return(new_door_state);
2064 unsigned int GetDoorState()
2066 return MoveDoor(DOOR_GET_STATE);
2069 unsigned int SetDoorState(unsigned int door_state)
2071 return MoveDoor(door_state | DOOR_SET_STATE);
2074 unsigned int MoveDoor(unsigned int door_state)
2076 static int door1 = DOOR_OPEN_1;
2077 static int door2 = DOOR_CLOSE_2;
2078 static unsigned long door_delay = 0;
2079 int x, start, stepsize = door.step_offset;
2080 unsigned long door_delay_value = door.step_delay;
2082 if (door_state == DOOR_GET_STATE)
2083 return(door1 | door2);
2085 if (door_state & DOOR_SET_STATE)
2087 if (door_state & DOOR_ACTION_1)
2088 door1 = door_state & DOOR_ACTION_1;
2089 if (door_state & DOOR_ACTION_2)
2090 door2 = door_state & DOOR_ACTION_2;
2092 return(door1 | door2);
2095 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
2096 door_state &= ~DOOR_OPEN_1;
2097 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
2098 door_state &= ~DOOR_CLOSE_1;
2099 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
2100 door_state &= ~DOOR_OPEN_2;
2101 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
2102 door_state &= ~DOOR_CLOSE_2;
2104 if (setup.quick_doors)
2107 door_delay_value = 0;
2109 StopSound(SND_DOOR_OPENING);
2110 StopSound(SND_DOOR_CLOSING);
2113 if (global.autoplay_leveldir)
2115 door_state |= DOOR_NO_DELAY;
2116 door_state &= ~DOOR_CLOSE_ALL;
2119 if (door_state & DOOR_ACTION)
2121 if (!(door_state & DOOR_NO_DELAY))
2123 /* opening door sound has priority over simultaneously closing door */
2124 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
2125 PlaySoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
2126 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
2127 PlaySoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
2130 start = ((door_state & DOOR_NO_DELAY) ? DXSIZE : 0);
2132 for(x=start; x<=DXSIZE; x+=stepsize)
2134 Bitmap *bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
2135 GC gc = bitmap->stored_clip_gc;
2137 if (!(door_state & DOOR_NO_DELAY))
2138 WaitUntilDelayReached(&door_delay, door_delay_value);
2140 if (door_state & DOOR_ACTION_1)
2142 int i = (door_state & DOOR_OPEN_1 ? DXSIZE-x : x);
2143 int j = (DXSIZE - i) / 3;
2145 BlitBitmap(bitmap_db_door, drawto,
2146 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + i/2,
2147 DXSIZE,DYSIZE - i/2, DX, DY);
2149 ClearRectangle(drawto, DX, DY + DYSIZE - i/2, DXSIZE,i/2);
2151 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2152 BlitBitmapMasked(bitmap, drawto,
2153 DXSIZE, DOOR_GFX_PAGEY1, i, 77,
2154 DX + DXSIZE - i, DY + j);
2155 BlitBitmapMasked(bitmap, drawto,
2156 DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63,
2157 DX + DXSIZE - i, DY + 140 + j);
2158 SetClipOrigin(bitmap, gc, DX - DXSIZE + i, DY - (DOOR_GFX_PAGEY1 + j));
2159 BlitBitmapMasked(bitmap, drawto,
2160 DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j,
2162 BlitBitmapMasked(bitmap, drawto,
2163 DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63,
2166 BlitBitmapMasked(bitmap, drawto,
2167 DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
2169 BlitBitmapMasked(bitmap, drawto,
2170 DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
2172 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2173 BlitBitmapMasked(bitmap, drawto,
2174 DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
2175 DX + DXSIZE - i, DY + 77 + j);
2176 BlitBitmapMasked(bitmap, drawto,
2177 DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
2178 DX + DXSIZE - i, DY + 203 + j);
2180 redraw_mask |= REDRAW_DOOR_1;
2183 if (door_state & DOOR_ACTION_2)
2185 int i = (door_state & DOOR_OPEN_2 ? VXSIZE - x : x);
2186 int j = (VXSIZE - i) / 3;
2188 BlitBitmap(bitmap_db_door, drawto,
2189 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + i/2,
2190 VXSIZE, VYSIZE - i/2, VX, VY);
2192 ClearRectangle(drawto, VX, VY + VYSIZE-i/2, VXSIZE, i/2);
2194 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2195 BlitBitmapMasked(bitmap, drawto,
2196 VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2,
2197 VX + VXSIZE-i, VY+j);
2198 SetClipOrigin(bitmap, gc,
2199 VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
2200 BlitBitmapMasked(bitmap, drawto,
2201 VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j,
2204 BlitBitmapMasked(bitmap, drawto,
2205 VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2,
2206 i, VYSIZE / 2, VX, VY + VYSIZE / 2 - j);
2207 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2208 BlitBitmapMasked(bitmap, drawto,
2209 VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2,
2211 VX + VXSIZE - i, VY + VYSIZE / 2 + j);
2213 redraw_mask |= REDRAW_DOOR_2;
2218 if (game_status == GAME_MODE_MAIN)
2223 if (setup.quick_doors)
2225 StopSound(SND_DOOR_OPENING);
2226 StopSound(SND_DOOR_CLOSING);
2229 if (door_state & DOOR_ACTION_1)
2230 door1 = door_state & DOOR_ACTION_1;
2231 if (door_state & DOOR_ACTION_2)
2232 door2 = door_state & DOOR_ACTION_2;
2234 return (door1 | door2);
2237 void DrawSpecialEditorDoor()
2239 /* draw bigger toolbox window */
2240 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
2241 DOOR_GFX_PAGEX7, 0, EXSIZE + 8, 8,
2243 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
2244 EX - 4, VY - 4, EXSIZE + 8, EYSIZE - VYSIZE + 4,
2247 redraw_mask |= REDRAW_ALL;
2250 void UndrawSpecialEditorDoor()
2252 /* draw normal tape recorder window */
2253 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
2254 EX - 4, EY - 12, EXSIZE + 8, EYSIZE - VYSIZE + 12,
2257 redraw_mask |= REDRAW_ALL;
2261 /* ---------- new tool button stuff ---------------------------------------- */
2263 /* graphic position values for tool buttons */
2264 #define TOOL_BUTTON_YES_XPOS 2
2265 #define TOOL_BUTTON_YES_YPOS 250
2266 #define TOOL_BUTTON_YES_GFX_YPOS 0
2267 #define TOOL_BUTTON_YES_XSIZE 46
2268 #define TOOL_BUTTON_YES_YSIZE 28
2269 #define TOOL_BUTTON_NO_XPOS 52
2270 #define TOOL_BUTTON_NO_YPOS TOOL_BUTTON_YES_YPOS
2271 #define TOOL_BUTTON_NO_GFX_YPOS TOOL_BUTTON_YES_GFX_YPOS
2272 #define TOOL_BUTTON_NO_XSIZE TOOL_BUTTON_YES_XSIZE
2273 #define TOOL_BUTTON_NO_YSIZE TOOL_BUTTON_YES_YSIZE
2274 #define TOOL_BUTTON_CONFIRM_XPOS TOOL_BUTTON_YES_XPOS
2275 #define TOOL_BUTTON_CONFIRM_YPOS TOOL_BUTTON_YES_YPOS
2276 #define TOOL_BUTTON_CONFIRM_GFX_YPOS 30
2277 #define TOOL_BUTTON_CONFIRM_XSIZE 96
2278 #define TOOL_BUTTON_CONFIRM_YSIZE TOOL_BUTTON_YES_YSIZE
2279 #define TOOL_BUTTON_PLAYER_XSIZE 30
2280 #define TOOL_BUTTON_PLAYER_YSIZE 30
2281 #define TOOL_BUTTON_PLAYER_GFX_XPOS 5
2282 #define TOOL_BUTTON_PLAYER_GFX_YPOS 185
2283 #define TOOL_BUTTON_PLAYER_XPOS (5 + TOOL_BUTTON_PLAYER_XSIZE / 2)
2284 #define TOOL_BUTTON_PLAYER_YPOS (215 - TOOL_BUTTON_PLAYER_YSIZE / 2)
2285 #define TOOL_BUTTON_PLAYER1_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2286 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2287 #define TOOL_BUTTON_PLAYER2_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2288 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2289 #define TOOL_BUTTON_PLAYER3_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2290 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2291 #define TOOL_BUTTON_PLAYER4_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2292 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2293 #define TOOL_BUTTON_PLAYER1_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2294 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2295 #define TOOL_BUTTON_PLAYER2_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2296 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2297 #define TOOL_BUTTON_PLAYER3_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2298 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2299 #define TOOL_BUTTON_PLAYER4_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2300 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2309 } toolbutton_info[NUM_TOOL_BUTTONS] =
2312 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_GFX_YPOS,
2313 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_YPOS,
2314 TOOL_BUTTON_YES_XSIZE, TOOL_BUTTON_YES_YSIZE,
2319 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_GFX_YPOS,
2320 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_YPOS,
2321 TOOL_BUTTON_NO_XSIZE, TOOL_BUTTON_NO_YSIZE,
2326 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_GFX_YPOS,
2327 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_YPOS,
2328 TOOL_BUTTON_CONFIRM_XSIZE, TOOL_BUTTON_CONFIRM_YSIZE,
2329 TOOL_CTRL_ID_CONFIRM,
2333 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2334 TOOL_BUTTON_PLAYER1_XPOS, TOOL_BUTTON_PLAYER1_YPOS,
2335 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2336 TOOL_CTRL_ID_PLAYER_1,
2340 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2341 TOOL_BUTTON_PLAYER2_XPOS, TOOL_BUTTON_PLAYER2_YPOS,
2342 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2343 TOOL_CTRL_ID_PLAYER_2,
2347 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2348 TOOL_BUTTON_PLAYER3_XPOS, TOOL_BUTTON_PLAYER3_YPOS,
2349 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2350 TOOL_CTRL_ID_PLAYER_3,
2354 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2355 TOOL_BUTTON_PLAYER4_XPOS, TOOL_BUTTON_PLAYER4_YPOS,
2356 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2357 TOOL_CTRL_ID_PLAYER_4,
2362 void CreateToolButtons()
2366 for (i=0; i<NUM_TOOL_BUTTONS; i++)
2368 Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
2369 Bitmap *deco_bitmap = None;
2370 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
2371 struct GadgetInfo *gi;
2372 unsigned long event_mask;
2373 int gd_xoffset, gd_yoffset;
2374 int gd_x1, gd_x2, gd_y;
2377 event_mask = GD_EVENT_RELEASED;
2379 gd_xoffset = toolbutton_info[i].xpos;
2380 gd_yoffset = toolbutton_info[i].ypos;
2381 gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
2382 gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
2383 gd_y = DOOR_GFX_PAGEY1 + gd_yoffset;
2385 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
2387 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
2389 getMiniGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr),
2390 &deco_bitmap, &deco_x, &deco_y);
2391 deco_xpos = (toolbutton_info[i].width - MINI_TILEX) / 2;
2392 deco_ypos = (toolbutton_info[i].height - MINI_TILEY) / 2;
2395 gi = CreateGadget(GDI_CUSTOM_ID, id,
2396 GDI_INFO_TEXT, toolbutton_info[i].infotext,
2397 GDI_X, DX + toolbutton_info[i].x,
2398 GDI_Y, DY + toolbutton_info[i].y,
2399 GDI_WIDTH, toolbutton_info[i].width,
2400 GDI_HEIGHT, toolbutton_info[i].height,
2401 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
2402 GDI_STATE, GD_BUTTON_UNPRESSED,
2403 GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
2404 GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
2405 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
2406 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
2407 GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
2408 GDI_DECORATION_SHIFTING, 1, 1,
2409 GDI_EVENT_MASK, event_mask,
2410 GDI_CALLBACK_ACTION, HandleToolButtons,
2414 Error(ERR_EXIT, "cannot create gadget");
2416 tool_gadget[id] = gi;
2420 void FreeToolButtons()
2424 for (i=0; i<NUM_TOOL_BUTTONS; i++)
2425 FreeGadget(tool_gadget[i]);
2428 static void UnmapToolButtons()
2432 for (i=0; i<NUM_TOOL_BUTTONS; i++)
2433 UnmapGadget(tool_gadget[i]);
2436 static void HandleToolButtons(struct GadgetInfo *gi)
2438 request_gadget_id = gi->custom_id;
2441 int get_next_element(int element)
2445 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
2446 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
2447 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
2448 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
2449 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
2450 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
2451 case EL_AMOEBA_DROPPING: return EL_AMOEBA_WET;
2453 default: return element;
2457 int el_act_dir2img(int element, int action, int direction)
2459 element = GFX_ELEMENT(element);
2460 direction = MV_DIR_BIT(direction);
2462 return element_info[element].direction_graphic[action][direction];
2465 static int el_act_dir2crm(int element, int action, int direction)
2467 element = GFX_ELEMENT(element);
2468 direction = MV_DIR_BIT(direction);
2470 return element_info[element].direction_crumbled[action][direction];
2473 int el_act2img(int element, int action)
2475 element = GFX_ELEMENT(element);
2477 return element_info[element].graphic[action];
2480 int el_dir2img(int element, int direction)
2482 element = GFX_ELEMENT(element);
2484 return el_act_dir2img(element, ACTION_DEFAULT, direction);
2487 int el2img(int element)
2489 element = GFX_ELEMENT(element);
2491 return element_info[element].graphic[ACTION_DEFAULT];
2494 int el2edimg(int element)
2496 element = GFX_ELEMENT(element);
2498 return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
2501 int el2preimg(int element)
2503 element = GFX_ELEMENT(element);
2505 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];