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);
1885 SetMouseCursor(CURSOR_DEFAULT);
1897 case EVENT_BUTTONPRESS:
1898 case EVENT_BUTTONRELEASE:
1899 case EVENT_MOTIONNOTIFY:
1901 if (event.type == EVENT_MOTIONNOTIFY)
1903 if (!PointerInWindow(window))
1904 continue; /* window and pointer are on different screens */
1909 motion_status = TRUE;
1910 mx = ((MotionEvent *) &event)->x;
1911 my = ((MotionEvent *) &event)->y;
1915 motion_status = FALSE;
1916 mx = ((ButtonEvent *) &event)->x;
1917 my = ((ButtonEvent *) &event)->y;
1918 if (event.type == EVENT_BUTTONPRESS)
1919 button_status = ((ButtonEvent *) &event)->button;
1921 button_status = MB_RELEASED;
1924 /* this sets 'request_gadget_id' */
1925 HandleGadgets(mx, my, button_status);
1927 switch(request_gadget_id)
1929 case TOOL_CTRL_ID_YES:
1932 case TOOL_CTRL_ID_NO:
1935 case TOOL_CTRL_ID_CONFIRM:
1936 result = TRUE | FALSE;
1939 case TOOL_CTRL_ID_PLAYER_1:
1942 case TOOL_CTRL_ID_PLAYER_2:
1945 case TOOL_CTRL_ID_PLAYER_3:
1948 case TOOL_CTRL_ID_PLAYER_4:
1959 case EVENT_KEYPRESS:
1960 switch(GetEventKey((KeyEvent *)&event, TRUE))
1973 if (req_state & REQ_PLAYER)
1977 case EVENT_KEYRELEASE:
1978 ClearPlayerAction();
1982 HandleOtherEvents(&event);
1986 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
1988 int joy = AnyJoystick();
1990 if (joy & JOY_BUTTON_1)
1992 else if (joy & JOY_BUTTON_2)
1998 /* don't eat all CPU time */
2002 if (game_status != GAME_MODE_MAIN)
2007 if (!(req_state & REQ_STAY_OPEN))
2009 CloseDoor(DOOR_CLOSE_1);
2011 if (!(req_state & REQ_STAY_CLOSED) && (old_door_state & DOOR_OPEN_1))
2013 BlitBitmap(bitmap_db_door, bitmap_db_door,
2014 DOOR_GFX_PAGEX2,DOOR_GFX_PAGEY1, DXSIZE,DYSIZE,
2015 DOOR_GFX_PAGEX1,DOOR_GFX_PAGEY1);
2016 OpenDoor(DOOR_OPEN_1);
2022 SetDrawBackgroundMask(REDRAW_FIELD);
2024 #if defined(PLATFORM_UNIX)
2025 /* continue network game after request */
2026 if (options.network &&
2027 game_status == GAME_MODE_PLAYING &&
2028 req_state & REQUEST_WAIT_FOR)
2029 SendToServer_ContinuePlaying();
2035 unsigned int OpenDoor(unsigned int door_state)
2037 unsigned int new_door_state;
2039 if (door_state & DOOR_COPY_BACK)
2041 BlitBitmap(bitmap_db_door, bitmap_db_door,
2042 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE + VYSIZE,
2043 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2044 door_state &= ~DOOR_COPY_BACK;
2047 new_door_state = MoveDoor(door_state);
2049 return(new_door_state);
2052 unsigned int CloseDoor(unsigned int door_state)
2054 unsigned int new_door_state;
2056 BlitBitmap(backbuffer, bitmap_db_door,
2057 DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2058 BlitBitmap(backbuffer, bitmap_db_door,
2059 VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
2061 new_door_state = MoveDoor(door_state);
2063 return(new_door_state);
2066 unsigned int GetDoorState()
2068 return MoveDoor(DOOR_GET_STATE);
2071 unsigned int SetDoorState(unsigned int door_state)
2073 return MoveDoor(door_state | DOOR_SET_STATE);
2076 unsigned int MoveDoor(unsigned int door_state)
2078 static int door1 = DOOR_OPEN_1;
2079 static int door2 = DOOR_CLOSE_2;
2080 static unsigned long door_delay = 0;
2081 int x, start, stepsize = door.step_offset;
2082 unsigned long door_delay_value = door.step_delay;
2084 if (door_state == DOOR_GET_STATE)
2085 return(door1 | door2);
2087 if (door_state & DOOR_SET_STATE)
2089 if (door_state & DOOR_ACTION_1)
2090 door1 = door_state & DOOR_ACTION_1;
2091 if (door_state & DOOR_ACTION_2)
2092 door2 = door_state & DOOR_ACTION_2;
2094 return(door1 | door2);
2097 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
2098 door_state &= ~DOOR_OPEN_1;
2099 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
2100 door_state &= ~DOOR_CLOSE_1;
2101 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
2102 door_state &= ~DOOR_OPEN_2;
2103 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
2104 door_state &= ~DOOR_CLOSE_2;
2106 if (setup.quick_doors)
2109 door_delay_value = 0;
2111 StopSound(SND_DOOR_OPENING);
2112 StopSound(SND_DOOR_CLOSING);
2115 if (global.autoplay_leveldir)
2117 door_state |= DOOR_NO_DELAY;
2118 door_state &= ~DOOR_CLOSE_ALL;
2121 if (door_state & DOOR_ACTION)
2123 if (!(door_state & DOOR_NO_DELAY))
2125 /* opening door sound has priority over simultaneously closing door */
2126 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
2127 PlaySoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
2128 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
2129 PlaySoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
2132 start = ((door_state & DOOR_NO_DELAY) ? DXSIZE : 0);
2134 for(x=start; x<=DXSIZE; x+=stepsize)
2136 Bitmap *bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
2137 GC gc = bitmap->stored_clip_gc;
2139 if (!(door_state & DOOR_NO_DELAY))
2140 WaitUntilDelayReached(&door_delay, door_delay_value);
2142 if (door_state & DOOR_ACTION_1)
2144 int i = (door_state & DOOR_OPEN_1 ? DXSIZE-x : x);
2145 int j = (DXSIZE - i) / 3;
2147 BlitBitmap(bitmap_db_door, drawto,
2148 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + i/2,
2149 DXSIZE,DYSIZE - i/2, DX, DY);
2151 ClearRectangle(drawto, DX, DY + DYSIZE - i/2, DXSIZE,i/2);
2153 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2154 BlitBitmapMasked(bitmap, drawto,
2155 DXSIZE, DOOR_GFX_PAGEY1, i, 77,
2156 DX + DXSIZE - i, DY + j);
2157 BlitBitmapMasked(bitmap, drawto,
2158 DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63,
2159 DX + DXSIZE - i, DY + 140 + j);
2160 SetClipOrigin(bitmap, gc, DX - DXSIZE + i, DY - (DOOR_GFX_PAGEY1 + j));
2161 BlitBitmapMasked(bitmap, drawto,
2162 DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j,
2164 BlitBitmapMasked(bitmap, drawto,
2165 DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63,
2168 BlitBitmapMasked(bitmap, drawto,
2169 DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
2171 BlitBitmapMasked(bitmap, drawto,
2172 DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
2174 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2175 BlitBitmapMasked(bitmap, drawto,
2176 DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
2177 DX + DXSIZE - i, DY + 77 + j);
2178 BlitBitmapMasked(bitmap, drawto,
2179 DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
2180 DX + DXSIZE - i, DY + 203 + j);
2182 redraw_mask |= REDRAW_DOOR_1;
2185 if (door_state & DOOR_ACTION_2)
2187 int i = (door_state & DOOR_OPEN_2 ? VXSIZE - x : x);
2188 int j = (VXSIZE - i) / 3;
2190 BlitBitmap(bitmap_db_door, drawto,
2191 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + i/2,
2192 VXSIZE, VYSIZE - i/2, VX, VY);
2194 ClearRectangle(drawto, VX, VY + VYSIZE-i/2, VXSIZE, i/2);
2196 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2197 BlitBitmapMasked(bitmap, drawto,
2198 VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2,
2199 VX + VXSIZE-i, VY+j);
2200 SetClipOrigin(bitmap, gc,
2201 VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
2202 BlitBitmapMasked(bitmap, drawto,
2203 VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j,
2206 BlitBitmapMasked(bitmap, drawto,
2207 VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2,
2208 i, VYSIZE / 2, VX, VY + VYSIZE / 2 - j);
2209 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2210 BlitBitmapMasked(bitmap, drawto,
2211 VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2,
2213 VX + VXSIZE - i, VY + VYSIZE / 2 + j);
2215 redraw_mask |= REDRAW_DOOR_2;
2220 if (game_status == GAME_MODE_MAIN)
2225 if (setup.quick_doors)
2227 StopSound(SND_DOOR_OPENING);
2228 StopSound(SND_DOOR_CLOSING);
2231 if (door_state & DOOR_ACTION_1)
2232 door1 = door_state & DOOR_ACTION_1;
2233 if (door_state & DOOR_ACTION_2)
2234 door2 = door_state & DOOR_ACTION_2;
2236 return (door1 | door2);
2239 void DrawSpecialEditorDoor()
2241 /* draw bigger toolbox window */
2242 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
2243 DOOR_GFX_PAGEX7, 0, EXSIZE + 8, 8,
2245 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
2246 EX - 4, VY - 4, EXSIZE + 8, EYSIZE - VYSIZE + 4,
2249 redraw_mask |= REDRAW_ALL;
2252 void UndrawSpecialEditorDoor()
2254 /* draw normal tape recorder window */
2255 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
2256 EX - 4, EY - 12, EXSIZE + 8, EYSIZE - VYSIZE + 12,
2259 redraw_mask |= REDRAW_ALL;
2263 /* ---------- new tool button stuff ---------------------------------------- */
2265 /* graphic position values for tool buttons */
2266 #define TOOL_BUTTON_YES_XPOS 2
2267 #define TOOL_BUTTON_YES_YPOS 250
2268 #define TOOL_BUTTON_YES_GFX_YPOS 0
2269 #define TOOL_BUTTON_YES_XSIZE 46
2270 #define TOOL_BUTTON_YES_YSIZE 28
2271 #define TOOL_BUTTON_NO_XPOS 52
2272 #define TOOL_BUTTON_NO_YPOS TOOL_BUTTON_YES_YPOS
2273 #define TOOL_BUTTON_NO_GFX_YPOS TOOL_BUTTON_YES_GFX_YPOS
2274 #define TOOL_BUTTON_NO_XSIZE TOOL_BUTTON_YES_XSIZE
2275 #define TOOL_BUTTON_NO_YSIZE TOOL_BUTTON_YES_YSIZE
2276 #define TOOL_BUTTON_CONFIRM_XPOS TOOL_BUTTON_YES_XPOS
2277 #define TOOL_BUTTON_CONFIRM_YPOS TOOL_BUTTON_YES_YPOS
2278 #define TOOL_BUTTON_CONFIRM_GFX_YPOS 30
2279 #define TOOL_BUTTON_CONFIRM_XSIZE 96
2280 #define TOOL_BUTTON_CONFIRM_YSIZE TOOL_BUTTON_YES_YSIZE
2281 #define TOOL_BUTTON_PLAYER_XSIZE 30
2282 #define TOOL_BUTTON_PLAYER_YSIZE 30
2283 #define TOOL_BUTTON_PLAYER_GFX_XPOS 5
2284 #define TOOL_BUTTON_PLAYER_GFX_YPOS 185
2285 #define TOOL_BUTTON_PLAYER_XPOS (5 + TOOL_BUTTON_PLAYER_XSIZE / 2)
2286 #define TOOL_BUTTON_PLAYER_YPOS (215 - TOOL_BUTTON_PLAYER_YSIZE / 2)
2287 #define TOOL_BUTTON_PLAYER1_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2288 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2289 #define TOOL_BUTTON_PLAYER2_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2290 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2291 #define TOOL_BUTTON_PLAYER3_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2292 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2293 #define TOOL_BUTTON_PLAYER4_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2294 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2295 #define TOOL_BUTTON_PLAYER1_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2296 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2297 #define TOOL_BUTTON_PLAYER2_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2298 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2299 #define TOOL_BUTTON_PLAYER3_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2300 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2301 #define TOOL_BUTTON_PLAYER4_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2302 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2311 } toolbutton_info[NUM_TOOL_BUTTONS] =
2314 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_GFX_YPOS,
2315 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_YPOS,
2316 TOOL_BUTTON_YES_XSIZE, TOOL_BUTTON_YES_YSIZE,
2321 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_GFX_YPOS,
2322 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_YPOS,
2323 TOOL_BUTTON_NO_XSIZE, TOOL_BUTTON_NO_YSIZE,
2328 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_GFX_YPOS,
2329 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_YPOS,
2330 TOOL_BUTTON_CONFIRM_XSIZE, TOOL_BUTTON_CONFIRM_YSIZE,
2331 TOOL_CTRL_ID_CONFIRM,
2335 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2336 TOOL_BUTTON_PLAYER1_XPOS, TOOL_BUTTON_PLAYER1_YPOS,
2337 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2338 TOOL_CTRL_ID_PLAYER_1,
2342 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2343 TOOL_BUTTON_PLAYER2_XPOS, TOOL_BUTTON_PLAYER2_YPOS,
2344 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2345 TOOL_CTRL_ID_PLAYER_2,
2349 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2350 TOOL_BUTTON_PLAYER3_XPOS, TOOL_BUTTON_PLAYER3_YPOS,
2351 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2352 TOOL_CTRL_ID_PLAYER_3,
2356 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2357 TOOL_BUTTON_PLAYER4_XPOS, TOOL_BUTTON_PLAYER4_YPOS,
2358 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2359 TOOL_CTRL_ID_PLAYER_4,
2364 void CreateToolButtons()
2368 for (i=0; i<NUM_TOOL_BUTTONS; i++)
2370 Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
2371 Bitmap *deco_bitmap = None;
2372 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
2373 struct GadgetInfo *gi;
2374 unsigned long event_mask;
2375 int gd_xoffset, gd_yoffset;
2376 int gd_x1, gd_x2, gd_y;
2379 event_mask = GD_EVENT_RELEASED;
2381 gd_xoffset = toolbutton_info[i].xpos;
2382 gd_yoffset = toolbutton_info[i].ypos;
2383 gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
2384 gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
2385 gd_y = DOOR_GFX_PAGEY1 + gd_yoffset;
2387 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
2389 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
2391 getMiniGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr),
2392 &deco_bitmap, &deco_x, &deco_y);
2393 deco_xpos = (toolbutton_info[i].width - MINI_TILEX) / 2;
2394 deco_ypos = (toolbutton_info[i].height - MINI_TILEY) / 2;
2397 gi = CreateGadget(GDI_CUSTOM_ID, id,
2398 GDI_INFO_TEXT, toolbutton_info[i].infotext,
2399 GDI_X, DX + toolbutton_info[i].x,
2400 GDI_Y, DY + toolbutton_info[i].y,
2401 GDI_WIDTH, toolbutton_info[i].width,
2402 GDI_HEIGHT, toolbutton_info[i].height,
2403 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
2404 GDI_STATE, GD_BUTTON_UNPRESSED,
2405 GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
2406 GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
2407 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
2408 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
2409 GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
2410 GDI_DECORATION_SHIFTING, 1, 1,
2411 GDI_EVENT_MASK, event_mask,
2412 GDI_CALLBACK_ACTION, HandleToolButtons,
2416 Error(ERR_EXIT, "cannot create gadget");
2418 tool_gadget[id] = gi;
2422 void FreeToolButtons()
2426 for (i=0; i<NUM_TOOL_BUTTONS; i++)
2427 FreeGadget(tool_gadget[i]);
2430 static void UnmapToolButtons()
2434 for (i=0; i<NUM_TOOL_BUTTONS; i++)
2435 UnmapGadget(tool_gadget[i]);
2438 static void HandleToolButtons(struct GadgetInfo *gi)
2440 request_gadget_id = gi->custom_id;
2443 int get_next_element(int element)
2447 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
2448 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
2449 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
2450 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
2451 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
2452 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
2453 case EL_AMOEBA_DROPPING: return EL_AMOEBA_WET;
2455 default: return element;
2459 int el_act_dir2img(int element, int action, int direction)
2461 element = GFX_ELEMENT(element);
2462 direction = MV_DIR_BIT(direction);
2464 return element_info[element].direction_graphic[action][direction];
2467 static int el_act_dir2crm(int element, int action, int direction)
2469 element = GFX_ELEMENT(element);
2470 direction = MV_DIR_BIT(direction);
2472 return element_info[element].direction_crumbled[action][direction];
2475 int el_act2img(int element, int action)
2477 element = GFX_ELEMENT(element);
2479 return element_info[element].graphic[action];
2482 int el_dir2img(int element, int direction)
2484 element = GFX_ELEMENT(element);
2486 return el_act_dir2img(element, ACTION_DEFAULT, direction);
2489 int el2img(int element)
2491 element = GFX_ELEMENT(element);
2493 return element_info[element].graphic[ACTION_DEFAULT];
2496 int el2edimg(int element)
2498 element = GFX_ELEMENT(element);
2500 return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
2503 int el2preimg(int element)
2505 element = GFX_ELEMENT(element);
2507 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];