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