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 int REQ_in_range(int x, int y)
1785 if (y > DY+249 && y < DY+278)
1787 if (x > DX+1 && x < DX+48)
1789 else if (x > DX+51 && x < DX+98)
1795 #define MAX_REQUEST_LINES 13
1796 #define MAX_REQUEST_LINE_LEN 7
1798 boolean Request(char *text, unsigned int req_state)
1800 int mx, my, ty, result = -1;
1801 unsigned int old_door_state;
1802 int last_game_status = game_status; /* save current game status */
1804 #if defined(PLATFORM_UNIX)
1805 /* pause network game while waiting for request to answer */
1806 if (options.network &&
1807 game_status == GAME_MODE_PLAYING &&
1808 req_state & REQUEST_WAIT_FOR)
1809 SendToServer_PausePlaying();
1812 old_door_state = GetDoorState();
1814 /* simulate releasing mouse button over last gadget, if still pressed */
1816 HandleGadgets(-1, -1, 0);
1820 CloseDoor(DOOR_CLOSE_1);
1822 /* save old door content */
1823 BlitBitmap(bitmap_db_door, bitmap_db_door,
1824 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
1825 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
1827 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
1829 /* clear door drawing field */
1830 DrawBackground(DX, DY, DXSIZE, DYSIZE);
1832 /* force DOOR font on preview level */
1833 game_status = GAME_MODE_PSEUDO_DOOR;
1835 /* write text for request */
1836 for(ty=0; ty < MAX_REQUEST_LINES; ty++)
1838 char text_line[MAX_REQUEST_LINE_LEN + 1];
1844 for(tl=0,tx=0; tx < MAX_REQUEST_LINE_LEN; tl++,tx++)
1847 if (!tc || tc == ' ')
1858 strncpy(text_line, text, tl);
1861 DrawText(DX + (DXSIZE - tl * getFontWidth(FONT_TEXT_2)) / 2,
1862 DY + 8 + ty * (getFontHeight(FONT_TEXT_2) + 2),
1863 text_line, FONT_TEXT_2);
1865 text += tl + (tc == ' ' ? 1 : 0);
1868 game_status = last_game_status; /* restore current game status */
1870 if (req_state & REQ_ASK)
1872 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
1873 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
1875 else if (req_state & REQ_CONFIRM)
1877 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
1879 else if (req_state & REQ_PLAYER)
1881 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
1882 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
1883 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
1884 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
1887 /* copy request gadgets to door backbuffer */
1888 BlitBitmap(drawto, bitmap_db_door,
1889 DX, DY, DXSIZE, DYSIZE,
1890 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
1892 OpenDoor(DOOR_OPEN_1);
1898 if (!(req_state & REQUEST_WAIT_FOR))
1900 SetDrawBackgroundMask(REDRAW_FIELD);
1905 if (game_status != GAME_MODE_MAIN)
1908 button_status = MB_RELEASED;
1910 request_gadget_id = -1;
1912 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
1914 SetMouseCursor(CURSOR_DEFAULT);
1926 case EVENT_BUTTONPRESS:
1927 case EVENT_BUTTONRELEASE:
1928 case EVENT_MOTIONNOTIFY:
1930 if (event.type == EVENT_MOTIONNOTIFY)
1932 if (!PointerInWindow(window))
1933 continue; /* window and pointer are on different screens */
1938 motion_status = TRUE;
1939 mx = ((MotionEvent *) &event)->x;
1940 my = ((MotionEvent *) &event)->y;
1944 motion_status = FALSE;
1945 mx = ((ButtonEvent *) &event)->x;
1946 my = ((ButtonEvent *) &event)->y;
1947 if (event.type == EVENT_BUTTONPRESS)
1948 button_status = ((ButtonEvent *) &event)->button;
1950 button_status = MB_RELEASED;
1953 /* this sets 'request_gadget_id' */
1954 HandleGadgets(mx, my, button_status);
1956 switch(request_gadget_id)
1958 case TOOL_CTRL_ID_YES:
1961 case TOOL_CTRL_ID_NO:
1964 case TOOL_CTRL_ID_CONFIRM:
1965 result = TRUE | FALSE;
1968 case TOOL_CTRL_ID_PLAYER_1:
1971 case TOOL_CTRL_ID_PLAYER_2:
1974 case TOOL_CTRL_ID_PLAYER_3:
1977 case TOOL_CTRL_ID_PLAYER_4:
1988 case EVENT_KEYPRESS:
1989 switch(GetEventKey((KeyEvent *)&event, TRUE))
2002 if (req_state & REQ_PLAYER)
2006 case EVENT_KEYRELEASE:
2007 ClearPlayerAction();
2011 HandleOtherEvents(&event);
2015 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
2017 int joy = AnyJoystick();
2019 if (joy & JOY_BUTTON_1)
2021 else if (joy & JOY_BUTTON_2)
2027 /* don't eat all CPU time */
2031 if (game_status != GAME_MODE_MAIN)
2036 if (!(req_state & REQ_STAY_OPEN))
2038 CloseDoor(DOOR_CLOSE_1);
2040 if (!(req_state & REQ_STAY_CLOSED) && (old_door_state & DOOR_OPEN_1))
2042 BlitBitmap(bitmap_db_door, bitmap_db_door,
2043 DOOR_GFX_PAGEX2,DOOR_GFX_PAGEY1, DXSIZE,DYSIZE,
2044 DOOR_GFX_PAGEX1,DOOR_GFX_PAGEY1);
2045 OpenDoor(DOOR_OPEN_1);
2051 SetDrawBackgroundMask(REDRAW_FIELD);
2053 #if defined(PLATFORM_UNIX)
2054 /* continue network game after request */
2055 if (options.network &&
2056 game_status == GAME_MODE_PLAYING &&
2057 req_state & REQUEST_WAIT_FOR)
2058 SendToServer_ContinuePlaying();
2064 unsigned int OpenDoor(unsigned int door_state)
2066 unsigned int new_door_state;
2068 if (door_state & DOOR_COPY_BACK)
2070 BlitBitmap(bitmap_db_door, bitmap_db_door,
2071 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE + VYSIZE,
2072 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2073 door_state &= ~DOOR_COPY_BACK;
2076 new_door_state = MoveDoor(door_state);
2078 return(new_door_state);
2081 unsigned int CloseDoor(unsigned int door_state)
2083 unsigned int new_door_state;
2085 BlitBitmap(backbuffer, bitmap_db_door,
2086 DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2087 BlitBitmap(backbuffer, bitmap_db_door,
2088 VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
2090 new_door_state = MoveDoor(door_state);
2092 return(new_door_state);
2095 unsigned int GetDoorState()
2097 return MoveDoor(DOOR_GET_STATE);
2100 unsigned int SetDoorState(unsigned int door_state)
2102 return MoveDoor(door_state | DOOR_SET_STATE);
2105 unsigned int MoveDoor(unsigned int door_state)
2107 static int door1 = DOOR_OPEN_1;
2108 static int door2 = DOOR_CLOSE_2;
2109 static unsigned long door_delay = 0;
2110 int x, start, stepsize = door.step_offset;
2111 unsigned long door_delay_value = door.step_delay;
2113 if (door_state == DOOR_GET_STATE)
2114 return(door1 | door2);
2116 if (door_state & DOOR_SET_STATE)
2118 if (door_state & DOOR_ACTION_1)
2119 door1 = door_state & DOOR_ACTION_1;
2120 if (door_state & DOOR_ACTION_2)
2121 door2 = door_state & DOOR_ACTION_2;
2123 return(door1 | door2);
2126 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
2127 door_state &= ~DOOR_OPEN_1;
2128 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
2129 door_state &= ~DOOR_CLOSE_1;
2130 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
2131 door_state &= ~DOOR_OPEN_2;
2132 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
2133 door_state &= ~DOOR_CLOSE_2;
2135 if (setup.quick_doors)
2138 door_delay_value = 0;
2140 StopSound(SND_DOOR_OPENING);
2141 StopSound(SND_DOOR_CLOSING);
2144 if (global.autoplay_leveldir)
2146 door_state |= DOOR_NO_DELAY;
2147 door_state &= ~DOOR_CLOSE_ALL;
2150 if (door_state & DOOR_ACTION)
2152 if (!(door_state & DOOR_NO_DELAY))
2154 /* opening door sound has priority over simultaneously closing door */
2155 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
2156 PlaySoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
2157 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
2158 PlaySoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
2161 start = ((door_state & DOOR_NO_DELAY) ? DXSIZE : 0);
2163 for(x=start; x<=DXSIZE; x+=stepsize)
2165 Bitmap *bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
2166 GC gc = bitmap->stored_clip_gc;
2168 if (!(door_state & DOOR_NO_DELAY))
2169 WaitUntilDelayReached(&door_delay, door_delay_value);
2171 if (door_state & DOOR_ACTION_1)
2173 int i = (door_state & DOOR_OPEN_1 ? DXSIZE-x : x);
2174 int j = (DXSIZE - i) / 3;
2176 BlitBitmap(bitmap_db_door, drawto,
2177 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + i/2,
2178 DXSIZE,DYSIZE - i/2, DX, DY);
2180 ClearRectangle(drawto, DX, DY + DYSIZE - i/2, DXSIZE,i/2);
2182 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2183 BlitBitmapMasked(bitmap, drawto,
2184 DXSIZE, DOOR_GFX_PAGEY1, i, 77,
2185 DX + DXSIZE - i, DY + j);
2186 BlitBitmapMasked(bitmap, drawto,
2187 DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63,
2188 DX + DXSIZE - i, DY + 140 + j);
2189 SetClipOrigin(bitmap, gc, DX - DXSIZE + i, DY - (DOOR_GFX_PAGEY1 + j));
2190 BlitBitmapMasked(bitmap, drawto,
2191 DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j,
2193 BlitBitmapMasked(bitmap, drawto,
2194 DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63,
2197 BlitBitmapMasked(bitmap, drawto,
2198 DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
2200 BlitBitmapMasked(bitmap, drawto,
2201 DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
2203 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2204 BlitBitmapMasked(bitmap, drawto,
2205 DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
2206 DX + DXSIZE - i, DY + 77 + j);
2207 BlitBitmapMasked(bitmap, drawto,
2208 DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
2209 DX + DXSIZE - i, DY + 203 + j);
2211 redraw_mask |= REDRAW_DOOR_1;
2214 if (door_state & DOOR_ACTION_2)
2216 int i = (door_state & DOOR_OPEN_2 ? VXSIZE - x : x);
2217 int j = (VXSIZE - i) / 3;
2219 BlitBitmap(bitmap_db_door, drawto,
2220 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + i/2,
2221 VXSIZE, VYSIZE - i/2, VX, VY);
2223 ClearRectangle(drawto, VX, VY + VYSIZE-i/2, VXSIZE, i/2);
2225 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2226 BlitBitmapMasked(bitmap, drawto,
2227 VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2,
2228 VX + VXSIZE-i, VY+j);
2229 SetClipOrigin(bitmap, gc,
2230 VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
2231 BlitBitmapMasked(bitmap, drawto,
2232 VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j,
2235 BlitBitmapMasked(bitmap, drawto,
2236 VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2,
2237 i, VYSIZE / 2, VX, VY + VYSIZE / 2 - j);
2238 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2239 BlitBitmapMasked(bitmap, drawto,
2240 VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2,
2242 VX + VXSIZE - i, VY + VYSIZE / 2 + j);
2244 redraw_mask |= REDRAW_DOOR_2;
2249 if (game_status == GAME_MODE_MAIN)
2254 if (setup.quick_doors)
2256 StopSound(SND_DOOR_OPENING);
2257 StopSound(SND_DOOR_CLOSING);
2260 if (door_state & DOOR_ACTION_1)
2261 door1 = door_state & DOOR_ACTION_1;
2262 if (door_state & DOOR_ACTION_2)
2263 door2 = door_state & DOOR_ACTION_2;
2265 return (door1 | door2);
2268 void DrawSpecialEditorDoor()
2270 /* draw bigger toolbox window */
2271 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
2272 DOOR_GFX_PAGEX7, 0, EXSIZE + 8, 8,
2274 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
2275 EX - 4, VY - 4, EXSIZE + 8, EYSIZE - VYSIZE + 4,
2278 redraw_mask |= REDRAW_ALL;
2281 void UndrawSpecialEditorDoor()
2283 /* draw normal tape recorder window */
2284 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
2285 EX - 4, EY - 12, EXSIZE + 8, EYSIZE - VYSIZE + 12,
2288 redraw_mask |= REDRAW_ALL;
2292 /* ---------- new tool button stuff ---------------------------------------- */
2294 /* graphic position values for tool buttons */
2295 #define TOOL_BUTTON_YES_XPOS 2
2296 #define TOOL_BUTTON_YES_YPOS 250
2297 #define TOOL_BUTTON_YES_GFX_YPOS 0
2298 #define TOOL_BUTTON_YES_XSIZE 46
2299 #define TOOL_BUTTON_YES_YSIZE 28
2300 #define TOOL_BUTTON_NO_XPOS 52
2301 #define TOOL_BUTTON_NO_YPOS TOOL_BUTTON_YES_YPOS
2302 #define TOOL_BUTTON_NO_GFX_YPOS TOOL_BUTTON_YES_GFX_YPOS
2303 #define TOOL_BUTTON_NO_XSIZE TOOL_BUTTON_YES_XSIZE
2304 #define TOOL_BUTTON_NO_YSIZE TOOL_BUTTON_YES_YSIZE
2305 #define TOOL_BUTTON_CONFIRM_XPOS TOOL_BUTTON_YES_XPOS
2306 #define TOOL_BUTTON_CONFIRM_YPOS TOOL_BUTTON_YES_YPOS
2307 #define TOOL_BUTTON_CONFIRM_GFX_YPOS 30
2308 #define TOOL_BUTTON_CONFIRM_XSIZE 96
2309 #define TOOL_BUTTON_CONFIRM_YSIZE TOOL_BUTTON_YES_YSIZE
2310 #define TOOL_BUTTON_PLAYER_XSIZE 30
2311 #define TOOL_BUTTON_PLAYER_YSIZE 30
2312 #define TOOL_BUTTON_PLAYER_GFX_XPOS 5
2313 #define TOOL_BUTTON_PLAYER_GFX_YPOS 185
2314 #define TOOL_BUTTON_PLAYER_XPOS (5 + TOOL_BUTTON_PLAYER_XSIZE / 2)
2315 #define TOOL_BUTTON_PLAYER_YPOS (215 - TOOL_BUTTON_PLAYER_YSIZE / 2)
2316 #define TOOL_BUTTON_PLAYER1_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2317 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2318 #define TOOL_BUTTON_PLAYER2_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2319 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2320 #define TOOL_BUTTON_PLAYER3_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2321 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2322 #define TOOL_BUTTON_PLAYER4_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2323 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2324 #define TOOL_BUTTON_PLAYER1_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2325 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2326 #define TOOL_BUTTON_PLAYER2_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2327 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2328 #define TOOL_BUTTON_PLAYER3_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2329 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2330 #define TOOL_BUTTON_PLAYER4_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2331 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2340 } toolbutton_info[NUM_TOOL_BUTTONS] =
2343 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_GFX_YPOS,
2344 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_YPOS,
2345 TOOL_BUTTON_YES_XSIZE, TOOL_BUTTON_YES_YSIZE,
2350 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_GFX_YPOS,
2351 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_YPOS,
2352 TOOL_BUTTON_NO_XSIZE, TOOL_BUTTON_NO_YSIZE,
2357 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_GFX_YPOS,
2358 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_YPOS,
2359 TOOL_BUTTON_CONFIRM_XSIZE, TOOL_BUTTON_CONFIRM_YSIZE,
2360 TOOL_CTRL_ID_CONFIRM,
2364 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2365 TOOL_BUTTON_PLAYER1_XPOS, TOOL_BUTTON_PLAYER1_YPOS,
2366 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2367 TOOL_CTRL_ID_PLAYER_1,
2371 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2372 TOOL_BUTTON_PLAYER2_XPOS, TOOL_BUTTON_PLAYER2_YPOS,
2373 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2374 TOOL_CTRL_ID_PLAYER_2,
2378 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2379 TOOL_BUTTON_PLAYER3_XPOS, TOOL_BUTTON_PLAYER3_YPOS,
2380 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2381 TOOL_CTRL_ID_PLAYER_3,
2385 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2386 TOOL_BUTTON_PLAYER4_XPOS, TOOL_BUTTON_PLAYER4_YPOS,
2387 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2388 TOOL_CTRL_ID_PLAYER_4,
2393 void CreateToolButtons()
2397 for (i=0; i<NUM_TOOL_BUTTONS; i++)
2399 Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
2400 Bitmap *deco_bitmap = None;
2401 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
2402 struct GadgetInfo *gi;
2403 unsigned long event_mask;
2404 int gd_xoffset, gd_yoffset;
2405 int gd_x1, gd_x2, gd_y;
2408 event_mask = GD_EVENT_RELEASED;
2410 gd_xoffset = toolbutton_info[i].xpos;
2411 gd_yoffset = toolbutton_info[i].ypos;
2412 gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
2413 gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
2414 gd_y = DOOR_GFX_PAGEY1 + gd_yoffset;
2416 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
2418 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
2420 getMiniGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr),
2421 &deco_bitmap, &deco_x, &deco_y);
2422 deco_xpos = (toolbutton_info[i].width - MINI_TILEX) / 2;
2423 deco_ypos = (toolbutton_info[i].height - MINI_TILEY) / 2;
2426 gi = CreateGadget(GDI_CUSTOM_ID, id,
2427 GDI_INFO_TEXT, toolbutton_info[i].infotext,
2428 GDI_X, DX + toolbutton_info[i].x,
2429 GDI_Y, DY + toolbutton_info[i].y,
2430 GDI_WIDTH, toolbutton_info[i].width,
2431 GDI_HEIGHT, toolbutton_info[i].height,
2432 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
2433 GDI_STATE, GD_BUTTON_UNPRESSED,
2434 GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
2435 GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
2436 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
2437 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
2438 GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
2439 GDI_DECORATION_SHIFTING, 1, 1,
2440 GDI_EVENT_MASK, event_mask,
2441 GDI_CALLBACK_ACTION, HandleToolButtons,
2445 Error(ERR_EXIT, "cannot create gadget");
2447 tool_gadget[id] = gi;
2451 void FreeToolButtons()
2455 for (i=0; i<NUM_TOOL_BUTTONS; i++)
2456 FreeGadget(tool_gadget[i]);
2459 static void UnmapToolButtons()
2463 for (i=0; i<NUM_TOOL_BUTTONS; i++)
2464 UnmapGadget(tool_gadget[i]);
2467 static void HandleToolButtons(struct GadgetInfo *gi)
2469 request_gadget_id = gi->custom_id;
2472 int get_next_element(int element)
2476 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
2477 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
2478 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
2479 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
2480 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
2481 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
2482 case EL_AMOEBA_DROPPING: return EL_AMOEBA_WET;
2484 default: return element;
2488 int el_act_dir2img(int element, int action, int direction)
2490 element = GFX_ELEMENT(element);
2491 direction = MV_DIR_BIT(direction);
2493 return element_info[element].direction_graphic[action][direction];
2496 static int el_act_dir2crm(int element, int action, int direction)
2498 element = GFX_ELEMENT(element);
2499 direction = MV_DIR_BIT(direction);
2501 return element_info[element].direction_crumbled[action][direction];
2504 int el_act2img(int element, int action)
2506 element = GFX_ELEMENT(element);
2508 return element_info[element].graphic[action];
2511 int el_dir2img(int element, int direction)
2513 element = GFX_ELEMENT(element);
2515 return el_act_dir2img(element, ACTION_DEFAULT, direction);
2518 int el2img(int element)
2520 element = GFX_ELEMENT(element);
2522 return element_info[element].graphic[ACTION_DEFAULT];
2525 int el2edimg(int element)
2527 element = GFX_ELEMENT(element);
2529 return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
2532 int el2preimg(int element)
2534 element = GFX_ELEMENT(element);
2536 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];