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 getMicroGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
1530 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
1531 int mini_startx = src_bitmap->width * 3 / 4;
1532 int mini_starty = src_bitmap->height * 2 / 3;
1533 int src_x = mini_startx + graphic_info[graphic].src_x / 8;
1534 int src_y = mini_starty + graphic_info[graphic].src_y / 8;
1536 *bitmap = src_bitmap;
1541 void DrawMicroElement(int xpos, int ypos, int element)
1545 int graphic = el2preimg(element);
1547 getMicroGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
1548 BlitBitmap(src_bitmap, drawto, src_x, src_y, MICRO_TILEX, MICRO_TILEY,
1556 SetDrawBackgroundMask(REDRAW_NONE);
1559 for(x=BX1; x<=BX2; x++)
1560 for(y=BY1; y<=BY2; y++)
1561 DrawScreenField(x, y);
1563 redraw_mask |= REDRAW_FIELD;
1566 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
1570 for(x=0; x<size_x; x++)
1571 for(y=0; y<size_y; y++)
1572 DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
1574 redraw_mask |= REDRAW_FIELD;
1577 static void DrawMicroLevelExt(int xpos, int ypos, int from_x, int from_y)
1581 DrawBackground(xpos, ypos, MICROLEV_XSIZE, MICROLEV_YSIZE);
1583 if (lev_fieldx < STD_LEV_FIELDX)
1584 xpos += (STD_LEV_FIELDX - lev_fieldx) / 2 * MICRO_TILEX;
1585 if (lev_fieldy < STD_LEV_FIELDY)
1586 ypos += (STD_LEV_FIELDY - lev_fieldy) / 2 * MICRO_TILEY;
1588 xpos += MICRO_TILEX;
1589 ypos += MICRO_TILEY;
1591 for(x=-1; x<=STD_LEV_FIELDX; x++)
1593 for(y=-1; y<=STD_LEV_FIELDY; y++)
1595 int lx = from_x + x, ly = from_y + y;
1597 if (lx >= 0 && lx < lev_fieldx && ly >= 0 && ly < lev_fieldy)
1598 DrawMicroElement(xpos + x * MICRO_TILEX, ypos + y * MICRO_TILEY,
1599 level.field[lx][ly]);
1600 else if (lx >= -1 && lx < lev_fieldx+1 && ly >= -1 && ly < lev_fieldy+1
1601 && BorderElement != EL_EMPTY)
1602 DrawMicroElement(xpos + x * MICRO_TILEX, ypos + y * MICRO_TILEY,
1603 getBorderElement(lx, ly));
1607 redraw_mask |= REDRAW_MICROLEVEL;
1610 #define MICROLABEL_EMPTY 0
1611 #define MICROLABEL_LEVEL_NAME 1
1612 #define MICROLABEL_CREATED_BY 2
1613 #define MICROLABEL_LEVEL_AUTHOR 3
1614 #define MICROLABEL_IMPORTED_FROM 4
1615 #define MICROLABEL_LEVEL_IMPORT_INFO 5
1617 static void DrawMicroLevelLabelExt(int mode)
1619 char label_text[MAX_OUTPUT_LINESIZE + 1];
1620 int max_len_label_text;
1621 int font_nr = FONT_TEXT_2;
1623 if (mode == MICROLABEL_CREATED_BY || mode == MICROLABEL_IMPORTED_FROM)
1624 font_nr = FONT_TEXT_3;
1626 max_len_label_text = SXSIZE / getFontWidth(font_nr);
1628 DrawBackground(SX, MICROLABEL_YPOS, SXSIZE, getFontHeight(font_nr));
1630 strncpy(label_text, (mode == MICROLABEL_LEVEL_NAME ? level.name :
1631 mode == MICROLABEL_CREATED_BY ? "created by" :
1632 mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
1633 mode == MICROLABEL_IMPORTED_FROM ? "imported from" :
1634 mode == MICROLABEL_LEVEL_IMPORT_INFO ?
1635 leveldir_current->imported_from : ""),
1636 max_len_label_text);
1637 label_text[max_len_label_text] = '\0';
1639 if (strlen(label_text) > 0)
1641 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
1642 int lypos = MICROLABEL_YPOS;
1644 DrawText(lxpos, lypos, label_text, font_nr);
1647 redraw_mask |= REDRAW_MICROLEVEL;
1650 void DrawMicroLevel(int xpos, int ypos, boolean restart)
1652 static unsigned long scroll_delay = 0;
1653 static unsigned long label_delay = 0;
1654 static int from_x, from_y, scroll_direction;
1655 static int label_state, label_counter;
1656 int last_game_status = game_status; /* save current game status */
1658 /* force PREVIEW font on preview level */
1659 game_status = GAME_MODE_PSEUDO_PREVIEW;
1663 from_x = from_y = 0;
1664 scroll_direction = MV_RIGHT;
1668 DrawMicroLevelExt(xpos, ypos, from_x, from_y);
1669 DrawMicroLevelLabelExt(label_state);
1671 /* initialize delay counters */
1672 DelayReached(&scroll_delay, 0);
1673 DelayReached(&label_delay, 0);
1675 if (leveldir_current->name)
1677 int text_width = getTextWidth(leveldir_current->name, FONT_TEXT_1);
1678 int lxpos = SX + (SXSIZE - text_width) / 2;
1679 int lypos = SY + 352;
1681 DrawText(lxpos, lypos, leveldir_current->name, FONT_TEXT_1);
1684 game_status = last_game_status; /* restore current game status */
1689 /* scroll micro level, if needed */
1690 if ((lev_fieldx > STD_LEV_FIELDX || lev_fieldy > STD_LEV_FIELDY) &&
1691 DelayReached(&scroll_delay, MICROLEVEL_SCROLL_DELAY))
1693 switch (scroll_direction)
1699 scroll_direction = MV_UP;
1703 if (from_x < lev_fieldx - STD_LEV_FIELDX)
1706 scroll_direction = MV_DOWN;
1713 scroll_direction = MV_RIGHT;
1717 if (from_y < lev_fieldy - STD_LEV_FIELDY)
1720 scroll_direction = MV_LEFT;
1727 DrawMicroLevelExt(xpos, ypos, from_x, from_y);
1730 /* redraw micro level label, if needed */
1731 if (strcmp(level.name, NAMELESS_LEVEL_NAME) != 0 &&
1732 strcmp(level.author, ANONYMOUS_NAME) != 0 &&
1733 strcmp(level.author, leveldir_current->name) != 0 &&
1734 DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
1736 int max_label_counter = 23;
1738 if (leveldir_current->imported_from != NULL)
1739 max_label_counter += 14;
1741 label_counter = (label_counter + 1) % max_label_counter;
1742 label_state = (label_counter >= 0 && label_counter <= 7 ?
1743 MICROLABEL_LEVEL_NAME :
1744 label_counter >= 9 && label_counter <= 12 ?
1745 MICROLABEL_CREATED_BY :
1746 label_counter >= 14 && label_counter <= 21 ?
1747 MICROLABEL_LEVEL_AUTHOR :
1748 label_counter >= 23 && label_counter <= 26 ?
1749 MICROLABEL_IMPORTED_FROM :
1750 label_counter >= 28 && label_counter <= 35 ?
1751 MICROLABEL_LEVEL_IMPORT_INFO : MICROLABEL_EMPTY);
1752 DrawMicroLevelLabelExt(label_state);
1755 game_status = last_game_status; /* restore current game status */
1758 int REQ_in_range(int x, int y)
1760 if (y > DY+249 && y < DY+278)
1762 if (x > DX+1 && x < DX+48)
1764 else if (x > DX+51 && x < DX+98)
1770 #define MAX_REQUEST_LINES 13
1771 #define MAX_REQUEST_LINE_LEN 7
1773 boolean Request(char *text, unsigned int req_state)
1775 int mx, my, ty, result = -1;
1776 unsigned int old_door_state;
1777 int last_game_status = game_status; /* save current game status */
1779 #if defined(PLATFORM_UNIX)
1780 /* pause network game while waiting for request to answer */
1781 if (options.network &&
1782 game_status == GAME_MODE_PLAYING &&
1783 req_state & REQUEST_WAIT_FOR)
1784 SendToServer_PausePlaying();
1787 old_door_state = GetDoorState();
1789 /* simulate releasing mouse button over last gadget, if still pressed */
1791 HandleGadgets(-1, -1, 0);
1795 CloseDoor(DOOR_CLOSE_1);
1797 /* save old door content */
1798 BlitBitmap(bitmap_db_door, bitmap_db_door,
1799 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
1800 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
1802 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
1804 /* clear door drawing field */
1805 DrawBackground(DX, DY, DXSIZE, DYSIZE);
1807 /* force DOOR font on preview level */
1808 game_status = GAME_MODE_PSEUDO_DOOR;
1810 /* write text for request */
1811 for(ty=0; ty < MAX_REQUEST_LINES; ty++)
1813 char text_line[MAX_REQUEST_LINE_LEN + 1];
1819 for(tl=0,tx=0; tx < MAX_REQUEST_LINE_LEN; tl++,tx++)
1822 if (!tc || tc == ' ')
1833 strncpy(text_line, text, tl);
1836 DrawText(DX + (DXSIZE - tl * getFontWidth(FONT_TEXT_2)) / 2,
1837 DY + 8 + ty * (getFontHeight(FONT_TEXT_2) + 2),
1838 text_line, FONT_TEXT_2);
1840 text += tl + (tc == ' ' ? 1 : 0);
1843 game_status = last_game_status; /* restore current game status */
1845 if (req_state & REQ_ASK)
1847 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
1848 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
1850 else if (req_state & REQ_CONFIRM)
1852 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
1854 else if (req_state & REQ_PLAYER)
1856 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
1857 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
1858 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
1859 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
1862 /* copy request gadgets to door backbuffer */
1863 BlitBitmap(drawto, bitmap_db_door,
1864 DX, DY, DXSIZE, DYSIZE,
1865 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
1867 OpenDoor(DOOR_OPEN_1);
1873 if (!(req_state & REQUEST_WAIT_FOR))
1875 SetDrawBackgroundMask(REDRAW_FIELD);
1880 if (game_status != GAME_MODE_MAIN)
1883 button_status = MB_RELEASED;
1885 request_gadget_id = -1;
1887 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
1889 SetMouseCursor(CURSOR_DEFAULT);
1901 case EVENT_BUTTONPRESS:
1902 case EVENT_BUTTONRELEASE:
1903 case EVENT_MOTIONNOTIFY:
1905 if (event.type == EVENT_MOTIONNOTIFY)
1907 if (!PointerInWindow(window))
1908 continue; /* window and pointer are on different screens */
1913 motion_status = TRUE;
1914 mx = ((MotionEvent *) &event)->x;
1915 my = ((MotionEvent *) &event)->y;
1919 motion_status = FALSE;
1920 mx = ((ButtonEvent *) &event)->x;
1921 my = ((ButtonEvent *) &event)->y;
1922 if (event.type == EVENT_BUTTONPRESS)
1923 button_status = ((ButtonEvent *) &event)->button;
1925 button_status = MB_RELEASED;
1928 /* this sets 'request_gadget_id' */
1929 HandleGadgets(mx, my, button_status);
1931 switch(request_gadget_id)
1933 case TOOL_CTRL_ID_YES:
1936 case TOOL_CTRL_ID_NO:
1939 case TOOL_CTRL_ID_CONFIRM:
1940 result = TRUE | FALSE;
1943 case TOOL_CTRL_ID_PLAYER_1:
1946 case TOOL_CTRL_ID_PLAYER_2:
1949 case TOOL_CTRL_ID_PLAYER_3:
1952 case TOOL_CTRL_ID_PLAYER_4:
1963 case EVENT_KEYPRESS:
1964 switch(GetEventKey((KeyEvent *)&event, TRUE))
1977 if (req_state & REQ_PLAYER)
1981 case EVENT_KEYRELEASE:
1982 ClearPlayerAction();
1986 HandleOtherEvents(&event);
1990 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
1992 int joy = AnyJoystick();
1994 if (joy & JOY_BUTTON_1)
1996 else if (joy & JOY_BUTTON_2)
2002 /* don't eat all CPU time */
2006 if (game_status != GAME_MODE_MAIN)
2011 if (!(req_state & REQ_STAY_OPEN))
2013 CloseDoor(DOOR_CLOSE_1);
2015 if (!(req_state & REQ_STAY_CLOSED) && (old_door_state & DOOR_OPEN_1))
2017 BlitBitmap(bitmap_db_door, bitmap_db_door,
2018 DOOR_GFX_PAGEX2,DOOR_GFX_PAGEY1, DXSIZE,DYSIZE,
2019 DOOR_GFX_PAGEX1,DOOR_GFX_PAGEY1);
2020 OpenDoor(DOOR_OPEN_1);
2026 SetDrawBackgroundMask(REDRAW_FIELD);
2028 #if defined(PLATFORM_UNIX)
2029 /* continue network game after request */
2030 if (options.network &&
2031 game_status == GAME_MODE_PLAYING &&
2032 req_state & REQUEST_WAIT_FOR)
2033 SendToServer_ContinuePlaying();
2039 unsigned int OpenDoor(unsigned int door_state)
2041 unsigned int new_door_state;
2043 if (door_state & DOOR_COPY_BACK)
2045 BlitBitmap(bitmap_db_door, bitmap_db_door,
2046 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE + VYSIZE,
2047 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2048 door_state &= ~DOOR_COPY_BACK;
2051 new_door_state = MoveDoor(door_state);
2053 return(new_door_state);
2056 unsigned int CloseDoor(unsigned int door_state)
2058 unsigned int new_door_state;
2060 BlitBitmap(backbuffer, bitmap_db_door,
2061 DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2062 BlitBitmap(backbuffer, bitmap_db_door,
2063 VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
2065 new_door_state = MoveDoor(door_state);
2067 return(new_door_state);
2070 unsigned int GetDoorState()
2072 return MoveDoor(DOOR_GET_STATE);
2075 unsigned int SetDoorState(unsigned int door_state)
2077 return MoveDoor(door_state | DOOR_SET_STATE);
2080 unsigned int MoveDoor(unsigned int door_state)
2082 static int door1 = DOOR_OPEN_1;
2083 static int door2 = DOOR_CLOSE_2;
2084 static unsigned long door_delay = 0;
2085 int x, start, stepsize = door.step_offset;
2086 unsigned long door_delay_value = door.step_delay;
2088 if (door_state == DOOR_GET_STATE)
2089 return(door1 | door2);
2091 if (door_state & DOOR_SET_STATE)
2093 if (door_state & DOOR_ACTION_1)
2094 door1 = door_state & DOOR_ACTION_1;
2095 if (door_state & DOOR_ACTION_2)
2096 door2 = door_state & DOOR_ACTION_2;
2098 return(door1 | door2);
2101 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
2102 door_state &= ~DOOR_OPEN_1;
2103 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
2104 door_state &= ~DOOR_CLOSE_1;
2105 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
2106 door_state &= ~DOOR_OPEN_2;
2107 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
2108 door_state &= ~DOOR_CLOSE_2;
2110 if (setup.quick_doors)
2113 door_delay_value = 0;
2115 StopSound(SND_DOOR_OPENING);
2116 StopSound(SND_DOOR_CLOSING);
2119 if (global.autoplay_leveldir)
2121 door_state |= DOOR_NO_DELAY;
2122 door_state &= ~DOOR_CLOSE_ALL;
2125 if (door_state & DOOR_ACTION)
2127 if (!(door_state & DOOR_NO_DELAY))
2129 /* opening door sound has priority over simultaneously closing door */
2130 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
2131 PlaySoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
2132 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
2133 PlaySoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
2136 start = ((door_state & DOOR_NO_DELAY) ? DXSIZE : 0);
2138 for(x=start; x<=DXSIZE; x+=stepsize)
2140 Bitmap *bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
2141 GC gc = bitmap->stored_clip_gc;
2143 if (!(door_state & DOOR_NO_DELAY))
2144 WaitUntilDelayReached(&door_delay, door_delay_value);
2146 if (door_state & DOOR_ACTION_1)
2148 int i = (door_state & DOOR_OPEN_1 ? DXSIZE-x : x);
2149 int j = (DXSIZE - i) / 3;
2151 BlitBitmap(bitmap_db_door, drawto,
2152 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + i/2,
2153 DXSIZE,DYSIZE - i/2, DX, DY);
2155 ClearRectangle(drawto, DX, DY + DYSIZE - i/2, DXSIZE,i/2);
2157 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2158 BlitBitmapMasked(bitmap, drawto,
2159 DXSIZE, DOOR_GFX_PAGEY1, i, 77,
2160 DX + DXSIZE - i, DY + j);
2161 BlitBitmapMasked(bitmap, drawto,
2162 DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63,
2163 DX + DXSIZE - i, DY + 140 + j);
2164 SetClipOrigin(bitmap, gc, DX - DXSIZE + i, DY - (DOOR_GFX_PAGEY1 + j));
2165 BlitBitmapMasked(bitmap, drawto,
2166 DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j,
2168 BlitBitmapMasked(bitmap, drawto,
2169 DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63,
2172 BlitBitmapMasked(bitmap, drawto,
2173 DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
2175 BlitBitmapMasked(bitmap, drawto,
2176 DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
2178 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2179 BlitBitmapMasked(bitmap, drawto,
2180 DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
2181 DX + DXSIZE - i, DY + 77 + j);
2182 BlitBitmapMasked(bitmap, drawto,
2183 DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
2184 DX + DXSIZE - i, DY + 203 + j);
2186 redraw_mask |= REDRAW_DOOR_1;
2189 if (door_state & DOOR_ACTION_2)
2191 int i = (door_state & DOOR_OPEN_2 ? VXSIZE - x : x);
2192 int j = (VXSIZE - i) / 3;
2194 BlitBitmap(bitmap_db_door, drawto,
2195 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + i/2,
2196 VXSIZE, VYSIZE - i/2, VX, VY);
2198 ClearRectangle(drawto, VX, VY + VYSIZE-i/2, VXSIZE, i/2);
2200 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2201 BlitBitmapMasked(bitmap, drawto,
2202 VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2,
2203 VX + VXSIZE-i, VY+j);
2204 SetClipOrigin(bitmap, gc,
2205 VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
2206 BlitBitmapMasked(bitmap, drawto,
2207 VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j,
2210 BlitBitmapMasked(bitmap, drawto,
2211 VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2,
2212 i, VYSIZE / 2, VX, VY + VYSIZE / 2 - j);
2213 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2214 BlitBitmapMasked(bitmap, drawto,
2215 VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2,
2217 VX + VXSIZE - i, VY + VYSIZE / 2 + j);
2219 redraw_mask |= REDRAW_DOOR_2;
2224 if (game_status == GAME_MODE_MAIN)
2229 if (setup.quick_doors)
2231 StopSound(SND_DOOR_OPENING);
2232 StopSound(SND_DOOR_CLOSING);
2235 if (door_state & DOOR_ACTION_1)
2236 door1 = door_state & DOOR_ACTION_1;
2237 if (door_state & DOOR_ACTION_2)
2238 door2 = door_state & DOOR_ACTION_2;
2240 return (door1 | door2);
2243 void DrawSpecialEditorDoor()
2245 /* draw bigger toolbox window */
2246 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
2247 DOOR_GFX_PAGEX7, 0, EXSIZE + 8, 8,
2249 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
2250 EX - 4, VY - 4, EXSIZE + 8, EYSIZE - VYSIZE + 4,
2253 redraw_mask |= REDRAW_ALL;
2256 void UndrawSpecialEditorDoor()
2258 /* draw normal tape recorder window */
2259 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
2260 EX - 4, EY - 12, EXSIZE + 8, EYSIZE - VYSIZE + 12,
2263 redraw_mask |= REDRAW_ALL;
2267 /* ---------- new tool button stuff ---------------------------------------- */
2269 /* graphic position values for tool buttons */
2270 #define TOOL_BUTTON_YES_XPOS 2
2271 #define TOOL_BUTTON_YES_YPOS 250
2272 #define TOOL_BUTTON_YES_GFX_YPOS 0
2273 #define TOOL_BUTTON_YES_XSIZE 46
2274 #define TOOL_BUTTON_YES_YSIZE 28
2275 #define TOOL_BUTTON_NO_XPOS 52
2276 #define TOOL_BUTTON_NO_YPOS TOOL_BUTTON_YES_YPOS
2277 #define TOOL_BUTTON_NO_GFX_YPOS TOOL_BUTTON_YES_GFX_YPOS
2278 #define TOOL_BUTTON_NO_XSIZE TOOL_BUTTON_YES_XSIZE
2279 #define TOOL_BUTTON_NO_YSIZE TOOL_BUTTON_YES_YSIZE
2280 #define TOOL_BUTTON_CONFIRM_XPOS TOOL_BUTTON_YES_XPOS
2281 #define TOOL_BUTTON_CONFIRM_YPOS TOOL_BUTTON_YES_YPOS
2282 #define TOOL_BUTTON_CONFIRM_GFX_YPOS 30
2283 #define TOOL_BUTTON_CONFIRM_XSIZE 96
2284 #define TOOL_BUTTON_CONFIRM_YSIZE TOOL_BUTTON_YES_YSIZE
2285 #define TOOL_BUTTON_PLAYER_XSIZE 30
2286 #define TOOL_BUTTON_PLAYER_YSIZE 30
2287 #define TOOL_BUTTON_PLAYER_GFX_XPOS 5
2288 #define TOOL_BUTTON_PLAYER_GFX_YPOS 185
2289 #define TOOL_BUTTON_PLAYER_XPOS (5 + TOOL_BUTTON_PLAYER_XSIZE / 2)
2290 #define TOOL_BUTTON_PLAYER_YPOS (215 - TOOL_BUTTON_PLAYER_YSIZE / 2)
2291 #define TOOL_BUTTON_PLAYER1_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2292 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2293 #define TOOL_BUTTON_PLAYER2_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2294 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2295 #define TOOL_BUTTON_PLAYER3_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2296 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2297 #define TOOL_BUTTON_PLAYER4_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2298 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2299 #define TOOL_BUTTON_PLAYER1_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2300 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2301 #define TOOL_BUTTON_PLAYER2_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2302 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2303 #define TOOL_BUTTON_PLAYER3_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2304 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2305 #define TOOL_BUTTON_PLAYER4_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2306 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2315 } toolbutton_info[NUM_TOOL_BUTTONS] =
2318 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_GFX_YPOS,
2319 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_YPOS,
2320 TOOL_BUTTON_YES_XSIZE, TOOL_BUTTON_YES_YSIZE,
2325 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_GFX_YPOS,
2326 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_YPOS,
2327 TOOL_BUTTON_NO_XSIZE, TOOL_BUTTON_NO_YSIZE,
2332 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_GFX_YPOS,
2333 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_YPOS,
2334 TOOL_BUTTON_CONFIRM_XSIZE, TOOL_BUTTON_CONFIRM_YSIZE,
2335 TOOL_CTRL_ID_CONFIRM,
2339 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2340 TOOL_BUTTON_PLAYER1_XPOS, TOOL_BUTTON_PLAYER1_YPOS,
2341 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2342 TOOL_CTRL_ID_PLAYER_1,
2346 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2347 TOOL_BUTTON_PLAYER2_XPOS, TOOL_BUTTON_PLAYER2_YPOS,
2348 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2349 TOOL_CTRL_ID_PLAYER_2,
2353 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2354 TOOL_BUTTON_PLAYER3_XPOS, TOOL_BUTTON_PLAYER3_YPOS,
2355 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2356 TOOL_CTRL_ID_PLAYER_3,
2360 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2361 TOOL_BUTTON_PLAYER4_XPOS, TOOL_BUTTON_PLAYER4_YPOS,
2362 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2363 TOOL_CTRL_ID_PLAYER_4,
2368 void CreateToolButtons()
2372 for (i=0; i<NUM_TOOL_BUTTONS; i++)
2374 Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
2375 Bitmap *deco_bitmap = None;
2376 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
2377 struct GadgetInfo *gi;
2378 unsigned long event_mask;
2379 int gd_xoffset, gd_yoffset;
2380 int gd_x1, gd_x2, gd_y;
2383 event_mask = GD_EVENT_RELEASED;
2385 gd_xoffset = toolbutton_info[i].xpos;
2386 gd_yoffset = toolbutton_info[i].ypos;
2387 gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
2388 gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
2389 gd_y = DOOR_GFX_PAGEY1 + gd_yoffset;
2391 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
2393 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
2395 getMiniGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr),
2396 &deco_bitmap, &deco_x, &deco_y);
2397 deco_xpos = (toolbutton_info[i].width - MINI_TILEX) / 2;
2398 deco_ypos = (toolbutton_info[i].height - MINI_TILEY) / 2;
2401 gi = CreateGadget(GDI_CUSTOM_ID, id,
2402 GDI_INFO_TEXT, toolbutton_info[i].infotext,
2403 GDI_X, DX + toolbutton_info[i].x,
2404 GDI_Y, DY + toolbutton_info[i].y,
2405 GDI_WIDTH, toolbutton_info[i].width,
2406 GDI_HEIGHT, toolbutton_info[i].height,
2407 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
2408 GDI_STATE, GD_BUTTON_UNPRESSED,
2409 GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
2410 GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
2411 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
2412 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
2413 GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
2414 GDI_DECORATION_SHIFTING, 1, 1,
2415 GDI_EVENT_MASK, event_mask,
2416 GDI_CALLBACK_ACTION, HandleToolButtons,
2420 Error(ERR_EXIT, "cannot create gadget");
2422 tool_gadget[id] = gi;
2426 void FreeToolButtons()
2430 for (i=0; i<NUM_TOOL_BUTTONS; i++)
2431 FreeGadget(tool_gadget[i]);
2434 static void UnmapToolButtons()
2438 for (i=0; i<NUM_TOOL_BUTTONS; i++)
2439 UnmapGadget(tool_gadget[i]);
2442 static void HandleToolButtons(struct GadgetInfo *gi)
2444 request_gadget_id = gi->custom_id;
2447 int get_next_element(int element)
2451 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
2452 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
2453 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
2454 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
2455 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
2456 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
2457 case EL_AMOEBA_DROPPING: return EL_AMOEBA_WET;
2459 default: return element;
2463 int el_act_dir2img(int element, int action, int direction)
2465 element = GFX_ELEMENT(element);
2466 direction = MV_DIR_BIT(direction);
2468 return element_info[element].direction_graphic[action][direction];
2471 static int el_act_dir2crm(int element, int action, int direction)
2473 element = GFX_ELEMENT(element);
2474 direction = MV_DIR_BIT(direction);
2476 return element_info[element].direction_crumbled[action][direction];
2479 int el_act2img(int element, int action)
2481 element = GFX_ELEMENT(element);
2483 return element_info[element].graphic[action];
2486 int el_dir2img(int element, int direction)
2488 element = GFX_ELEMENT(element);
2490 return el_act_dir2img(element, ACTION_DEFAULT, direction);
2493 int el2img(int element)
2495 element = GFX_ELEMENT(element);
2497 return element_info[element].graphic[ACTION_DEFAULT];
2500 int el2edimg(int element)
2502 element = GFX_ELEMENT(element);
2504 return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
2507 int el2preimg(int element)
2509 element = GFX_ELEMENT(element);
2511 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];