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 */
1780 SetMouseCursor(CURSOR_DEFAULT);
1783 #if defined(PLATFORM_UNIX)
1784 /* pause network game while waiting for request to answer */
1785 if (options.network &&
1786 game_status == GAME_MODE_PLAYING &&
1787 req_state & REQUEST_WAIT_FOR)
1788 SendToServer_PausePlaying();
1791 old_door_state = GetDoorState();
1793 /* simulate releasing mouse button over last gadget, if still pressed */
1795 HandleGadgets(-1, -1, 0);
1799 CloseDoor(DOOR_CLOSE_1);
1801 /* save old door content */
1802 BlitBitmap(bitmap_db_door, bitmap_db_door,
1803 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
1804 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
1806 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
1808 /* clear door drawing field */
1809 DrawBackground(DX, DY, DXSIZE, DYSIZE);
1811 /* force DOOR font on preview level */
1812 game_status = GAME_MODE_PSEUDO_DOOR;
1814 /* write text for request */
1815 for(ty=0; ty < MAX_REQUEST_LINES; ty++)
1817 char text_line[MAX_REQUEST_LINE_LEN + 1];
1823 for(tl=0,tx=0; tx < MAX_REQUEST_LINE_LEN; tl++,tx++)
1826 if (!tc || tc == ' ')
1837 strncpy(text_line, text, tl);
1840 DrawText(DX + (DXSIZE - tl * getFontWidth(FONT_TEXT_2)) / 2,
1841 DY + 8 + ty * (getFontHeight(FONT_TEXT_2) + 2),
1842 text_line, FONT_TEXT_2);
1844 text += tl + (tc == ' ' ? 1 : 0);
1847 game_status = last_game_status; /* restore current game status */
1849 if (req_state & REQ_ASK)
1851 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
1852 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
1854 else if (req_state & REQ_CONFIRM)
1856 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
1858 else if (req_state & REQ_PLAYER)
1860 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
1861 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
1862 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
1863 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
1866 /* copy request gadgets to door backbuffer */
1867 BlitBitmap(drawto, bitmap_db_door,
1868 DX, DY, DXSIZE, DYSIZE,
1869 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
1871 OpenDoor(DOOR_OPEN_1);
1877 if (!(req_state & REQUEST_WAIT_FOR))
1879 SetDrawBackgroundMask(REDRAW_FIELD);
1884 if (game_status != GAME_MODE_MAIN)
1887 button_status = MB_RELEASED;
1889 request_gadget_id = -1;
1891 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
1894 SetMouseCursor(CURSOR_DEFAULT);
1907 case EVENT_BUTTONPRESS:
1908 case EVENT_BUTTONRELEASE:
1909 case EVENT_MOTIONNOTIFY:
1911 if (event.type == EVENT_MOTIONNOTIFY)
1913 if (!PointerInWindow(window))
1914 continue; /* window and pointer are on different screens */
1919 motion_status = TRUE;
1920 mx = ((MotionEvent *) &event)->x;
1921 my = ((MotionEvent *) &event)->y;
1925 motion_status = FALSE;
1926 mx = ((ButtonEvent *) &event)->x;
1927 my = ((ButtonEvent *) &event)->y;
1928 if (event.type == EVENT_BUTTONPRESS)
1929 button_status = ((ButtonEvent *) &event)->button;
1931 button_status = MB_RELEASED;
1934 /* this sets 'request_gadget_id' */
1935 HandleGadgets(mx, my, button_status);
1937 switch(request_gadget_id)
1939 case TOOL_CTRL_ID_YES:
1942 case TOOL_CTRL_ID_NO:
1945 case TOOL_CTRL_ID_CONFIRM:
1946 result = TRUE | FALSE;
1949 case TOOL_CTRL_ID_PLAYER_1:
1952 case TOOL_CTRL_ID_PLAYER_2:
1955 case TOOL_CTRL_ID_PLAYER_3:
1958 case TOOL_CTRL_ID_PLAYER_4:
1969 case EVENT_KEYPRESS:
1970 switch(GetEventKey((KeyEvent *)&event, TRUE))
1983 if (req_state & REQ_PLAYER)
1987 case EVENT_KEYRELEASE:
1988 ClearPlayerAction();
1992 HandleOtherEvents(&event);
1996 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
1998 int joy = AnyJoystick();
2000 if (joy & JOY_BUTTON_1)
2002 else if (joy & JOY_BUTTON_2)
2008 /* don't eat all CPU time */
2012 if (game_status != GAME_MODE_MAIN)
2017 if (!(req_state & REQ_STAY_OPEN))
2019 CloseDoor(DOOR_CLOSE_1);
2021 if (!(req_state & REQ_STAY_CLOSED) && (old_door_state & DOOR_OPEN_1))
2023 BlitBitmap(bitmap_db_door, bitmap_db_door,
2024 DOOR_GFX_PAGEX2,DOOR_GFX_PAGEY1, DXSIZE,DYSIZE,
2025 DOOR_GFX_PAGEX1,DOOR_GFX_PAGEY1);
2026 OpenDoor(DOOR_OPEN_1);
2032 SetDrawBackgroundMask(REDRAW_FIELD);
2034 #if defined(PLATFORM_UNIX)
2035 /* continue network game after request */
2036 if (options.network &&
2037 game_status == GAME_MODE_PLAYING &&
2038 req_state & REQUEST_WAIT_FOR)
2039 SendToServer_ContinuePlaying();
2045 unsigned int OpenDoor(unsigned int door_state)
2047 unsigned int new_door_state;
2049 if (door_state & DOOR_COPY_BACK)
2051 BlitBitmap(bitmap_db_door, bitmap_db_door,
2052 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE + VYSIZE,
2053 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2054 door_state &= ~DOOR_COPY_BACK;
2057 new_door_state = MoveDoor(door_state);
2059 return(new_door_state);
2062 unsigned int CloseDoor(unsigned int door_state)
2064 unsigned int new_door_state;
2066 BlitBitmap(backbuffer, bitmap_db_door,
2067 DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2068 BlitBitmap(backbuffer, bitmap_db_door,
2069 VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
2071 new_door_state = MoveDoor(door_state);
2073 return(new_door_state);
2076 unsigned int GetDoorState()
2078 return MoveDoor(DOOR_GET_STATE);
2081 unsigned int SetDoorState(unsigned int door_state)
2083 return MoveDoor(door_state | DOOR_SET_STATE);
2086 unsigned int MoveDoor(unsigned int door_state)
2088 static int door1 = DOOR_OPEN_1;
2089 static int door2 = DOOR_CLOSE_2;
2090 static unsigned long door_delay = 0;
2091 int x, start, stepsize = door.step_offset;
2092 unsigned long door_delay_value = door.step_delay;
2094 if (door_state == DOOR_GET_STATE)
2095 return(door1 | door2);
2097 if (door_state & DOOR_SET_STATE)
2099 if (door_state & DOOR_ACTION_1)
2100 door1 = door_state & DOOR_ACTION_1;
2101 if (door_state & DOOR_ACTION_2)
2102 door2 = door_state & DOOR_ACTION_2;
2104 return(door1 | door2);
2107 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
2108 door_state &= ~DOOR_OPEN_1;
2109 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
2110 door_state &= ~DOOR_CLOSE_1;
2111 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
2112 door_state &= ~DOOR_OPEN_2;
2113 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
2114 door_state &= ~DOOR_CLOSE_2;
2116 if (setup.quick_doors)
2119 door_delay_value = 0;
2121 StopSound(SND_DOOR_OPENING);
2122 StopSound(SND_DOOR_CLOSING);
2125 if (global.autoplay_leveldir)
2127 door_state |= DOOR_NO_DELAY;
2128 door_state &= ~DOOR_CLOSE_ALL;
2131 if (door_state & DOOR_ACTION)
2133 if (!(door_state & DOOR_NO_DELAY))
2135 /* opening door sound has priority over simultaneously closing door */
2136 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
2137 PlaySoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
2138 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
2139 PlaySoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
2142 start = ((door_state & DOOR_NO_DELAY) ? DXSIZE : 0);
2144 for(x=start; x<=DXSIZE; x+=stepsize)
2146 Bitmap *bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
2147 GC gc = bitmap->stored_clip_gc;
2149 if (!(door_state & DOOR_NO_DELAY))
2150 WaitUntilDelayReached(&door_delay, door_delay_value);
2152 if (door_state & DOOR_ACTION_1)
2154 int i = (door_state & DOOR_OPEN_1 ? DXSIZE-x : x);
2155 int j = (DXSIZE - i) / 3;
2157 BlitBitmap(bitmap_db_door, drawto,
2158 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + i/2,
2159 DXSIZE,DYSIZE - i/2, DX, DY);
2161 ClearRectangle(drawto, DX, DY + DYSIZE - i/2, DXSIZE,i/2);
2163 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2164 BlitBitmapMasked(bitmap, drawto,
2165 DXSIZE, DOOR_GFX_PAGEY1, i, 77,
2166 DX + DXSIZE - i, DY + j);
2167 BlitBitmapMasked(bitmap, drawto,
2168 DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63,
2169 DX + DXSIZE - i, DY + 140 + j);
2170 SetClipOrigin(bitmap, gc, DX - DXSIZE + i, DY - (DOOR_GFX_PAGEY1 + j));
2171 BlitBitmapMasked(bitmap, drawto,
2172 DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j,
2174 BlitBitmapMasked(bitmap, drawto,
2175 DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63,
2178 BlitBitmapMasked(bitmap, drawto,
2179 DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
2181 BlitBitmapMasked(bitmap, drawto,
2182 DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
2184 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2185 BlitBitmapMasked(bitmap, drawto,
2186 DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
2187 DX + DXSIZE - i, DY + 77 + j);
2188 BlitBitmapMasked(bitmap, drawto,
2189 DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
2190 DX + DXSIZE - i, DY + 203 + j);
2192 redraw_mask |= REDRAW_DOOR_1;
2195 if (door_state & DOOR_ACTION_2)
2197 int i = (door_state & DOOR_OPEN_2 ? VXSIZE - x : x);
2198 int j = (VXSIZE - i) / 3;
2200 BlitBitmap(bitmap_db_door, drawto,
2201 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + i/2,
2202 VXSIZE, VYSIZE - i/2, VX, VY);
2204 ClearRectangle(drawto, VX, VY + VYSIZE-i/2, VXSIZE, i/2);
2206 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2207 BlitBitmapMasked(bitmap, drawto,
2208 VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2,
2209 VX + VXSIZE-i, VY+j);
2210 SetClipOrigin(bitmap, gc,
2211 VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
2212 BlitBitmapMasked(bitmap, drawto,
2213 VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j,
2216 BlitBitmapMasked(bitmap, drawto,
2217 VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2,
2218 i, VYSIZE / 2, VX, VY + VYSIZE / 2 - j);
2219 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2220 BlitBitmapMasked(bitmap, drawto,
2221 VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2,
2223 VX + VXSIZE - i, VY + VYSIZE / 2 + j);
2225 redraw_mask |= REDRAW_DOOR_2;
2230 if (game_status == GAME_MODE_MAIN)
2235 if (setup.quick_doors)
2237 StopSound(SND_DOOR_OPENING);
2238 StopSound(SND_DOOR_CLOSING);
2241 if (door_state & DOOR_ACTION_1)
2242 door1 = door_state & DOOR_ACTION_1;
2243 if (door_state & DOOR_ACTION_2)
2244 door2 = door_state & DOOR_ACTION_2;
2246 return (door1 | door2);
2249 void DrawSpecialEditorDoor()
2251 /* draw bigger toolbox window */
2252 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
2253 DOOR_GFX_PAGEX7, 0, EXSIZE + 8, 8,
2255 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
2256 EX - 4, VY - 4, EXSIZE + 8, EYSIZE - VYSIZE + 4,
2259 redraw_mask |= REDRAW_ALL;
2262 void UndrawSpecialEditorDoor()
2264 /* draw normal tape recorder window */
2265 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
2266 EX - 4, EY - 12, EXSIZE + 8, EYSIZE - VYSIZE + 12,
2269 redraw_mask |= REDRAW_ALL;
2273 /* ---------- new tool button stuff ---------------------------------------- */
2275 /* graphic position values for tool buttons */
2276 #define TOOL_BUTTON_YES_XPOS 2
2277 #define TOOL_BUTTON_YES_YPOS 250
2278 #define TOOL_BUTTON_YES_GFX_YPOS 0
2279 #define TOOL_BUTTON_YES_XSIZE 46
2280 #define TOOL_BUTTON_YES_YSIZE 28
2281 #define TOOL_BUTTON_NO_XPOS 52
2282 #define TOOL_BUTTON_NO_YPOS TOOL_BUTTON_YES_YPOS
2283 #define TOOL_BUTTON_NO_GFX_YPOS TOOL_BUTTON_YES_GFX_YPOS
2284 #define TOOL_BUTTON_NO_XSIZE TOOL_BUTTON_YES_XSIZE
2285 #define TOOL_BUTTON_NO_YSIZE TOOL_BUTTON_YES_YSIZE
2286 #define TOOL_BUTTON_CONFIRM_XPOS TOOL_BUTTON_YES_XPOS
2287 #define TOOL_BUTTON_CONFIRM_YPOS TOOL_BUTTON_YES_YPOS
2288 #define TOOL_BUTTON_CONFIRM_GFX_YPOS 30
2289 #define TOOL_BUTTON_CONFIRM_XSIZE 96
2290 #define TOOL_BUTTON_CONFIRM_YSIZE TOOL_BUTTON_YES_YSIZE
2291 #define TOOL_BUTTON_PLAYER_XSIZE 30
2292 #define TOOL_BUTTON_PLAYER_YSIZE 30
2293 #define TOOL_BUTTON_PLAYER_GFX_XPOS 5
2294 #define TOOL_BUTTON_PLAYER_GFX_YPOS 185
2295 #define TOOL_BUTTON_PLAYER_XPOS (5 + TOOL_BUTTON_PLAYER_XSIZE / 2)
2296 #define TOOL_BUTTON_PLAYER_YPOS (215 - TOOL_BUTTON_PLAYER_YSIZE / 2)
2297 #define TOOL_BUTTON_PLAYER1_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2298 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2299 #define TOOL_BUTTON_PLAYER2_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2300 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2301 #define TOOL_BUTTON_PLAYER3_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2302 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2303 #define TOOL_BUTTON_PLAYER4_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2304 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2305 #define TOOL_BUTTON_PLAYER1_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2306 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2307 #define TOOL_BUTTON_PLAYER2_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2308 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2309 #define TOOL_BUTTON_PLAYER3_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2310 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2311 #define TOOL_BUTTON_PLAYER4_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2312 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2321 } toolbutton_info[NUM_TOOL_BUTTONS] =
2324 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_GFX_YPOS,
2325 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_YPOS,
2326 TOOL_BUTTON_YES_XSIZE, TOOL_BUTTON_YES_YSIZE,
2331 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_GFX_YPOS,
2332 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_YPOS,
2333 TOOL_BUTTON_NO_XSIZE, TOOL_BUTTON_NO_YSIZE,
2338 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_GFX_YPOS,
2339 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_YPOS,
2340 TOOL_BUTTON_CONFIRM_XSIZE, TOOL_BUTTON_CONFIRM_YSIZE,
2341 TOOL_CTRL_ID_CONFIRM,
2345 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2346 TOOL_BUTTON_PLAYER1_XPOS, TOOL_BUTTON_PLAYER1_YPOS,
2347 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2348 TOOL_CTRL_ID_PLAYER_1,
2352 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2353 TOOL_BUTTON_PLAYER2_XPOS, TOOL_BUTTON_PLAYER2_YPOS,
2354 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2355 TOOL_CTRL_ID_PLAYER_2,
2359 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2360 TOOL_BUTTON_PLAYER3_XPOS, TOOL_BUTTON_PLAYER3_YPOS,
2361 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2362 TOOL_CTRL_ID_PLAYER_3,
2366 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2367 TOOL_BUTTON_PLAYER4_XPOS, TOOL_BUTTON_PLAYER4_YPOS,
2368 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2369 TOOL_CTRL_ID_PLAYER_4,
2374 void CreateToolButtons()
2378 for (i=0; i<NUM_TOOL_BUTTONS; i++)
2380 Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
2381 Bitmap *deco_bitmap = None;
2382 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
2383 struct GadgetInfo *gi;
2384 unsigned long event_mask;
2385 int gd_xoffset, gd_yoffset;
2386 int gd_x1, gd_x2, gd_y;
2389 event_mask = GD_EVENT_RELEASED;
2391 gd_xoffset = toolbutton_info[i].xpos;
2392 gd_yoffset = toolbutton_info[i].ypos;
2393 gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
2394 gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
2395 gd_y = DOOR_GFX_PAGEY1 + gd_yoffset;
2397 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
2399 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
2401 getMiniGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr),
2402 &deco_bitmap, &deco_x, &deco_y);
2403 deco_xpos = (toolbutton_info[i].width - MINI_TILEX) / 2;
2404 deco_ypos = (toolbutton_info[i].height - MINI_TILEY) / 2;
2407 gi = CreateGadget(GDI_CUSTOM_ID, id,
2408 GDI_INFO_TEXT, toolbutton_info[i].infotext,
2409 GDI_X, DX + toolbutton_info[i].x,
2410 GDI_Y, DY + toolbutton_info[i].y,
2411 GDI_WIDTH, toolbutton_info[i].width,
2412 GDI_HEIGHT, toolbutton_info[i].height,
2413 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
2414 GDI_STATE, GD_BUTTON_UNPRESSED,
2415 GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
2416 GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
2417 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
2418 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
2419 GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
2420 GDI_DECORATION_SHIFTING, 1, 1,
2421 GDI_EVENT_MASK, event_mask,
2422 GDI_CALLBACK_ACTION, HandleToolButtons,
2426 Error(ERR_EXIT, "cannot create gadget");
2428 tool_gadget[id] = gi;
2432 void FreeToolButtons()
2436 for (i=0; i<NUM_TOOL_BUTTONS; i++)
2437 FreeGadget(tool_gadget[i]);
2440 static void UnmapToolButtons()
2444 for (i=0; i<NUM_TOOL_BUTTONS; i++)
2445 UnmapGadget(tool_gadget[i]);
2448 static void HandleToolButtons(struct GadgetInfo *gi)
2450 request_gadget_id = gi->custom_id;
2453 int get_next_element(int element)
2457 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
2458 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
2459 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
2460 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
2461 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
2462 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
2463 case EL_AMOEBA_DROPPING: return EL_AMOEBA_WET;
2465 default: return element;
2469 int el_act_dir2img(int element, int action, int direction)
2471 element = GFX_ELEMENT(element);
2472 direction = MV_DIR_BIT(direction);
2474 return element_info[element].direction_graphic[action][direction];
2477 static int el_act_dir2crm(int element, int action, int direction)
2479 element = GFX_ELEMENT(element);
2480 direction = MV_DIR_BIT(direction);
2482 return element_info[element].direction_crumbled[action][direction];
2485 int el_act2img(int element, int action)
2487 element = GFX_ELEMENT(element);
2489 return element_info[element].graphic[action];
2492 int el_dir2img(int element, int direction)
2494 element = GFX_ELEMENT(element);
2496 return el_act_dir2img(element, ACTION_DEFAULT, direction);
2499 int el2img(int element)
2501 element = GFX_ELEMENT(element);
2503 return element_info[element].graphic[ACTION_DEFAULT];
2506 int el2edimg(int element)
2508 element = GFX_ELEMENT(element);
2510 return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
2513 int el2preimg(int element)
2515 element = GFX_ELEMENT(element);
2517 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];