1 /***********************************************************
2 * Rocks'n'Diamonds -- McDuffin Strikes Back! *
3 *----------------------------------------------------------*
4 * (c) 1995-2002 Artsoft Entertainment *
6 * Detmolder Strasse 189 *
9 * e-mail: info@artsoft.org *
10 *----------------------------------------------------------*
12 ***********************************************************/
14 #include "libgame/libgame.h"
23 /* tool button identifiers */
24 #define TOOL_CTRL_ID_YES 0
25 #define TOOL_CTRL_ID_NO 1
26 #define TOOL_CTRL_ID_CONFIRM 2
27 #define TOOL_CTRL_ID_PLAYER_1 3
28 #define TOOL_CTRL_ID_PLAYER_2 4
29 #define TOOL_CTRL_ID_PLAYER_3 5
30 #define TOOL_CTRL_ID_PLAYER_4 6
32 #define NUM_TOOL_BUTTONS 7
34 /* forward declaration for internal use */
35 static void UnmapToolButtons();
36 static void HandleToolButtons(struct GadgetInfo *);
37 static int el_act_dir2crm(int, int, int);
39 static struct GadgetInfo *tool_gadget[NUM_TOOL_BUTTONS];
40 static int request_gadget_id = -1;
42 void SetDrawtoField(int mode)
44 if (mode == DRAW_BUFFERED && setup.soft_scrolling)
55 drawto_field = fieldbuffer;
57 else /* DRAW_DIRECT, DRAW_BACKBUFFER */
68 drawto_field = (mode == DRAW_DIRECT ? window : backbuffer);
72 void RedrawPlayfield(boolean force_redraw, int x, int y, int width, int height)
74 if (game_status == GAME_MODE_PLAYING)
80 width = gfx.sxsize + 2 * TILEX;
81 height = gfx.sysize + 2 * TILEY;
84 if (force_redraw || setup.direct_draw)
87 int x1 = (x - SX) / TILEX, y1 = (y - SY) / TILEY;
88 int x2 = (x - SX + width) / TILEX, y2 = (y - SY + height) / TILEY;
90 if (setup.direct_draw)
91 SetDrawtoField(DRAW_BACKBUFFER);
93 for(xx=BX1; xx<=BX2; xx++)
94 for(yy=BY1; yy<=BY2; yy++)
95 if (xx >= x1 && xx <= x2 && yy >= y1 && yy <= y2)
96 DrawScreenField(xx, yy);
99 if (setup.direct_draw)
100 SetDrawtoField(DRAW_DIRECT);
103 if (setup.soft_scrolling)
105 int fx = FX, fy = FY;
107 fx += (ScreenMovDir & (MV_LEFT|MV_RIGHT) ? ScreenGfxPos : 0);
108 fy += (ScreenMovDir & (MV_UP|MV_DOWN) ? ScreenGfxPos : 0);
110 BlitBitmap(fieldbuffer, backbuffer, fx,fy, SXSIZE,SYSIZE, SX,SY);
114 BlitBitmap(drawto, window, x, y, width, height, x, y);
120 DrawBuffer *buffer = (drawto_field == window ? backbuffer : drawto_field);
122 if (setup.direct_draw && game_status == GAME_MODE_PLAYING)
123 redraw_mask &= ~REDRAW_MAIN;
125 if (redraw_mask & REDRAW_TILES && redraw_tiles > REDRAWTILES_THRESHOLD)
126 redraw_mask |= REDRAW_FIELD;
128 if (redraw_mask & REDRAW_FIELD)
129 redraw_mask &= ~REDRAW_TILES;
131 if (redraw_mask == REDRAW_NONE)
134 if (global.fps_slowdown && game_status == GAME_MODE_PLAYING)
136 static boolean last_frame_skipped = FALSE;
137 boolean skip_even_when_not_scrolling = TRUE;
138 boolean just_scrolling = (ScreenMovDir != 0);
139 boolean verbose = FALSE;
141 if (global.fps_slowdown_factor > 1 &&
142 (FrameCounter % global.fps_slowdown_factor) &&
143 (just_scrolling || skip_even_when_not_scrolling))
145 redraw_mask &= ~REDRAW_MAIN;
147 last_frame_skipped = TRUE;
150 printf("FRAME SKIPPED\n");
154 if (last_frame_skipped)
155 redraw_mask |= REDRAW_FIELD;
157 last_frame_skipped = FALSE;
160 printf("frame not skipped\n");
164 /* synchronize X11 graphics at this point; if we would synchronize the
165 display immediately after the buffer switching (after the XFlush),
166 this could mean that we have to wait for the graphics to complete,
167 although we could go on doing calculations for the next frame */
171 if (redraw_mask & REDRAW_ALL)
173 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
177 if (redraw_mask & REDRAW_FIELD)
179 if (game_status != GAME_MODE_PLAYING ||
180 redraw_mask & REDRAW_FROM_BACKBUFFER)
182 BlitBitmap(backbuffer, window,
183 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE, REAL_SX, REAL_SY);
187 int fx = FX, fy = FY;
189 if (setup.soft_scrolling)
191 fx += (ScreenMovDir & (MV_LEFT | MV_RIGHT) ? ScreenGfxPos : 0);
192 fy += (ScreenMovDir & (MV_UP | MV_DOWN) ? ScreenGfxPos : 0);
195 if (setup.soft_scrolling ||
196 ABS(ScreenMovPos) + ScrollStepSize == TILEX ||
197 ABS(ScreenMovPos) == ScrollStepSize ||
198 redraw_tiles > REDRAWTILES_THRESHOLD)
200 BlitBitmap(buffer, window, fx, fy, SXSIZE, SYSIZE, SX, SY);
204 printf("redrawing all (ScreenGfxPos == %d) because %s\n",
206 (setup.soft_scrolling ?
207 "setup.soft_scrolling" :
208 ABS(ScreenGfxPos) + ScrollStepSize == TILEX ?
209 "ABS(ScreenGfxPos) + ScrollStepSize == TILEX" :
210 ABS(ScreenGfxPos) == ScrollStepSize ?
211 "ABS(ScreenGfxPos) == ScrollStepSize" :
212 "redraw_tiles > REDRAWTILES_THRESHOLD"));
218 redraw_mask &= ~REDRAW_MAIN;
221 if (redraw_mask & REDRAW_DOORS)
223 if (redraw_mask & REDRAW_DOOR_1)
224 BlitBitmap(backbuffer, window, DX, DY, DXSIZE, DYSIZE, DX, DY);
225 if (redraw_mask & REDRAW_DOOR_2)
227 if ((redraw_mask & REDRAW_DOOR_2) == REDRAW_DOOR_2)
228 BlitBitmap(backbuffer, window, VX,VY, VXSIZE,VYSIZE, VX,VY);
231 if (redraw_mask & REDRAW_VIDEO_1)
232 BlitBitmap(backbuffer, window,
233 VX+VIDEO_DISPLAY1_XPOS,VY+VIDEO_DISPLAY1_YPOS,
234 VIDEO_DISPLAY_XSIZE,VIDEO_DISPLAY_YSIZE,
235 VX+VIDEO_DISPLAY1_XPOS,VY+VIDEO_DISPLAY1_YPOS);
236 if (redraw_mask & REDRAW_VIDEO_2)
237 BlitBitmap(backbuffer, window,
238 VX+VIDEO_DISPLAY2_XPOS,VY+VIDEO_DISPLAY2_YPOS,
239 VIDEO_DISPLAY_XSIZE,VIDEO_DISPLAY_YSIZE,
240 VX+VIDEO_DISPLAY2_XPOS,VY+VIDEO_DISPLAY2_YPOS);
241 if (redraw_mask & REDRAW_VIDEO_3)
242 BlitBitmap(backbuffer, window,
243 VX+VIDEO_CONTROL_XPOS,VY+VIDEO_CONTROL_YPOS,
244 VIDEO_CONTROL_XSIZE,VIDEO_CONTROL_YSIZE,
245 VX+VIDEO_CONTROL_XPOS,VY+VIDEO_CONTROL_YPOS);
249 if (redraw_mask & REDRAW_DOOR_3)
250 BlitBitmap(backbuffer, window, EX, EY, EXSIZE, EYSIZE, EX, EY);
252 redraw_mask &= ~REDRAW_DOORS;
255 if (redraw_mask & REDRAW_MICROLEVEL)
257 BlitBitmap(backbuffer, window, SX, SY + 10 * TILEY, SXSIZE, 7 * TILEY,
258 SX, SY + 10 * TILEY);
260 redraw_mask &= ~REDRAW_MICROLEVEL;
263 if (redraw_mask & REDRAW_TILES)
265 for(x=0; x<SCR_FIELDX; x++)
266 for(y=0; y<SCR_FIELDY; y++)
267 if (redraw[redraw_x1 + x][redraw_y1 + y])
268 BlitBitmap(buffer, window,
269 FX + x * TILEX, FX + y * TILEY, TILEX, TILEY,
270 SX + x * TILEX, SY + y * TILEY);
273 if (redraw_mask & REDRAW_FPS) /* display frames per second */
278 sprintf(info1, " (only every %d. frame)", global.fps_slowdown_factor);
279 if (!global.fps_slowdown)
282 sprintf(text, "%.1f fps%s", global.frames_per_second, info1);
283 DrawTextExt(window, SX, SY, text, FONT_TEXT_2, BLIT_OPAQUE);
288 for(x=0; x<MAX_BUF_XSIZE; x++)
289 for(y=0; y<MAX_BUF_YSIZE; y++)
292 redraw_mask = REDRAW_NONE;
298 long fading_delay = 300;
300 if (setup.fading && (redraw_mask & REDRAW_FIELD))
307 ClearRectangle(window, REAL_SX,REAL_SY,FULL_SXSIZE,FULL_SYSIZE);
310 for(i=0;i<2*FULL_SYSIZE;i++)
312 for(y=0;y<FULL_SYSIZE;y++)
314 BlitBitmap(backbuffer, window,
315 REAL_SX,REAL_SY+i, FULL_SXSIZE,1, REAL_SX,REAL_SY+i);
323 for(i=1;i<FULL_SYSIZE;i+=2)
324 BlitBitmap(backbuffer, window,
325 REAL_SX,REAL_SY+i, FULL_SXSIZE,1, REAL_SX,REAL_SY+i);
331 SetClipOrigin(clip_gc[PIX_FADEMASK], 0, 0);
332 BlitBitmapMasked(backbuffer, window,
333 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
338 SetClipOrigin(clip_gc[PIX_FADEMASK], -1, -1);
339 BlitBitmapMasked(backbuffer, window,
340 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
345 SetClipOrigin(clip_gc[PIX_FADEMASK], 0, -1);
346 BlitBitmapMasked(backbuffer, window,
347 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
352 SetClipOrigin(clip_gc[PIX_FADEMASK], -1, 0);
353 BlitBitmapMasked(backbuffer, window,
354 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
359 redraw_mask &= ~REDRAW_MAIN;
366 void SetMainBackgroundImage(int graphic)
368 SetMainBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
369 graphic_info[graphic].bitmap ?
370 graphic_info[graphic].bitmap :
371 graphic_info[IMG_BACKGROUND].bitmap);
374 void SetDoorBackgroundImage(int graphic)
376 SetDoorBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
377 graphic_info[graphic].bitmap ?
378 graphic_info[graphic].bitmap :
379 graphic_info[IMG_BACKGROUND].bitmap);
382 void DrawBackground(int dest_x, int dest_y, int width, int height)
384 ClearRectangleOnBackground(backbuffer, dest_x, dest_y, width, height);
386 redraw_mask |= REDRAW_FIELD;
391 DrawBackground(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
393 if (setup.soft_scrolling && game_status == GAME_MODE_PLAYING)
395 ClearRectangle(fieldbuffer, 0, 0, FXSIZE, FYSIZE);
396 SetDrawtoField(DRAW_BUFFERED);
399 SetDrawtoField(DRAW_BACKBUFFER);
401 if (setup.direct_draw && game_status == GAME_MODE_PLAYING)
403 ClearRectangle(window, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
404 SetDrawtoField(DRAW_DIRECT);
408 void MarkTileDirty(int x, int y)
410 int xx = redraw_x1 + x;
411 int yy = redraw_y1 + y;
416 redraw[xx][yy] = TRUE;
417 redraw_mask |= REDRAW_TILES;
420 void SetBorderElement()
424 BorderElement = EL_EMPTY;
426 for(y=0; y<lev_fieldy && BorderElement == EL_EMPTY; y++)
428 for(x=0; x<lev_fieldx; x++)
430 if (!IS_INDESTRUCTIBLE(Feld[x][y]))
431 BorderElement = EL_STEELWALL;
433 if (y != 0 && y != lev_fieldy - 1 && x != lev_fieldx - 1)
439 void SetRandomAnimationValue(int x, int y)
441 gfx.anim_random_frame = GfxRandom[x][y];
444 inline int getGraphicAnimationFrame(int graphic, int sync_frame)
446 /* animation synchronized with global frame counter, not move position */
447 if (graphic_info[graphic].anim_global_sync || sync_frame < 0)
448 sync_frame = FrameCounter;
450 return getAnimationFrame(graphic_info[graphic].anim_frames,
451 graphic_info[graphic].anim_delay,
452 graphic_info[graphic].anim_mode,
453 graphic_info[graphic].anim_start_frame,
457 inline void DrawGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
458 int graphic, int sync_frame, int mask_mode)
460 int frame = getGraphicAnimationFrame(graphic, sync_frame);
462 if (mask_mode == USE_MASKING)
463 DrawGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
465 DrawGraphicExt(dst_bitmap, x, y, graphic, frame);
468 inline void DrawGraphicAnimation(int x, int y, int graphic)
470 int lx = LEVELX(x), ly = LEVELY(y);
472 if (!IN_SCR_FIELD(x, y))
475 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
476 graphic, GfxFrame[lx][ly], NO_MASKING);
480 void DrawLevelGraphicAnimation(int x, int y, int graphic)
482 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
485 void DrawLevelElementAnimation(int x, int y, int element)
488 int graphic = el_act_dir2img(element, GfxAction[x][y], MovDir[x][y]);
490 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
492 DrawGraphicAnimation(SCREENX(x), SCREENY(y), el2img(element));
496 inline void DrawLevelGraphicAnimationIfNeeded(int x, int y, int graphic)
498 int sx = SCREENX(x), sy = SCREENY(y);
500 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
503 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
506 DrawGraphicAnimation(sx, sy, graphic);
508 if (CAN_BE_CRUMBLED(Feld[x][y]))
509 DrawLevelFieldCrumbledSand(x, y);
512 void DrawLevelElementAnimationIfNeeded(int x, int y, int element)
514 int sx = SCREENX(x), sy = SCREENY(y);
517 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
520 graphic = el_act_dir2img(element, GfxAction[x][y], MovDir[x][y]);
522 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
525 DrawGraphicAnimation(sx, sy, graphic);
527 if (CAN_BE_CRUMBLED(element))
528 DrawLevelFieldCrumbledSand(x, y);
531 void DrawAllPlayers()
535 for(i=0; i<MAX_PLAYERS; i++)
536 if (stored_player[i].active)
537 DrawPlayer(&stored_player[i]);
540 void DrawPlayerField(int x, int y)
542 if (!IS_PLAYER(x, y))
545 DrawPlayer(PLAYERINFO(x, y));
548 void DrawPlayer(struct PlayerInfo *player)
551 int jx = player->jx, jy = player->jy;
552 int last_jx = player->last_jx, last_jy = player->last_jy;
553 int next_jx = jx + (jx - last_jx), next_jy = jy + (jy - last_jy);
554 int sx = SCREENX(jx), sy = SCREENY(jy);
555 int sxx = 0, syy = 0;
556 int element = Feld[jx][jy], last_element = Feld[last_jx][last_jy];
559 boolean player_is_moving = (last_jx != jx || last_jy != jy ? TRUE : FALSE);
560 int move_dir = player->MovDir;
561 int action = ACTION_DEFAULT;
563 int jx = player->jx, jy = player->jy;
564 int move_dir = player->MovDir;
565 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? +1 : 0);
566 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? +1 : 0);
567 int last_jx = (player->is_moving ? jx - dx : jx);
568 int last_jy = (player->is_moving ? jy - dy : jy);
569 int next_jx = jx + dx;
570 int next_jy = jy + dy;
571 int sx = SCREENX(jx), sy = SCREENY(jy);
572 int sxx = 0, syy = 0;
573 int element = Feld[jx][jy], last_element = Feld[last_jx][last_jy];
576 boolean player_is_moving = (player->MovPos ? TRUE : FALSE);
577 int action = ACTION_DEFAULT;
580 if (!player->active || !IN_SCR_FIELD(SCREENX(last_jx), SCREENY(last_jy)))
584 if (!IN_LEV_FIELD(jx,jy))
586 printf("DrawPlayerField(): x = %d, y = %d\n",jx,jy);
587 printf("DrawPlayerField(): sx = %d, sy = %d\n",sx,sy);
588 printf("DrawPlayerField(): This should never happen!\n");
593 if (element == EL_EXPLOSION)
596 action = (player->Pushing ? ACTION_PUSHING :
597 player->is_digging ? ACTION_DIGGING :
598 player->is_collecting ? ACTION_COLLECTING :
599 player->is_moving ? ACTION_MOVING :
600 player->snapped ? ACTION_SNAPPING : ACTION_DEFAULT);
603 printf("::: '%s'\n", element_action_info[action].suffix);
606 InitPlayerGfxAnimation(player, action, move_dir);
608 /* ----------------------------------------------------------------------- */
609 /* draw things in the field the player is leaving, if needed */
610 /* ----------------------------------------------------------------------- */
613 if (player->is_moving)
615 if (player_is_moving)
618 if (Back[last_jx][last_jy] && IS_DRAWABLE(last_element))
620 DrawLevelElement(last_jx, last_jy, Back[last_jx][last_jy]);
622 if (last_element == EL_DYNAMITE_ACTIVE ||
623 last_element == EL_SP_DISK_RED_ACTIVE)
624 DrawDynamite(last_jx, last_jy);
626 DrawLevelFieldThruMask(last_jx, last_jy);
628 else if (last_element == EL_DYNAMITE_ACTIVE ||
629 last_element == EL_SP_DISK_RED_ACTIVE)
630 DrawDynamite(last_jx, last_jy);
632 DrawLevelField(last_jx, last_jy);
634 if (player->Pushing && IN_SCR_FIELD(SCREENX(next_jx), SCREENY(next_jy)))
638 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
642 if (Feld[next_jx][next_jy] == EL_SOKOBAN_FIELD_FULL)
643 DrawLevelElement(next_jx, next_jy, EL_SOKOBAN_FIELD_EMPTY);
645 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
648 DrawLevelField(next_jx, next_jy);
654 if (!IN_SCR_FIELD(sx, sy))
657 if (setup.direct_draw)
658 SetDrawtoField(DRAW_BUFFERED);
660 /* ----------------------------------------------------------------------- */
661 /* draw things behind the player, if needed */
662 /* ----------------------------------------------------------------------- */
665 DrawLevelElement(jx, jy, Back[jx][jy]);
666 else if (IS_ACTIVE_BOMB(element))
667 DrawLevelElement(jx, jy, EL_EMPTY);
670 if (player_is_moving && GfxElement[jx][jy] != EL_UNDEFINED)
673 if (CAN_BE_CRUMBLED(GfxElement[jx][jy]))
674 DrawLevelFieldCrumbledSandDigging(jx, jy, move_dir, player->StepFrame);
676 if (GfxElement[jx][jy] == EL_SAND)
677 DrawLevelFieldCrumbledSandDigging(jx, jy, move_dir, player->StepFrame);
681 int old_element = GfxElement[jx][jy];
682 int old_graphic = el_act_dir2img(old_element, action, move_dir);
683 int frame = getGraphicAnimationFrame(old_graphic, player->StepFrame);
685 DrawGraphic(sx, sy, old_graphic, frame);
690 GfxElement[jx][jy] = EL_UNDEFINED;
692 DrawLevelField(jx, jy);
696 /* ----------------------------------------------------------------------- */
697 /* draw player himself */
698 /* ----------------------------------------------------------------------- */
700 if (player->use_murphy_graphic)
702 static int last_horizontal_dir = MV_LEFT;
705 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
706 last_horizontal_dir = move_dir;
708 direction = (player->snapped ? move_dir : last_horizontal_dir);
710 graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, direction);
713 graphic = el_act_dir2img(player->element_nr, player->GfxAction, move_dir);
715 frame = getGraphicAnimationFrame(graphic, player->Frame);
719 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
720 sxx = player->GfxPos;
722 syy = player->GfxPos;
725 if (!setup.soft_scrolling && ScreenMovPos)
728 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
730 if (SHIELD_ON(player))
732 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
733 IMG_SHIELD_NORMAL_ACTIVE);
734 int frame = getGraphicAnimationFrame(graphic, -1);
736 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
739 /* ----------------------------------------------------------------------- */
740 /* draw things the player is pushing, if needed */
741 /* ----------------------------------------------------------------------- */
744 printf("::: %d, %d [%d, %d] [%d]\n",
745 player->Pushing, player_is_moving, player->GfxAction,
746 player->is_moving, player_is_moving);
750 if (player->Pushing && player->is_moving)
752 if (player->Pushing && player_is_moving)
755 int px = SCREENX(next_jx), py = SCREENY(next_jy);
757 if (Back[next_jx][next_jy])
758 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
761 if ((sxx || syy) && element == EL_SOKOBAN_OBJECT)
762 DrawGraphicShiftedThruMask(px, py, sxx, syy, IMG_SOKOBAN_OBJECT, 0,
766 (element == EL_SOKOBAN_FIELD_EMPTY ||
767 Feld[next_jx][next_jy] == EL_SOKOBAN_FIELD_FULL))
768 DrawGraphicShiftedThruMask(px, py, sxx, syy, IMG_SOKOBAN_OBJECT, 0,
774 int element = MovingOrBlocked2Element(next_jx, next_jy);
777 int element = Feld[jx][jy];
779 int element = Feld[next_jx][next_jy];
784 int graphic = el2img(element);
788 if ((sxx || syy) && IS_PUSHABLE(element))
791 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
792 frame = getGraphicAnimationFrame(graphic, player->Frame);
796 printf("::: pushing %d: %d ...\n", sxx, frame);
799 DrawGraphicShifted(px, py, sxx, syy, graphic, frame,
800 NO_CUTTING, NO_MASKING);
805 /* ----------------------------------------------------------------------- */
806 /* draw things in front of player (active dynamite or dynabombs) */
807 /* ----------------------------------------------------------------------- */
809 if (IS_ACTIVE_BOMB(element))
811 graphic = el2img(element);
812 frame = getGraphicAnimationFrame(graphic, GfxFrame[jx][jy]);
814 if (game.emulation == EMU_SUPAPLEX)
815 DrawGraphic(sx, sy, IMG_SP_DISK_RED, frame);
817 DrawGraphicThruMask(sx, sy, graphic, frame);
820 if (player_is_moving && last_element == EL_EXPLOSION)
823 int graphic = el_act2img(GfxElement[last_jx][last_jy], ACTION_EXPLODING);
825 int stored = Store[last_jx][last_jy];
826 int graphic = (game.emulation != EMU_SUPAPLEX ? IMG_EXPLOSION :
827 stored == EL_SP_INFOTRON ? IMG_SP_EXPLOSION_INFOTRON :
830 int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
831 int phase = ExplodePhase[last_jx][last_jy] - 1;
832 int frame = getGraphicAnimationFrame(graphic, phase - delay);
835 DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy), graphic, frame);
838 /* ----------------------------------------------------------------------- */
839 /* draw elements the player is just walking/passing through/under */
840 /* ----------------------------------------------------------------------- */
842 /* handle the field the player is leaving ... */
843 if (player_is_moving && IS_ACCESSIBLE_INSIDE(last_element))
844 DrawLevelField(last_jx, last_jy);
845 else if (player_is_moving && IS_ACCESSIBLE_UNDER(last_element))
846 DrawLevelFieldThruMask(last_jx, last_jy);
848 /* ... and the field the player is entering */
849 if (IS_ACCESSIBLE_INSIDE(element))
850 DrawLevelField(jx, jy);
851 else if (IS_ACCESSIBLE_UNDER(element))
852 DrawLevelFieldThruMask(jx, jy);
854 if (setup.direct_draw)
856 int dest_x = SX + SCREENX(MIN(jx, last_jx)) * TILEX;
857 int dest_y = SY + SCREENY(MIN(jy, last_jy)) * TILEY;
858 int x_size = TILEX * (1 + ABS(jx - last_jx));
859 int y_size = TILEY * (1 + ABS(jy - last_jy));
861 BlitBitmap(drawto_field, window,
862 dest_x, dest_y, x_size, y_size, dest_x, dest_y);
863 SetDrawtoField(DRAW_DIRECT);
866 MarkTileDirty(sx,sy);
869 void getGraphicSource(int graphic, int frame, Bitmap **bitmap, int *x, int *y)
871 struct GraphicInfo *g = &graphic_info[graphic];
875 if (g->offset_y == 0) /* frames are ordered horizontally */
877 int max_width = g->anim_frames_per_line * g->width;
879 *x = (g->src_x + frame * g->offset_x) % max_width;
880 *y = g->src_y + (g->src_x + frame * g->offset_x) / max_width * g->height;
882 else if (g->offset_x == 0) /* frames are ordered vertically */
884 int max_height = g->anim_frames_per_line * g->height;
886 *x = g->src_x + (g->src_y + frame * g->offset_y) / max_height * g->width;
887 *y = (g->src_y + frame * g->offset_y) % max_height;
889 else /* frames are ordered diagonally */
891 *x = g->src_x + frame * g->offset_x;
892 *y = g->src_y + frame * g->offset_y;
896 void DrawGraphic(int x, int y, int graphic, int frame)
899 if (!IN_SCR_FIELD(x, y))
901 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
902 printf("DrawGraphic(): This should never happen!\n");
907 DrawGraphicExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic, frame);
911 void DrawGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
917 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
918 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
921 void DrawGraphicThruMask(int x, int y, int graphic, int frame)
924 if (!IN_SCR_FIELD(x, y))
926 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
927 printf("DrawGraphicThruMask(): This should never happen!\n");
932 DrawGraphicThruMaskExt(drawto_field, FX + x * TILEX, FY + y *TILEY, graphic,
937 void DrawGraphicThruMaskExt(DrawBuffer *d, int dest_x, int dest_y, int graphic,
945 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
946 drawing_gc = src_bitmap->stored_clip_gc;
948 GC drawing_gc = src_bitmap->stored_clip_gc;
949 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
950 int src_x = graphic_info[graphic].src_x;
951 int src_y = graphic_info[graphic].src_y;
952 int offset_x = graphic_info[graphic].offset_x;
953 int offset_y = graphic_info[graphic].offset_y;
955 src_x += frame * offset_x;
956 src_y += frame * offset_y;
960 SetClipOrigin(src_bitmap, drawing_gc, dest_x - src_x, dest_y - src_y);
961 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX, TILEY, dest_x, dest_y);
964 void DrawMiniGraphic(int x, int y, int graphic)
966 DrawMiniGraphicExt(drawto, SX + x * MINI_TILEX,SY + y * MINI_TILEY, graphic);
967 MarkTileDirty(x / 2, y / 2);
970 void getMiniGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
972 struct GraphicInfo *g = &graphic_info[graphic];
974 int mini_starty = g->bitmap->height * 2 / 3;
977 *x = mini_startx + g->src_x / 2;
978 *y = mini_starty + g->src_y / 2;
981 void DrawMiniGraphicExt(DrawBuffer *d, int x, int y, int graphic)
986 getMiniGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
987 BlitBitmap(src_bitmap, d, src_x, src_y, MINI_TILEX, MINI_TILEY, x, y);
990 void DrawGraphicShifted(int x,int y, int dx,int dy, int graphic, int frame,
991 int cut_mode, int mask_mode)
996 int width = TILEX, height = TILEY;
1002 DrawGraphic(x, y, graphic, frame);
1006 if (dx || dy) /* shifted graphic */
1008 if (x < BX1) /* object enters playfield from the left */
1015 else if (x > BX2) /* object enters playfield from the right */
1021 else if (x==BX1 && dx < 0) /* object leaves playfield to the left */
1027 else if (x==BX2 && dx > 0) /* object leaves playfield to the right */
1029 else if (dx) /* general horizontal movement */
1030 MarkTileDirty(x + SIGN(dx), y);
1032 if (y < BY1) /* object enters playfield from the top */
1034 if (cut_mode==CUT_BELOW) /* object completely above top border */
1042 else if (y > BY2) /* object enters playfield from the bottom */
1048 else if (y==BY1 && dy < 0) /* object leaves playfield to the top */
1054 else if (dy > 0 && cut_mode == CUT_ABOVE)
1056 if (y == BY2) /* object completely above bottom border */
1062 MarkTileDirty(x, y + 1);
1063 } /* object leaves playfield to the bottom */
1064 else if (dy > 0 && (y == BY2 || cut_mode == CUT_BELOW))
1066 else if (dy) /* general vertical movement */
1067 MarkTileDirty(x, y + SIGN(dy));
1071 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1073 src_bitmap = graphic_info[graphic].bitmap;
1074 src_x = graphic_info[graphic].src_x;
1075 src_y = graphic_info[graphic].src_y;
1076 offset_x = graphic_info[graphic].offset_x;
1077 offset_y = graphic_info[graphic].offset_y;
1079 src_x += frame * offset_x;
1080 src_y += frame * offset_y;
1083 drawing_gc = src_bitmap->stored_clip_gc;
1088 dest_x = FX + x * TILEX + dx;
1089 dest_y = FY + y * TILEY + dy;
1092 if (!IN_SCR_FIELD(x,y))
1094 printf("DrawGraphicShifted(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
1095 printf("DrawGraphicShifted(): This should never happen!\n");
1100 if (mask_mode == USE_MASKING)
1102 SetClipOrigin(src_bitmap, drawing_gc, dest_x - src_x, dest_y - src_y);
1103 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1107 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1113 void DrawGraphicShiftedThruMask(int x, int y, int dx, int dy, int graphic,
1114 int frame, int cut_mode)
1116 DrawGraphicShifted(x,y, dx,dy, graphic, frame, cut_mode, USE_MASKING);
1119 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
1120 int cut_mode, int mask_mode)
1122 int lx = LEVELX(x), ly = LEVELY(y);
1126 if (IN_LEV_FIELD(lx, ly))
1128 SetRandomAnimationValue(lx, ly);
1130 graphic = el_act_dir2img(element, GfxAction[lx][ly], MovDir[lx][ly]);
1131 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1133 else /* border element */
1135 graphic = el2img(element);
1136 frame = getGraphicAnimationFrame(graphic, -1);
1139 if (element == EL_EXPANDABLE_WALL)
1141 boolean left_stopped = FALSE, right_stopped = FALSE;
1143 if (!IN_LEV_FIELD(lx - 1, ly) || IS_WALL(Feld[lx - 1][ly]))
1144 left_stopped = TRUE;
1145 if (!IN_LEV_FIELD(lx + 1, ly) || IS_WALL(Feld[lx + 1][ly]))
1146 right_stopped = TRUE;
1148 if (left_stopped && right_stopped)
1150 else if (left_stopped)
1152 graphic = IMG_EXPANDABLE_WALL_GROWING_RIGHT;
1153 frame = graphic_info[graphic].anim_frames - 1;
1155 else if (right_stopped)
1157 graphic = IMG_EXPANDABLE_WALL_GROWING_LEFT;
1158 frame = graphic_info[graphic].anim_frames - 1;
1163 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, mask_mode);
1164 else if (mask_mode == USE_MASKING)
1165 DrawGraphicThruMask(x, y, graphic, frame);
1167 DrawGraphic(x, y, graphic, frame);
1170 void DrawLevelElementExt(int x, int y, int dx, int dy, int element,
1171 int cut_mode, int mask_mode)
1173 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1174 DrawScreenElementExt(SCREENX(x), SCREENY(y), dx, dy, element,
1175 cut_mode, mask_mode);
1178 void DrawScreenElementShifted(int x, int y, int dx, int dy, int element,
1181 DrawScreenElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1184 void DrawLevelElementShifted(int x, int y, int dx, int dy, int element,
1187 DrawLevelElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1190 void DrawLevelElementThruMask(int x, int y, int element)
1192 DrawLevelElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1195 void DrawLevelFieldThruMask(int x, int y)
1197 DrawLevelElementExt(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
1200 static void DrawLevelFieldCrumbledSandExt(int x, int y, int graphic, int frame)
1204 int sx = SCREENX(x), sy = SCREENY(y);
1206 int width, height, cx, cy, i;
1207 int snip = TILEX / 8; /* number of border pixels from "crumbled graphic" */
1208 static int xy[4][2] =
1216 if (!IN_LEV_FIELD(x, y))
1219 element = (GfxElement[x][y] != EL_UNDEFINED && Feld[x][y] != EL_EXPLOSION ?
1220 GfxElement[x][y] : Feld[x][y]);
1222 /* crumble field itself */
1223 if (CAN_BE_CRUMBLED(element) && !IS_MOVING(x, y))
1225 if (!IN_SCR_FIELD(sx, sy))
1228 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1232 int xx = x + xy[i][0];
1233 int yy = y + xy[i][1];
1235 element = (IN_LEV_FIELD(xx, yy) ? Feld[xx][yy] : BorderElement);
1237 /* check if neighbour field is of same type */
1238 if (CAN_BE_CRUMBLED(element) && !IS_MOVING(xx, yy))
1242 if (Feld[x][y] == EL_CUSTOM_START + 123)
1243 printf("::: crumble [%d] THE CHAOS ENGINE (%d, %d): %d, %d\n",
1244 i, Feld[x][y], element,
1245 CAN_BE_CRUMBLED(element), IS_MOVING(x, y));
1248 if (i == 1 || i == 2)
1252 cx = (i == 2 ? TILEX - snip : 0);
1260 cy = (i == 3 ? TILEY - snip : 0);
1263 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1264 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
1267 MarkTileDirty(sx, sy);
1269 else /* crumble neighbour fields */
1271 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1275 int xx = x + xy[i][0];
1276 int yy = y + xy[i][1];
1277 int sxx = sx + xy[i][0];
1278 int syy = sy + xy[i][1];
1280 if (!IN_LEV_FIELD(xx, yy) ||
1281 !IN_SCR_FIELD(sxx, syy) ||
1282 !CAN_BE_CRUMBLED(Feld[xx][yy]) ||
1286 if (i == 1 || i == 2)
1290 cx = (i == 1 ? TILEX - snip : 0);
1298 cy = (i==0 ? TILEY-snip : 0);
1301 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1302 width, height, FX + sxx * TILEX + cx, FY + syy * TILEY + cy);
1304 MarkTileDirty(sxx, syy);
1309 void DrawLevelFieldCrumbledSand(int x, int y)
1311 DrawLevelFieldCrumbledSandExt(x, y, IMG_SAND_CRUMBLED, 0);
1314 void DrawLevelFieldCrumbledSandDigging(int x, int y, int direction,
1318 int graphic1 = el_act_dir2img(GfxElement[x][y], ACTION_DIGGING, direction);
1319 int graphic2 = el_act_dir2crm(GfxElement[x][y], ACTION_DIGGING, direction);
1321 int graphic1 = el_act_dir2img(EL_SAND, ACTION_DIGGING, direction);
1322 int graphic2 = el_act_dir2img(EL_SAND_CRUMBLED, ACTION_DIGGING, direction);
1324 int frame1 = getGraphicAnimationFrame(graphic1, step_frame);
1325 int frame2 = getGraphicAnimationFrame(graphic2, step_frame);
1326 int sx = SCREENX(x), sy = SCREENY(y);
1328 DrawGraphic(sx, sy, graphic1, frame1);
1329 DrawLevelFieldCrumbledSandExt(x, y, graphic2, frame2);
1332 void DrawLevelFieldCrumbledSandNeighbours(int x, int y)
1334 int sx = SCREENX(x), sy = SCREENY(y);
1335 static int xy[4][2] =
1346 int xx = x + xy[i][0];
1347 int yy = y + xy[i][1];
1348 int sxx = sx + xy[i][0];
1349 int syy = sy + xy[i][1];
1351 if (!IN_LEV_FIELD(xx, yy) ||
1352 !IN_SCR_FIELD(sxx, syy) ||
1353 !CAN_BE_CRUMBLED(Feld[xx][yy]) ||
1357 DrawLevelField(xx, yy);
1361 static int getBorderElement(int x, int y)
1365 { EL_STEELWALL_TOPLEFT, EL_INVISIBLE_STEELWALL_TOPLEFT },
1366 { EL_STEELWALL_TOPRIGHT, EL_INVISIBLE_STEELWALL_TOPRIGHT },
1367 { EL_STEELWALL_BOTTOMLEFT, EL_INVISIBLE_STEELWALL_BOTTOMLEFT },
1368 { EL_STEELWALL_BOTTOMRIGHT, EL_INVISIBLE_STEELWALL_BOTTOMRIGHT },
1369 { EL_STEELWALL_VERTICAL, EL_INVISIBLE_STEELWALL_VERTICAL },
1370 { EL_STEELWALL_HORIZONTAL, EL_INVISIBLE_STEELWALL_HORIZONTAL },
1371 { EL_STEELWALL, EL_INVISIBLE_STEELWALL }
1373 int steel_type = (BorderElement == EL_STEELWALL ? 0 : 1);
1374 int steel_position = (x == -1 && y == -1 ? 0 :
1375 x == lev_fieldx && y == -1 ? 1 :
1376 x == -1 && y == lev_fieldy ? 2 :
1377 x == lev_fieldx && y == lev_fieldy ? 3 :
1378 x == -1 || x == lev_fieldx ? 4 :
1379 y == -1 || y == lev_fieldy ? 5 : 6);
1381 return border[steel_position][steel_type];
1384 void DrawScreenElement(int x, int y, int element)
1386 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
1387 DrawLevelFieldCrumbledSand(LEVELX(x), LEVELY(y));
1390 void DrawLevelElement(int x, int y, int element)
1392 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1393 DrawScreenElement(SCREENX(x), SCREENY(y), element);
1396 void DrawScreenField(int x, int y)
1398 int lx = LEVELX(x), ly = LEVELY(y);
1399 int element, content;
1401 if (!IN_LEV_FIELD(lx, ly))
1403 if (lx < -1 || lx > lev_fieldx || ly < -1 || ly > lev_fieldy)
1406 element = getBorderElement(lx, ly);
1408 DrawScreenElement(x, y, element);
1412 element = Feld[lx][ly];
1413 content = Store[lx][ly];
1415 if (IS_MOVING(lx, ly))
1417 int horiz_move = (MovDir[lx][ly] == MV_LEFT || MovDir[lx][ly] == MV_RIGHT);
1418 boolean cut_mode = NO_CUTTING;
1420 if (element == EL_QUICKSAND_EMPTYING ||
1421 element == EL_MAGIC_WALL_EMPTYING ||
1422 element == EL_BD_MAGIC_WALL_EMPTYING ||
1423 element == EL_AMOEBA_DROPPING)
1424 cut_mode = CUT_ABOVE;
1425 else if (element == EL_QUICKSAND_FILLING ||
1426 element == EL_MAGIC_WALL_FILLING ||
1427 element == EL_BD_MAGIC_WALL_FILLING)
1428 cut_mode = CUT_BELOW;
1430 if (cut_mode == CUT_ABOVE)
1431 DrawScreenElementShifted(x, y, 0, 0, element, NO_CUTTING);
1433 DrawScreenElement(x, y, EL_EMPTY);
1436 DrawScreenElementShifted(x, y, MovPos[lx][ly], 0, element, NO_CUTTING);
1437 else if (cut_mode == NO_CUTTING)
1438 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], element, cut_mode);
1440 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], content, cut_mode);
1442 if (content == EL_ACID)
1443 DrawLevelElementThruMask(lx, ly + 1, EL_ACID);
1445 else if (IS_BLOCKED(lx, ly))
1450 boolean cut_mode = NO_CUTTING;
1451 int element_old, content_old;
1453 Blocked2Moving(lx, ly, &oldx, &oldy);
1456 horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
1457 MovDir[oldx][oldy] == MV_RIGHT);
1459 element_old = Feld[oldx][oldy];
1460 content_old = Store[oldx][oldy];
1462 if (element_old == EL_QUICKSAND_EMPTYING ||
1463 element_old == EL_MAGIC_WALL_EMPTYING ||
1464 element_old == EL_BD_MAGIC_WALL_EMPTYING ||
1465 element_old == EL_AMOEBA_DROPPING)
1466 cut_mode = CUT_ABOVE;
1468 DrawScreenElement(x, y, EL_EMPTY);
1471 DrawScreenElementShifted(sx, sy, MovPos[oldx][oldy], 0, element_old,
1473 else if (cut_mode == NO_CUTTING)
1474 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], element_old,
1477 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], content_old,
1480 else if (IS_DRAWABLE(element))
1481 DrawScreenElement(x, y, element);
1483 DrawScreenElement(x, y, EL_EMPTY);
1486 void DrawLevelField(int x, int y)
1488 if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1489 DrawScreenField(SCREENX(x), SCREENY(y));
1490 else if (IS_MOVING(x, y))
1494 Moving2Blocked(x, y, &newx, &newy);
1495 if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
1496 DrawScreenField(SCREENX(newx), SCREENY(newy));
1498 else if (IS_BLOCKED(x, y))
1502 Blocked2Moving(x, y, &oldx, &oldy);
1503 if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
1504 DrawScreenField(SCREENX(oldx), SCREENY(oldy));
1508 void DrawMiniElement(int x, int y, int element)
1512 graphic = el2edimg(element);
1513 DrawMiniGraphic(x, y, graphic);
1516 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
1518 int x = sx + scroll_x, y = sy + scroll_y;
1520 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
1521 DrawMiniElement(sx, sy, EL_EMPTY);
1522 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
1523 DrawMiniElement(sx, sy, Feld[x][y]);
1525 DrawMiniGraphic(sx, sy, el2edimg(getBorderElement(x, y)));
1528 void DrawEnvelopeBorder(int sx, int sy, int ex, int ey)
1532 { EL_STEELWALL_TOPLEFT, EL_INVISIBLE_STEELWALL_TOPLEFT },
1533 { EL_STEELWALL_TOPRIGHT, EL_INVISIBLE_STEELWALL_TOPRIGHT },
1534 { EL_STEELWALL_BOTTOMLEFT, EL_INVISIBLE_STEELWALL_BOTTOMLEFT },
1535 { EL_STEELWALL_BOTTOMRIGHT, EL_INVISIBLE_STEELWALL_BOTTOMRIGHT },
1536 { EL_STEELWALL_VERTICAL, EL_INVISIBLE_STEELWALL_VERTICAL },
1537 { EL_STEELWALL_HORIZONTAL, EL_INVISIBLE_STEELWALL_HORIZONTAL },
1538 { EL_STEELWALL, EL_INVISIBLE_STEELWALL },
1539 { EL_EMPTY, EL_EMPTY }
1541 int steel_type = (BorderElement == EL_STEELWALL ? 0 : 1);
1542 int steel_position = (ex == -1 && ey == -1 ? 0 :
1543 ex == +1 && ey == -1 ? 1 :
1544 ex == -1 && ey == +1 ? 2 :
1545 ex == +1 && ey == +1 ? 3 :
1546 ex == -1 || ex == +1 ? 4 :
1547 ey == -1 || ey == +1 ? 5 : 7);
1548 int element = border[steel_position][steel_type];
1550 DrawMiniGraphic(sx, sy, el2edimg(element));
1553 void getMicroGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
1555 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
1556 int mini_startx = src_bitmap->width * 3 / 4;
1557 int mini_starty = src_bitmap->height * 2 / 3;
1558 int src_x = mini_startx + graphic_info[graphic].src_x / 8;
1559 int src_y = mini_starty + graphic_info[graphic].src_y / 8;
1561 *bitmap = src_bitmap;
1566 void DrawMicroElement(int xpos, int ypos, int element)
1570 int graphic = el2preimg(element);
1572 getMicroGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
1573 BlitBitmap(src_bitmap, drawto, src_x, src_y, MICRO_TILEX, MICRO_TILEY,
1581 SetDrawBackgroundMask(REDRAW_NONE);
1584 for(x=BX1; x<=BX2; x++)
1585 for(y=BY1; y<=BY2; y++)
1586 DrawScreenField(x, y);
1588 redraw_mask |= REDRAW_FIELD;
1591 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
1595 for(x=0; x<size_x; x++)
1596 for(y=0; y<size_y; y++)
1597 DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
1599 redraw_mask |= REDRAW_FIELD;
1602 static void DrawMicroLevelExt(int xpos, int ypos, int from_x, int from_y)
1606 DrawBackground(xpos, ypos, MICROLEV_XSIZE, MICROLEV_YSIZE);
1608 if (lev_fieldx < STD_LEV_FIELDX)
1609 xpos += (STD_LEV_FIELDX - lev_fieldx) / 2 * MICRO_TILEX;
1610 if (lev_fieldy < STD_LEV_FIELDY)
1611 ypos += (STD_LEV_FIELDY - lev_fieldy) / 2 * MICRO_TILEY;
1613 xpos += MICRO_TILEX;
1614 ypos += MICRO_TILEY;
1616 for(x=-1; x<=STD_LEV_FIELDX; x++)
1618 for(y=-1; y<=STD_LEV_FIELDY; y++)
1620 int lx = from_x + x, ly = from_y + y;
1622 if (lx >= 0 && lx < lev_fieldx && ly >= 0 && ly < lev_fieldy)
1623 DrawMicroElement(xpos + x * MICRO_TILEX, ypos + y * MICRO_TILEY,
1624 level.field[lx][ly]);
1625 else if (lx >= -1 && lx < lev_fieldx+1 && ly >= -1 && ly < lev_fieldy+1
1626 && BorderElement != EL_EMPTY)
1627 DrawMicroElement(xpos + x * MICRO_TILEX, ypos + y * MICRO_TILEY,
1628 getBorderElement(lx, ly));
1632 redraw_mask |= REDRAW_MICROLEVEL;
1635 #define MICROLABEL_EMPTY 0
1636 #define MICROLABEL_LEVEL_NAME 1
1637 #define MICROLABEL_CREATED_BY 2
1638 #define MICROLABEL_LEVEL_AUTHOR 3
1639 #define MICROLABEL_IMPORTED_FROM 4
1640 #define MICROLABEL_LEVEL_IMPORT_INFO 5
1642 static void DrawMicroLevelLabelExt(int mode)
1644 char label_text[MAX_OUTPUT_LINESIZE + 1];
1645 int max_len_label_text;
1646 int font_nr = FONT_TEXT_2;
1648 if (mode == MICROLABEL_CREATED_BY || mode == MICROLABEL_IMPORTED_FROM)
1649 font_nr = FONT_TEXT_3;
1651 max_len_label_text = SXSIZE / getFontWidth(font_nr);
1653 DrawBackground(SX, MICROLABEL_YPOS, SXSIZE, getFontHeight(font_nr));
1655 strncpy(label_text, (mode == MICROLABEL_LEVEL_NAME ? level.name :
1656 mode == MICROLABEL_CREATED_BY ? "created by" :
1657 mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
1658 mode == MICROLABEL_IMPORTED_FROM ? "imported from" :
1659 mode == MICROLABEL_LEVEL_IMPORT_INFO ?
1660 leveldir_current->imported_from : ""),
1661 max_len_label_text);
1662 label_text[max_len_label_text] = '\0';
1664 if (strlen(label_text) > 0)
1666 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
1667 int lypos = MICROLABEL_YPOS;
1669 DrawText(lxpos, lypos, label_text, font_nr);
1672 redraw_mask |= REDRAW_MICROLEVEL;
1675 void DrawMicroLevel(int xpos, int ypos, boolean restart)
1677 static unsigned long scroll_delay = 0;
1678 static unsigned long label_delay = 0;
1679 static int from_x, from_y, scroll_direction;
1680 static int label_state, label_counter;
1681 int last_game_status = game_status; /* save current game status */
1683 /* force PREVIEW font on preview level */
1684 game_status = GAME_MODE_PSEUDO_PREVIEW;
1688 from_x = from_y = 0;
1689 scroll_direction = MV_RIGHT;
1693 DrawMicroLevelExt(xpos, ypos, from_x, from_y);
1694 DrawMicroLevelLabelExt(label_state);
1696 /* initialize delay counters */
1697 DelayReached(&scroll_delay, 0);
1698 DelayReached(&label_delay, 0);
1700 if (leveldir_current->name)
1702 int text_width = getTextWidth(leveldir_current->name, FONT_TEXT_1);
1703 int lxpos = SX + (SXSIZE - text_width) / 2;
1704 int lypos = SY + 352;
1706 DrawText(lxpos, lypos, leveldir_current->name, FONT_TEXT_1);
1709 game_status = last_game_status; /* restore current game status */
1714 /* scroll micro level, if needed */
1715 if ((lev_fieldx > STD_LEV_FIELDX || lev_fieldy > STD_LEV_FIELDY) &&
1716 DelayReached(&scroll_delay, MICROLEVEL_SCROLL_DELAY))
1718 switch (scroll_direction)
1724 scroll_direction = MV_UP;
1728 if (from_x < lev_fieldx - STD_LEV_FIELDX)
1731 scroll_direction = MV_DOWN;
1738 scroll_direction = MV_RIGHT;
1742 if (from_y < lev_fieldy - STD_LEV_FIELDY)
1745 scroll_direction = MV_LEFT;
1752 DrawMicroLevelExt(xpos, ypos, from_x, from_y);
1755 /* redraw micro level label, if needed */
1756 if (strcmp(level.name, NAMELESS_LEVEL_NAME) != 0 &&
1757 strcmp(level.author, ANONYMOUS_NAME) != 0 &&
1758 strcmp(level.author, leveldir_current->name) != 0 &&
1759 DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
1761 int max_label_counter = 23;
1763 if (leveldir_current->imported_from != NULL)
1764 max_label_counter += 14;
1766 label_counter = (label_counter + 1) % max_label_counter;
1767 label_state = (label_counter >= 0 && label_counter <= 7 ?
1768 MICROLABEL_LEVEL_NAME :
1769 label_counter >= 9 && label_counter <= 12 ?
1770 MICROLABEL_CREATED_BY :
1771 label_counter >= 14 && label_counter <= 21 ?
1772 MICROLABEL_LEVEL_AUTHOR :
1773 label_counter >= 23 && label_counter <= 26 ?
1774 MICROLABEL_IMPORTED_FROM :
1775 label_counter >= 28 && label_counter <= 35 ?
1776 MICROLABEL_LEVEL_IMPORT_INFO : MICROLABEL_EMPTY);
1777 DrawMicroLevelLabelExt(label_state);
1780 game_status = last_game_status; /* restore current game status */
1783 void WaitForEventToContinue()
1785 boolean still_wait = TRUE;
1787 /* simulate releasing mouse button over last gadget, if still pressed */
1789 HandleGadgets(-1, -1, 0);
1791 button_status = MB_RELEASED;
1803 case EVENT_BUTTONPRESS:
1804 case EVENT_KEYPRESS:
1808 case EVENT_KEYRELEASE:
1809 ClearPlayerAction();
1813 HandleOtherEvents(&event);
1817 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
1824 /* don't eat all CPU time */
1829 #define MAX_REQUEST_LINES 13
1830 #define MAX_REQUEST_LINE_LEN 7
1832 boolean Request(char *text, unsigned int req_state)
1834 int mx, my, ty, result = -1;
1835 unsigned int old_door_state;
1836 int last_game_status = game_status; /* save current game status */
1839 SetMouseCursor(CURSOR_DEFAULT);
1842 #if defined(PLATFORM_UNIX)
1843 /* pause network game while waiting for request to answer */
1844 if (options.network &&
1845 game_status == GAME_MODE_PLAYING &&
1846 req_state & REQUEST_WAIT_FOR)
1847 SendToServer_PausePlaying();
1850 old_door_state = GetDoorState();
1852 /* simulate releasing mouse button over last gadget, if still pressed */
1854 HandleGadgets(-1, -1, 0);
1858 CloseDoor(DOOR_CLOSE_1);
1860 /* save old door content */
1861 BlitBitmap(bitmap_db_door, bitmap_db_door,
1862 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
1863 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
1865 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
1867 /* clear door drawing field */
1868 DrawBackground(DX, DY, DXSIZE, DYSIZE);
1870 /* force DOOR font on preview level */
1871 game_status = GAME_MODE_PSEUDO_DOOR;
1873 /* write text for request */
1874 for(ty=0; ty < MAX_REQUEST_LINES; ty++)
1876 char text_line[MAX_REQUEST_LINE_LEN + 1];
1882 for(tl=0,tx=0; tx < MAX_REQUEST_LINE_LEN; tl++,tx++)
1885 if (!tc || tc == ' ')
1896 strncpy(text_line, text, tl);
1899 DrawText(DX + (DXSIZE - tl * getFontWidth(FONT_TEXT_2)) / 2,
1900 DY + 8 + ty * (getFontHeight(FONT_TEXT_2) + 2),
1901 text_line, FONT_TEXT_2);
1903 text += tl + (tc == ' ' ? 1 : 0);
1906 game_status = last_game_status; /* restore current game status */
1908 if (req_state & REQ_ASK)
1910 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
1911 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
1913 else if (req_state & REQ_CONFIRM)
1915 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
1917 else if (req_state & REQ_PLAYER)
1919 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
1920 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
1921 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
1922 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
1925 /* copy request gadgets to door backbuffer */
1926 BlitBitmap(drawto, bitmap_db_door,
1927 DX, DY, DXSIZE, DYSIZE,
1928 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
1930 OpenDoor(DOOR_OPEN_1);
1936 if (!(req_state & REQUEST_WAIT_FOR))
1938 SetDrawBackgroundMask(REDRAW_FIELD);
1943 if (game_status != GAME_MODE_MAIN)
1946 button_status = MB_RELEASED;
1948 request_gadget_id = -1;
1950 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
1953 SetMouseCursor(CURSOR_DEFAULT);
1966 case EVENT_BUTTONPRESS:
1967 case EVENT_BUTTONRELEASE:
1968 case EVENT_MOTIONNOTIFY:
1970 if (event.type == EVENT_MOTIONNOTIFY)
1972 if (!PointerInWindow(window))
1973 continue; /* window and pointer are on different screens */
1978 motion_status = TRUE;
1979 mx = ((MotionEvent *) &event)->x;
1980 my = ((MotionEvent *) &event)->y;
1984 motion_status = FALSE;
1985 mx = ((ButtonEvent *) &event)->x;
1986 my = ((ButtonEvent *) &event)->y;
1987 if (event.type == EVENT_BUTTONPRESS)
1988 button_status = ((ButtonEvent *) &event)->button;
1990 button_status = MB_RELEASED;
1993 /* this sets 'request_gadget_id' */
1994 HandleGadgets(mx, my, button_status);
1996 switch(request_gadget_id)
1998 case TOOL_CTRL_ID_YES:
2001 case TOOL_CTRL_ID_NO:
2004 case TOOL_CTRL_ID_CONFIRM:
2005 result = TRUE | FALSE;
2008 case TOOL_CTRL_ID_PLAYER_1:
2011 case TOOL_CTRL_ID_PLAYER_2:
2014 case TOOL_CTRL_ID_PLAYER_3:
2017 case TOOL_CTRL_ID_PLAYER_4:
2028 case EVENT_KEYPRESS:
2029 switch(GetEventKey((KeyEvent *)&event, TRUE))
2042 if (req_state & REQ_PLAYER)
2046 case EVENT_KEYRELEASE:
2047 ClearPlayerAction();
2051 HandleOtherEvents(&event);
2055 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
2057 int joy = AnyJoystick();
2059 if (joy & JOY_BUTTON_1)
2061 else if (joy & JOY_BUTTON_2)
2067 /* don't eat all CPU time */
2071 if (game_status != GAME_MODE_MAIN)
2076 if (!(req_state & REQ_STAY_OPEN))
2078 CloseDoor(DOOR_CLOSE_1);
2080 if (!(req_state & REQ_STAY_CLOSED) && (old_door_state & DOOR_OPEN_1))
2082 BlitBitmap(bitmap_db_door, bitmap_db_door,
2083 DOOR_GFX_PAGEX2,DOOR_GFX_PAGEY1, DXSIZE,DYSIZE,
2084 DOOR_GFX_PAGEX1,DOOR_GFX_PAGEY1);
2085 OpenDoor(DOOR_OPEN_1);
2091 SetDrawBackgroundMask(REDRAW_FIELD);
2093 #if defined(PLATFORM_UNIX)
2094 /* continue network game after request */
2095 if (options.network &&
2096 game_status == GAME_MODE_PLAYING &&
2097 req_state & REQUEST_WAIT_FOR)
2098 SendToServer_ContinuePlaying();
2104 unsigned int OpenDoor(unsigned int door_state)
2106 unsigned int new_door_state;
2108 if (door_state & DOOR_COPY_BACK)
2110 BlitBitmap(bitmap_db_door, bitmap_db_door,
2111 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE + VYSIZE,
2112 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2113 door_state &= ~DOOR_COPY_BACK;
2116 new_door_state = MoveDoor(door_state);
2118 return(new_door_state);
2121 unsigned int CloseDoor(unsigned int door_state)
2123 unsigned int new_door_state;
2125 BlitBitmap(backbuffer, bitmap_db_door,
2126 DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2127 BlitBitmap(backbuffer, bitmap_db_door,
2128 VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
2130 new_door_state = MoveDoor(door_state);
2132 return(new_door_state);
2135 unsigned int GetDoorState()
2137 return MoveDoor(DOOR_GET_STATE);
2140 unsigned int SetDoorState(unsigned int door_state)
2142 return MoveDoor(door_state | DOOR_SET_STATE);
2145 unsigned int MoveDoor(unsigned int door_state)
2147 static int door1 = DOOR_OPEN_1;
2148 static int door2 = DOOR_CLOSE_2;
2149 static unsigned long door_delay = 0;
2150 int x, start, stepsize = door.step_offset;
2151 unsigned long door_delay_value = door.step_delay;
2153 if (door_state == DOOR_GET_STATE)
2154 return(door1 | door2);
2156 if (door_state & DOOR_SET_STATE)
2158 if (door_state & DOOR_ACTION_1)
2159 door1 = door_state & DOOR_ACTION_1;
2160 if (door_state & DOOR_ACTION_2)
2161 door2 = door_state & DOOR_ACTION_2;
2163 return(door1 | door2);
2166 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
2167 door_state &= ~DOOR_OPEN_1;
2168 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
2169 door_state &= ~DOOR_CLOSE_1;
2170 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
2171 door_state &= ~DOOR_OPEN_2;
2172 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
2173 door_state &= ~DOOR_CLOSE_2;
2175 if (setup.quick_doors)
2178 door_delay_value = 0;
2180 StopSound(SND_DOOR_OPENING);
2181 StopSound(SND_DOOR_CLOSING);
2184 if (global.autoplay_leveldir)
2186 door_state |= DOOR_NO_DELAY;
2187 door_state &= ~DOOR_CLOSE_ALL;
2190 if (door_state & DOOR_ACTION)
2192 if (!(door_state & DOOR_NO_DELAY))
2194 /* opening door sound has priority over simultaneously closing door */
2195 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
2196 PlaySoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
2197 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
2198 PlaySoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
2201 start = ((door_state & DOOR_NO_DELAY) ? DXSIZE : 0);
2203 for(x=start; x<=DXSIZE; x+=stepsize)
2205 Bitmap *bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
2206 GC gc = bitmap->stored_clip_gc;
2208 if (!(door_state & DOOR_NO_DELAY))
2209 WaitUntilDelayReached(&door_delay, door_delay_value);
2211 if (door_state & DOOR_ACTION_1)
2213 int i = (door_state & DOOR_OPEN_1 ? DXSIZE-x : x);
2214 int j = (DXSIZE - i) / 3;
2216 BlitBitmap(bitmap_db_door, drawto,
2217 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + i/2,
2218 DXSIZE,DYSIZE - i/2, DX, DY);
2220 ClearRectangle(drawto, DX, DY + DYSIZE - i/2, DXSIZE,i/2);
2222 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2223 BlitBitmapMasked(bitmap, drawto,
2224 DXSIZE, DOOR_GFX_PAGEY1, i, 77,
2225 DX + DXSIZE - i, DY + j);
2226 BlitBitmapMasked(bitmap, drawto,
2227 DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63,
2228 DX + DXSIZE - i, DY + 140 + j);
2229 SetClipOrigin(bitmap, gc, DX - DXSIZE + i, DY - (DOOR_GFX_PAGEY1 + j));
2230 BlitBitmapMasked(bitmap, drawto,
2231 DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j,
2233 BlitBitmapMasked(bitmap, drawto,
2234 DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63,
2237 BlitBitmapMasked(bitmap, drawto,
2238 DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
2240 BlitBitmapMasked(bitmap, drawto,
2241 DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
2243 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2244 BlitBitmapMasked(bitmap, drawto,
2245 DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
2246 DX + DXSIZE - i, DY + 77 + j);
2247 BlitBitmapMasked(bitmap, drawto,
2248 DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
2249 DX + DXSIZE - i, DY + 203 + j);
2251 redraw_mask |= REDRAW_DOOR_1;
2254 if (door_state & DOOR_ACTION_2)
2256 int i = (door_state & DOOR_OPEN_2 ? VXSIZE - x : x);
2257 int j = (VXSIZE - i) / 3;
2259 BlitBitmap(bitmap_db_door, drawto,
2260 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + i/2,
2261 VXSIZE, VYSIZE - i/2, VX, VY);
2263 ClearRectangle(drawto, VX, VY + VYSIZE-i/2, VXSIZE, i/2);
2265 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2266 BlitBitmapMasked(bitmap, drawto,
2267 VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2,
2268 VX + VXSIZE-i, VY+j);
2269 SetClipOrigin(bitmap, gc,
2270 VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
2271 BlitBitmapMasked(bitmap, drawto,
2272 VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j,
2275 BlitBitmapMasked(bitmap, drawto,
2276 VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2,
2277 i, VYSIZE / 2, VX, VY + VYSIZE / 2 - j);
2278 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2279 BlitBitmapMasked(bitmap, drawto,
2280 VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2,
2282 VX + VXSIZE - i, VY + VYSIZE / 2 + j);
2284 redraw_mask |= REDRAW_DOOR_2;
2289 if (game_status == GAME_MODE_MAIN)
2294 if (setup.quick_doors)
2296 StopSound(SND_DOOR_OPENING);
2297 StopSound(SND_DOOR_CLOSING);
2300 if (door_state & DOOR_ACTION_1)
2301 door1 = door_state & DOOR_ACTION_1;
2302 if (door_state & DOOR_ACTION_2)
2303 door2 = door_state & DOOR_ACTION_2;
2305 return (door1 | door2);
2308 void DrawSpecialEditorDoor()
2310 /* draw bigger toolbox window */
2311 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
2312 DOOR_GFX_PAGEX7, 0, EXSIZE + 8, 8,
2314 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
2315 EX - 4, VY - 4, EXSIZE + 8, EYSIZE - VYSIZE + 4,
2318 redraw_mask |= REDRAW_ALL;
2321 void UndrawSpecialEditorDoor()
2323 /* draw normal tape recorder window */
2324 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
2325 EX - 4, EY - 12, EXSIZE + 8, EYSIZE - VYSIZE + 12,
2328 redraw_mask |= REDRAW_ALL;
2332 /* ---------- new tool button stuff ---------------------------------------- */
2334 /* graphic position values for tool buttons */
2335 #define TOOL_BUTTON_YES_XPOS 2
2336 #define TOOL_BUTTON_YES_YPOS 250
2337 #define TOOL_BUTTON_YES_GFX_YPOS 0
2338 #define TOOL_BUTTON_YES_XSIZE 46
2339 #define TOOL_BUTTON_YES_YSIZE 28
2340 #define TOOL_BUTTON_NO_XPOS 52
2341 #define TOOL_BUTTON_NO_YPOS TOOL_BUTTON_YES_YPOS
2342 #define TOOL_BUTTON_NO_GFX_YPOS TOOL_BUTTON_YES_GFX_YPOS
2343 #define TOOL_BUTTON_NO_XSIZE TOOL_BUTTON_YES_XSIZE
2344 #define TOOL_BUTTON_NO_YSIZE TOOL_BUTTON_YES_YSIZE
2345 #define TOOL_BUTTON_CONFIRM_XPOS TOOL_BUTTON_YES_XPOS
2346 #define TOOL_BUTTON_CONFIRM_YPOS TOOL_BUTTON_YES_YPOS
2347 #define TOOL_BUTTON_CONFIRM_GFX_YPOS 30
2348 #define TOOL_BUTTON_CONFIRM_XSIZE 96
2349 #define TOOL_BUTTON_CONFIRM_YSIZE TOOL_BUTTON_YES_YSIZE
2350 #define TOOL_BUTTON_PLAYER_XSIZE 30
2351 #define TOOL_BUTTON_PLAYER_YSIZE 30
2352 #define TOOL_BUTTON_PLAYER_GFX_XPOS 5
2353 #define TOOL_BUTTON_PLAYER_GFX_YPOS 185
2354 #define TOOL_BUTTON_PLAYER_XPOS (5 + TOOL_BUTTON_PLAYER_XSIZE / 2)
2355 #define TOOL_BUTTON_PLAYER_YPOS (215 - TOOL_BUTTON_PLAYER_YSIZE / 2)
2356 #define TOOL_BUTTON_PLAYER1_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2357 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2358 #define TOOL_BUTTON_PLAYER2_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2359 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2360 #define TOOL_BUTTON_PLAYER3_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2361 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2362 #define TOOL_BUTTON_PLAYER4_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2363 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2364 #define TOOL_BUTTON_PLAYER1_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2365 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2366 #define TOOL_BUTTON_PLAYER2_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2367 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2368 #define TOOL_BUTTON_PLAYER3_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2369 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2370 #define TOOL_BUTTON_PLAYER4_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2371 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2380 } toolbutton_info[NUM_TOOL_BUTTONS] =
2383 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_GFX_YPOS,
2384 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_YPOS,
2385 TOOL_BUTTON_YES_XSIZE, TOOL_BUTTON_YES_YSIZE,
2390 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_GFX_YPOS,
2391 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_YPOS,
2392 TOOL_BUTTON_NO_XSIZE, TOOL_BUTTON_NO_YSIZE,
2397 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_GFX_YPOS,
2398 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_YPOS,
2399 TOOL_BUTTON_CONFIRM_XSIZE, TOOL_BUTTON_CONFIRM_YSIZE,
2400 TOOL_CTRL_ID_CONFIRM,
2404 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2405 TOOL_BUTTON_PLAYER1_XPOS, TOOL_BUTTON_PLAYER1_YPOS,
2406 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2407 TOOL_CTRL_ID_PLAYER_1,
2411 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2412 TOOL_BUTTON_PLAYER2_XPOS, TOOL_BUTTON_PLAYER2_YPOS,
2413 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2414 TOOL_CTRL_ID_PLAYER_2,
2418 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2419 TOOL_BUTTON_PLAYER3_XPOS, TOOL_BUTTON_PLAYER3_YPOS,
2420 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2421 TOOL_CTRL_ID_PLAYER_3,
2425 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2426 TOOL_BUTTON_PLAYER4_XPOS, TOOL_BUTTON_PLAYER4_YPOS,
2427 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2428 TOOL_CTRL_ID_PLAYER_4,
2433 void CreateToolButtons()
2437 for (i=0; i<NUM_TOOL_BUTTONS; i++)
2439 Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
2440 Bitmap *deco_bitmap = None;
2441 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
2442 struct GadgetInfo *gi;
2443 unsigned long event_mask;
2444 int gd_xoffset, gd_yoffset;
2445 int gd_x1, gd_x2, gd_y;
2448 event_mask = GD_EVENT_RELEASED;
2450 gd_xoffset = toolbutton_info[i].xpos;
2451 gd_yoffset = toolbutton_info[i].ypos;
2452 gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
2453 gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
2454 gd_y = DOOR_GFX_PAGEY1 + gd_yoffset;
2456 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
2458 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
2460 getMiniGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr),
2461 &deco_bitmap, &deco_x, &deco_y);
2462 deco_xpos = (toolbutton_info[i].width - MINI_TILEX) / 2;
2463 deco_ypos = (toolbutton_info[i].height - MINI_TILEY) / 2;
2466 gi = CreateGadget(GDI_CUSTOM_ID, id,
2467 GDI_INFO_TEXT, toolbutton_info[i].infotext,
2468 GDI_X, DX + toolbutton_info[i].x,
2469 GDI_Y, DY + toolbutton_info[i].y,
2470 GDI_WIDTH, toolbutton_info[i].width,
2471 GDI_HEIGHT, toolbutton_info[i].height,
2472 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
2473 GDI_STATE, GD_BUTTON_UNPRESSED,
2474 GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
2475 GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
2476 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
2477 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
2478 GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
2479 GDI_DECORATION_SHIFTING, 1, 1,
2480 GDI_EVENT_MASK, event_mask,
2481 GDI_CALLBACK_ACTION, HandleToolButtons,
2485 Error(ERR_EXIT, "cannot create gadget");
2487 tool_gadget[id] = gi;
2491 void FreeToolButtons()
2495 for (i=0; i<NUM_TOOL_BUTTONS; i++)
2496 FreeGadget(tool_gadget[i]);
2499 static void UnmapToolButtons()
2503 for (i=0; i<NUM_TOOL_BUTTONS; i++)
2504 UnmapGadget(tool_gadget[i]);
2507 static void HandleToolButtons(struct GadgetInfo *gi)
2509 request_gadget_id = gi->custom_id;
2512 int get_next_element(int element)
2516 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
2517 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
2518 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
2519 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
2520 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
2521 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
2522 case EL_AMOEBA_DROPPING: return EL_AMOEBA_WET;
2524 default: return element;
2528 int el_act_dir2img(int element, int action, int direction)
2530 element = GFX_ELEMENT(element);
2531 direction = MV_DIR_BIT(direction);
2533 return element_info[element].direction_graphic[action][direction];
2536 static int el_act_dir2crm(int element, int action, int direction)
2538 element = GFX_ELEMENT(element);
2539 direction = MV_DIR_BIT(direction);
2541 return element_info[element].direction_crumbled[action][direction];
2544 int el_act2img(int element, int action)
2546 element = GFX_ELEMENT(element);
2548 return element_info[element].graphic[action];
2551 int el_dir2img(int element, int direction)
2553 element = GFX_ELEMENT(element);
2555 return el_act_dir2img(element, ACTION_DEFAULT, direction);
2558 int el2img(int element)
2560 element = GFX_ELEMENT(element);
2562 return element_info[element].graphic[ACTION_DEFAULT];
2565 int el2edimg(int element)
2567 element = GFX_ELEMENT(element);
2569 return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
2572 int el2preimg(int element)
2574 element = GFX_ELEMENT(element);
2576 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];