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);
602 InitPlayerGfxAnimation(player, action, move_dir);
604 /* ----------------------------------------------------------------------- */
605 /* draw things in the field the player is leaving, if needed */
606 /* ----------------------------------------------------------------------- */
609 if (player->is_moving)
611 if (player_is_moving)
614 if (Back[last_jx][last_jy] && IS_DRAWABLE(last_element))
616 DrawLevelElement(last_jx, last_jy, Back[last_jx][last_jy]);
618 if (last_element == EL_DYNAMITE_ACTIVE ||
619 last_element == EL_SP_DISK_RED_ACTIVE)
620 DrawDynamite(last_jx, last_jy);
622 DrawLevelFieldThruMask(last_jx, last_jy);
624 else if (last_element == EL_DYNAMITE_ACTIVE ||
625 last_element == EL_SP_DISK_RED_ACTIVE)
626 DrawDynamite(last_jx, last_jy);
628 DrawLevelField(last_jx, last_jy);
630 if (player->Pushing && IN_SCR_FIELD(SCREENX(next_jx), SCREENY(next_jy)))
634 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
638 if (Feld[next_jx][next_jy] == EL_SOKOBAN_FIELD_FULL)
639 DrawLevelElement(next_jx, next_jy, EL_SOKOBAN_FIELD_EMPTY);
641 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
644 DrawLevelField(next_jx, next_jy);
650 if (!IN_SCR_FIELD(sx, sy))
653 if (setup.direct_draw)
654 SetDrawtoField(DRAW_BUFFERED);
656 /* ----------------------------------------------------------------------- */
657 /* draw things behind the player, if needed */
658 /* ----------------------------------------------------------------------- */
661 DrawLevelElement(jx, jy, Back[jx][jy]);
662 else if (IS_ACTIVE_BOMB(element))
663 DrawLevelElement(jx, jy, EL_EMPTY);
666 if (player_is_moving && GfxElement[jx][jy] != EL_UNDEFINED)
669 /* !!! insert DrawLevelFieldCrumbledSandDigging code here !!! */
670 if (player->is_digging && CAN_BE_CRUMBLED(GfxElement[jx][jy]))
671 DrawLevelFieldCrumbledSandDigging(jx, jy, move_dir, player->StepFrame);
673 if (GfxElement[jx][jy] == EL_SAND)
674 DrawLevelFieldCrumbledSandDigging(jx, jy, move_dir, player->StepFrame);
676 else /* player->is_collecting */
678 int old_element = GfxElement[jx][jy];
679 int old_graphic = el_act_dir2img(old_element, action, move_dir);
680 int frame = getGraphicAnimationFrame(old_graphic, player->StepFrame);
682 DrawGraphic(sx, sy, old_graphic, frame);
687 GfxElement[jx][jy] = EL_UNDEFINED;
689 DrawLevelField(jx, jy);
693 /* ----------------------------------------------------------------------- */
694 /* draw player himself */
695 /* ----------------------------------------------------------------------- */
697 if (player->use_murphy_graphic)
699 static int last_horizontal_dir = MV_LEFT;
702 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
703 last_horizontal_dir = move_dir;
705 direction = (player->snapped ? move_dir : last_horizontal_dir);
707 graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, direction);
710 graphic = el_act_dir2img(player->element_nr, player->GfxAction, move_dir);
712 frame = getGraphicAnimationFrame(graphic, player->Frame);
716 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
717 sxx = player->GfxPos;
719 syy = player->GfxPos;
722 if (!setup.soft_scrolling && ScreenMovPos)
725 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
727 if (SHIELD_ON(player))
729 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
730 IMG_SHIELD_NORMAL_ACTIVE);
731 int frame = getGraphicAnimationFrame(graphic, -1);
733 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
736 /* ----------------------------------------------------------------------- */
737 /* draw things the player is pushing, if needed */
738 /* ----------------------------------------------------------------------- */
741 printf("::: %d, %d [%d, %d] [%d]\n",
742 player->Pushing, player_is_moving, player->GfxAction,
743 player->is_moving, player_is_moving);
747 if (player->Pushing && player->is_moving)
749 if (player->Pushing && player_is_moving)
752 int px = SCREENX(next_jx), py = SCREENY(next_jy);
754 if (Back[next_jx][next_jy])
755 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
758 if ((sxx || syy) && element == EL_SOKOBAN_OBJECT)
759 DrawGraphicShiftedThruMask(px, py, sxx, syy, IMG_SOKOBAN_OBJECT, 0,
763 (element == EL_SOKOBAN_FIELD_EMPTY ||
764 Feld[next_jx][next_jy] == EL_SOKOBAN_FIELD_FULL))
765 DrawGraphicShiftedThruMask(px, py, sxx, syy, IMG_SOKOBAN_OBJECT, 0,
771 int element = MovingOrBlocked2Element(next_jx, next_jy);
774 int element = Feld[jx][jy];
776 int element = Feld[next_jx][next_jy];
781 int graphic = el2img(element);
785 if ((sxx || syy) && IS_PUSHABLE(element))
788 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
789 frame = getGraphicAnimationFrame(graphic, player->Frame);
793 printf("::: pushing %d: %d ...\n", sxx, frame);
796 DrawGraphicShifted(px, py, sxx, syy, graphic, frame,
797 NO_CUTTING, NO_MASKING);
802 /* ----------------------------------------------------------------------- */
803 /* draw things in front of player (active dynamite or dynabombs) */
804 /* ----------------------------------------------------------------------- */
806 if (IS_ACTIVE_BOMB(element))
808 graphic = el2img(element);
809 frame = getGraphicAnimationFrame(graphic, GfxFrame[jx][jy]);
811 if (game.emulation == EMU_SUPAPLEX)
812 DrawGraphic(sx, sy, IMG_SP_DISK_RED, frame);
814 DrawGraphicThruMask(sx, sy, graphic, frame);
817 if (player_is_moving && last_element == EL_EXPLOSION)
820 int graphic = el_act2img(GfxElement[last_jx][last_jy], ACTION_EXPLODING);
822 int stored = Store[last_jx][last_jy];
823 int graphic = (game.emulation != EMU_SUPAPLEX ? IMG_EXPLOSION :
824 stored == EL_SP_INFOTRON ? IMG_SP_EXPLOSION_INFOTRON :
827 int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
828 int phase = ExplodePhase[last_jx][last_jy] - 1;
829 int frame = getGraphicAnimationFrame(graphic, phase - delay);
832 DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy), graphic, frame);
835 /* ----------------------------------------------------------------------- */
836 /* draw elements the player is just walking/passing through/under */
837 /* ----------------------------------------------------------------------- */
839 /* handle the field the player is leaving ... */
840 if (player_is_moving && IS_ACCESSIBLE_INSIDE(last_element))
841 DrawLevelField(last_jx, last_jy);
842 else if (player_is_moving && IS_ACCESSIBLE_UNDER(last_element))
843 DrawLevelFieldThruMask(last_jx, last_jy);
845 /* ... and the field the player is entering */
846 if (IS_ACCESSIBLE_INSIDE(element))
847 DrawLevelField(jx, jy);
848 else if (IS_ACCESSIBLE_UNDER(element))
849 DrawLevelFieldThruMask(jx, jy);
851 if (setup.direct_draw)
853 int dest_x = SX + SCREENX(MIN(jx, last_jx)) * TILEX;
854 int dest_y = SY + SCREENY(MIN(jy, last_jy)) * TILEY;
855 int x_size = TILEX * (1 + ABS(jx - last_jx));
856 int y_size = TILEY * (1 + ABS(jy - last_jy));
858 BlitBitmap(drawto_field, window,
859 dest_x, dest_y, x_size, y_size, dest_x, dest_y);
860 SetDrawtoField(DRAW_DIRECT);
863 MarkTileDirty(sx,sy);
866 void getGraphicSource(int graphic, int frame, Bitmap **bitmap, int *x, int *y)
868 struct GraphicInfo *g = &graphic_info[graphic];
872 if (g->offset_y == 0) /* frames are ordered horizontally */
874 int max_width = g->anim_frames_per_line * g->width;
876 *x = (g->src_x + frame * g->offset_x) % max_width;
877 *y = g->src_y + (g->src_x + frame * g->offset_x) / max_width * g->height;
879 else if (g->offset_x == 0) /* frames are ordered vertically */
881 int max_height = g->anim_frames_per_line * g->height;
883 *x = g->src_x + (g->src_y + frame * g->offset_y) / max_height * g->width;
884 *y = (g->src_y + frame * g->offset_y) % max_height;
886 else /* frames are ordered diagonally */
888 *x = g->src_x + frame * g->offset_x;
889 *y = g->src_y + frame * g->offset_y;
893 void DrawGraphic(int x, int y, int graphic, int frame)
896 if (!IN_SCR_FIELD(x, y))
898 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
899 printf("DrawGraphic(): This should never happen!\n");
904 DrawGraphicExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic, frame);
908 void DrawGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
914 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
915 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
918 void DrawGraphicThruMask(int x, int y, int graphic, int frame)
921 if (!IN_SCR_FIELD(x, y))
923 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
924 printf("DrawGraphicThruMask(): This should never happen!\n");
929 DrawGraphicThruMaskExt(drawto_field, FX + x * TILEX, FY + y *TILEY, graphic,
934 void DrawGraphicThruMaskExt(DrawBuffer *d, int dest_x, int dest_y, int graphic,
942 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
943 drawing_gc = src_bitmap->stored_clip_gc;
945 GC drawing_gc = src_bitmap->stored_clip_gc;
946 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
947 int src_x = graphic_info[graphic].src_x;
948 int src_y = graphic_info[graphic].src_y;
949 int offset_x = graphic_info[graphic].offset_x;
950 int offset_y = graphic_info[graphic].offset_y;
952 src_x += frame * offset_x;
953 src_y += frame * offset_y;
957 SetClipOrigin(src_bitmap, drawing_gc, dest_x - src_x, dest_y - src_y);
958 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX, TILEY, dest_x, dest_y);
961 void DrawMiniGraphic(int x, int y, int graphic)
963 DrawMiniGraphicExt(drawto, SX + x * MINI_TILEX,SY + y * MINI_TILEY, graphic);
964 MarkTileDirty(x / 2, y / 2);
967 void getMiniGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
969 struct GraphicInfo *g = &graphic_info[graphic];
971 int mini_starty = g->bitmap->height * 2 / 3;
974 *x = mini_startx + g->src_x / 2;
975 *y = mini_starty + g->src_y / 2;
978 void DrawMiniGraphicExt(DrawBuffer *d, int x, int y, int graphic)
983 getMiniGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
984 BlitBitmap(src_bitmap, d, src_x, src_y, MINI_TILEX, MINI_TILEY, x, y);
987 void DrawGraphicShifted(int x,int y, int dx,int dy, int graphic, int frame,
988 int cut_mode, int mask_mode)
993 int width = TILEX, height = TILEY;
999 DrawGraphic(x, y, graphic, frame);
1003 if (dx || dy) /* shifted graphic */
1005 if (x < BX1) /* object enters playfield from the left */
1012 else if (x > BX2) /* object enters playfield from the right */
1018 else if (x==BX1 && dx < 0) /* object leaves playfield to the left */
1024 else if (x==BX2 && dx > 0) /* object leaves playfield to the right */
1026 else if (dx) /* general horizontal movement */
1027 MarkTileDirty(x + SIGN(dx), y);
1029 if (y < BY1) /* object enters playfield from the top */
1031 if (cut_mode==CUT_BELOW) /* object completely above top border */
1039 else if (y > BY2) /* object enters playfield from the bottom */
1045 else if (y==BY1 && dy < 0) /* object leaves playfield to the top */
1051 else if (dy > 0 && cut_mode == CUT_ABOVE)
1053 if (y == BY2) /* object completely above bottom border */
1059 MarkTileDirty(x, y + 1);
1060 } /* object leaves playfield to the bottom */
1061 else if (dy > 0 && (y == BY2 || cut_mode == CUT_BELOW))
1063 else if (dy) /* general vertical movement */
1064 MarkTileDirty(x, y + SIGN(dy));
1068 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1070 src_bitmap = graphic_info[graphic].bitmap;
1071 src_x = graphic_info[graphic].src_x;
1072 src_y = graphic_info[graphic].src_y;
1073 offset_x = graphic_info[graphic].offset_x;
1074 offset_y = graphic_info[graphic].offset_y;
1076 src_x += frame * offset_x;
1077 src_y += frame * offset_y;
1080 drawing_gc = src_bitmap->stored_clip_gc;
1085 dest_x = FX + x * TILEX + dx;
1086 dest_y = FY + y * TILEY + dy;
1089 if (!IN_SCR_FIELD(x,y))
1091 printf("DrawGraphicShifted(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
1092 printf("DrawGraphicShifted(): This should never happen!\n");
1097 if (mask_mode == USE_MASKING)
1099 SetClipOrigin(src_bitmap, drawing_gc, dest_x - src_x, dest_y - src_y);
1100 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1104 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1110 void DrawGraphicShiftedThruMask(int x, int y, int dx, int dy, int graphic,
1111 int frame, int cut_mode)
1113 DrawGraphicShifted(x,y, dx,dy, graphic, frame, cut_mode, USE_MASKING);
1116 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
1117 int cut_mode, int mask_mode)
1119 int lx = LEVELX(x), ly = LEVELY(y);
1123 if (IN_LEV_FIELD(lx, ly))
1125 SetRandomAnimationValue(lx, ly);
1127 graphic = el_act_dir2img(element, GfxAction[lx][ly], MovDir[lx][ly]);
1128 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1130 else /* border element */
1132 graphic = el2img(element);
1133 frame = getGraphicAnimationFrame(graphic, -1);
1136 if (element == EL_EXPANDABLE_WALL)
1138 boolean left_stopped = FALSE, right_stopped = FALSE;
1140 if (!IN_LEV_FIELD(lx - 1, ly) || IS_WALL(Feld[lx - 1][ly]))
1141 left_stopped = TRUE;
1142 if (!IN_LEV_FIELD(lx + 1, ly) || IS_WALL(Feld[lx + 1][ly]))
1143 right_stopped = TRUE;
1145 if (left_stopped && right_stopped)
1147 else if (left_stopped)
1149 graphic = IMG_EXPANDABLE_WALL_GROWING_RIGHT;
1150 frame = graphic_info[graphic].anim_frames - 1;
1152 else if (right_stopped)
1154 graphic = IMG_EXPANDABLE_WALL_GROWING_LEFT;
1155 frame = graphic_info[graphic].anim_frames - 1;
1160 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, mask_mode);
1161 else if (mask_mode == USE_MASKING)
1162 DrawGraphicThruMask(x, y, graphic, frame);
1164 DrawGraphic(x, y, graphic, frame);
1167 void DrawLevelElementExt(int x, int y, int dx, int dy, int element,
1168 int cut_mode, int mask_mode)
1170 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1171 DrawScreenElementExt(SCREENX(x), SCREENY(y), dx, dy, element,
1172 cut_mode, mask_mode);
1175 void DrawScreenElementShifted(int x, int y, int dx, int dy, int element,
1178 DrawScreenElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1181 void DrawLevelElementShifted(int x, int y, int dx, int dy, int element,
1184 DrawLevelElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1187 void DrawLevelElementThruMask(int x, int y, int element)
1189 DrawLevelElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1192 void DrawLevelFieldThruMask(int x, int y)
1194 DrawLevelElementExt(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
1197 static void DrawLevelFieldCrumbledSandExt(int x, int y, int graphic, int frame)
1201 int sx = SCREENX(x), sy = SCREENY(y);
1203 int width, height, cx, cy, i;
1204 int snip = TILEX / 8; /* number of border pixels from "crumbled graphic" */
1205 static int xy[4][2] =
1213 if (!IN_LEV_FIELD(x, y))
1216 element = (GfxElement[x][y] != EL_UNDEFINED && Feld[x][y] != EL_EXPLOSION ?
1217 GfxElement[x][y] : Feld[x][y]);
1219 /* crumble field itself */
1220 if (CAN_BE_CRUMBLED(element) && !IS_MOVING(x, y))
1222 if (!IN_SCR_FIELD(sx, sy))
1225 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1229 int xx = x + xy[i][0];
1230 int yy = y + xy[i][1];
1232 element = (IN_LEV_FIELD(xx, yy) ? Feld[xx][yy] : BorderElement);
1234 /* check if neighbour field is of same type */
1235 if (CAN_BE_CRUMBLED(element) && !IS_MOVING(xx, yy))
1239 if (Feld[x][y] == EL_CUSTOM_START + 123)
1240 printf("::: crumble [%d] THE CHAOS ENGINE (%d, %d): %d, %d\n",
1241 i, Feld[x][y], element,
1242 CAN_BE_CRUMBLED(element), IS_MOVING(x, y));
1245 if (i == 1 || i == 2)
1249 cx = (i == 2 ? TILEX - snip : 0);
1257 cy = (i == 3 ? TILEY - snip : 0);
1260 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1261 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
1264 MarkTileDirty(sx, sy);
1266 else /* crumble neighbour fields */
1268 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1272 int xx = x + xy[i][0];
1273 int yy = y + xy[i][1];
1274 int sxx = sx + xy[i][0];
1275 int syy = sy + xy[i][1];
1277 if (!IN_LEV_FIELD(xx, yy) ||
1278 !IN_SCR_FIELD(sxx, syy) ||
1279 !CAN_BE_CRUMBLED(Feld[xx][yy]) ||
1283 if (i == 1 || i == 2)
1287 cx = (i == 1 ? TILEX - snip : 0);
1295 cy = (i==0 ? TILEY-snip : 0);
1298 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1299 width, height, FX + sxx * TILEX + cx, FY + syy * TILEY + cy);
1301 MarkTileDirty(sxx, syy);
1306 void DrawLevelFieldCrumbledSand(int x, int y)
1308 DrawLevelFieldCrumbledSandExt(x, y, IMG_SAND_CRUMBLED, 0);
1311 void DrawLevelFieldCrumbledSandDigging(int x, int y, int direction,
1315 int graphic1 = el_act_dir2img(GfxElement[x][y], ACTION_DIGGING, direction);
1316 int graphic2 = el_act_dir2crm(GfxElement[x][y], ACTION_DIGGING, direction);
1318 int graphic1 = el_act_dir2img(EL_SAND, ACTION_DIGGING, direction);
1319 int graphic2 = el_act_dir2img(EL_SAND_CRUMBLED, ACTION_DIGGING, direction);
1321 int frame1 = getGraphicAnimationFrame(graphic1, step_frame);
1322 int frame2 = getGraphicAnimationFrame(graphic2, step_frame);
1323 int sx = SCREENX(x), sy = SCREENY(y);
1325 DrawGraphic(sx, sy, graphic1, frame1);
1327 if (graphic1 != IMG_EMPTY_SPACE)
1328 DrawLevelFieldCrumbledSandExt(x, y, graphic2, frame2);
1331 void DrawLevelFieldCrumbledSandNeighbours(int x, int y)
1333 int sx = SCREENX(x), sy = SCREENY(y);
1334 static int xy[4][2] =
1345 int xx = x + xy[i][0];
1346 int yy = y + xy[i][1];
1347 int sxx = sx + xy[i][0];
1348 int syy = sy + xy[i][1];
1350 if (!IN_LEV_FIELD(xx, yy) ||
1351 !IN_SCR_FIELD(sxx, syy) ||
1352 !CAN_BE_CRUMBLED(Feld[xx][yy]) ||
1356 DrawLevelField(xx, yy);
1360 static int getBorderElement(int x, int y)
1364 { EL_STEELWALL_TOPLEFT, EL_INVISIBLE_STEELWALL_TOPLEFT },
1365 { EL_STEELWALL_TOPRIGHT, EL_INVISIBLE_STEELWALL_TOPRIGHT },
1366 { EL_STEELWALL_BOTTOMLEFT, EL_INVISIBLE_STEELWALL_BOTTOMLEFT },
1367 { EL_STEELWALL_BOTTOMRIGHT, EL_INVISIBLE_STEELWALL_BOTTOMRIGHT },
1368 { EL_STEELWALL_VERTICAL, EL_INVISIBLE_STEELWALL_VERTICAL },
1369 { EL_STEELWALL_HORIZONTAL, EL_INVISIBLE_STEELWALL_HORIZONTAL },
1370 { EL_STEELWALL, EL_INVISIBLE_STEELWALL }
1372 int steel_type = (BorderElement == EL_STEELWALL ? 0 : 1);
1373 int steel_position = (x == -1 && y == -1 ? 0 :
1374 x == lev_fieldx && y == -1 ? 1 :
1375 x == -1 && y == lev_fieldy ? 2 :
1376 x == lev_fieldx && y == lev_fieldy ? 3 :
1377 x == -1 || x == lev_fieldx ? 4 :
1378 y == -1 || y == lev_fieldy ? 5 : 6);
1380 return border[steel_position][steel_type];
1383 void DrawScreenElement(int x, int y, int element)
1385 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
1386 DrawLevelFieldCrumbledSand(LEVELX(x), LEVELY(y));
1389 void DrawLevelElement(int x, int y, int element)
1391 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1392 DrawScreenElement(SCREENX(x), SCREENY(y), element);
1395 void DrawScreenField(int x, int y)
1397 int lx = LEVELX(x), ly = LEVELY(y);
1398 int element, content;
1400 if (!IN_LEV_FIELD(lx, ly))
1402 if (lx < -1 || lx > lev_fieldx || ly < -1 || ly > lev_fieldy)
1405 element = getBorderElement(lx, ly);
1407 DrawScreenElement(x, y, element);
1411 element = Feld[lx][ly];
1412 content = Store[lx][ly];
1414 if (IS_MOVING(lx, ly))
1416 int horiz_move = (MovDir[lx][ly] == MV_LEFT || MovDir[lx][ly] == MV_RIGHT);
1417 boolean cut_mode = NO_CUTTING;
1419 if (element == EL_QUICKSAND_EMPTYING ||
1420 element == EL_MAGIC_WALL_EMPTYING ||
1421 element == EL_BD_MAGIC_WALL_EMPTYING ||
1422 element == EL_AMOEBA_DROPPING)
1423 cut_mode = CUT_ABOVE;
1424 else if (element == EL_QUICKSAND_FILLING ||
1425 element == EL_MAGIC_WALL_FILLING ||
1426 element == EL_BD_MAGIC_WALL_FILLING)
1427 cut_mode = CUT_BELOW;
1429 if (cut_mode == CUT_ABOVE)
1430 DrawScreenElementShifted(x, y, 0, 0, element, NO_CUTTING);
1432 DrawScreenElement(x, y, EL_EMPTY);
1435 DrawScreenElementShifted(x, y, MovPos[lx][ly], 0, element, NO_CUTTING);
1436 else if (cut_mode == NO_CUTTING)
1437 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], element, cut_mode);
1439 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], content, cut_mode);
1441 if (content == EL_ACID)
1442 DrawLevelElementThruMask(lx, ly + 1, EL_ACID);
1444 else if (IS_BLOCKED(lx, ly))
1449 boolean cut_mode = NO_CUTTING;
1450 int element_old, content_old;
1452 Blocked2Moving(lx, ly, &oldx, &oldy);
1455 horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
1456 MovDir[oldx][oldy] == MV_RIGHT);
1458 element_old = Feld[oldx][oldy];
1459 content_old = Store[oldx][oldy];
1461 if (element_old == EL_QUICKSAND_EMPTYING ||
1462 element_old == EL_MAGIC_WALL_EMPTYING ||
1463 element_old == EL_BD_MAGIC_WALL_EMPTYING ||
1464 element_old == EL_AMOEBA_DROPPING)
1465 cut_mode = CUT_ABOVE;
1467 DrawScreenElement(x, y, EL_EMPTY);
1470 DrawScreenElementShifted(sx, sy, MovPos[oldx][oldy], 0, element_old,
1472 else if (cut_mode == NO_CUTTING)
1473 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], element_old,
1476 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], content_old,
1479 else if (IS_DRAWABLE(element))
1480 DrawScreenElement(x, y, element);
1482 DrawScreenElement(x, y, EL_EMPTY);
1485 void DrawLevelField(int x, int y)
1487 if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1488 DrawScreenField(SCREENX(x), SCREENY(y));
1489 else if (IS_MOVING(x, y))
1493 Moving2Blocked(x, y, &newx, &newy);
1494 if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
1495 DrawScreenField(SCREENX(newx), SCREENY(newy));
1497 else if (IS_BLOCKED(x, y))
1501 Blocked2Moving(x, y, &oldx, &oldy);
1502 if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
1503 DrawScreenField(SCREENX(oldx), SCREENY(oldy));
1507 void DrawMiniElement(int x, int y, int element)
1511 graphic = el2edimg(element);
1512 DrawMiniGraphic(x, y, graphic);
1515 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
1517 int x = sx + scroll_x, y = sy + scroll_y;
1519 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
1520 DrawMiniElement(sx, sy, EL_EMPTY);
1521 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
1522 DrawMiniElement(sx, sy, Feld[x][y]);
1524 DrawMiniGraphic(sx, sy, el2edimg(getBorderElement(x, y)));
1527 void getMicroGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
1529 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
1530 int mini_startx = src_bitmap->width * 3 / 4;
1531 int mini_starty = src_bitmap->height * 2 / 3;
1532 int src_x = mini_startx + graphic_info[graphic].src_x / 8;
1533 int src_y = mini_starty + graphic_info[graphic].src_y / 8;
1535 *bitmap = src_bitmap;
1540 void DrawMicroElement(int xpos, int ypos, int element)
1544 int graphic = el2preimg(element);
1546 getMicroGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
1547 BlitBitmap(src_bitmap, drawto, src_x, src_y, MICRO_TILEX, MICRO_TILEY,
1555 SetDrawBackgroundMask(REDRAW_NONE);
1558 for(x=BX1; x<=BX2; x++)
1559 for(y=BY1; y<=BY2; y++)
1560 DrawScreenField(x, y);
1562 redraw_mask |= REDRAW_FIELD;
1565 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
1569 for(x=0; x<size_x; x++)
1570 for(y=0; y<size_y; y++)
1571 DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
1573 redraw_mask |= REDRAW_FIELD;
1576 static void DrawMicroLevelExt(int xpos, int ypos, int from_x, int from_y)
1580 DrawBackground(xpos, ypos, MICROLEV_XSIZE, MICROLEV_YSIZE);
1582 if (lev_fieldx < STD_LEV_FIELDX)
1583 xpos += (STD_LEV_FIELDX - lev_fieldx) / 2 * MICRO_TILEX;
1584 if (lev_fieldy < STD_LEV_FIELDY)
1585 ypos += (STD_LEV_FIELDY - lev_fieldy) / 2 * MICRO_TILEY;
1587 xpos += MICRO_TILEX;
1588 ypos += MICRO_TILEY;
1590 for(x=-1; x<=STD_LEV_FIELDX; x++)
1592 for(y=-1; y<=STD_LEV_FIELDY; y++)
1594 int lx = from_x + x, ly = from_y + y;
1596 if (lx >= 0 && lx < lev_fieldx && ly >= 0 && ly < lev_fieldy)
1597 DrawMicroElement(xpos + x * MICRO_TILEX, ypos + y * MICRO_TILEY,
1598 level.field[lx][ly]);
1599 else if (lx >= -1 && lx < lev_fieldx+1 && ly >= -1 && ly < lev_fieldy+1
1600 && BorderElement != EL_EMPTY)
1601 DrawMicroElement(xpos + x * MICRO_TILEX, ypos + y * MICRO_TILEY,
1602 getBorderElement(lx, ly));
1606 redraw_mask |= REDRAW_MICROLEVEL;
1609 #define MICROLABEL_EMPTY 0
1610 #define MICROLABEL_LEVEL_NAME 1
1611 #define MICROLABEL_CREATED_BY 2
1612 #define MICROLABEL_LEVEL_AUTHOR 3
1613 #define MICROLABEL_IMPORTED_FROM 4
1614 #define MICROLABEL_LEVEL_IMPORT_INFO 5
1616 static void DrawMicroLevelLabelExt(int mode)
1618 char label_text[MAX_OUTPUT_LINESIZE + 1];
1619 int max_len_label_text;
1620 int font_nr = FONT_TEXT_2;
1622 if (mode == MICROLABEL_CREATED_BY || mode == MICROLABEL_IMPORTED_FROM)
1623 font_nr = FONT_TEXT_3;
1625 max_len_label_text = SXSIZE / getFontWidth(font_nr);
1627 DrawBackground(SX, MICROLABEL_YPOS, SXSIZE, getFontHeight(font_nr));
1629 strncpy(label_text, (mode == MICROLABEL_LEVEL_NAME ? level.name :
1630 mode == MICROLABEL_CREATED_BY ? "created by" :
1631 mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
1632 mode == MICROLABEL_IMPORTED_FROM ? "imported from" :
1633 mode == MICROLABEL_LEVEL_IMPORT_INFO ?
1634 leveldir_current->imported_from : ""),
1635 max_len_label_text);
1636 label_text[max_len_label_text] = '\0';
1638 if (strlen(label_text) > 0)
1640 int text_width = strlen(label_text) * getFontWidth(font_nr);
1641 int lxpos = SX + (SXSIZE - text_width) / 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 len = strlen(leveldir_current->name);
1678 int lxpos = SX + (SXSIZE - len * getFontWidth(FONT_TEXT_1)) / 2;
1679 int lypos = SY + 352;
1681 DrawText(lxpos, lypos, leveldir_current->name, FONT_TEXT_1);
1684 game_status = last_game_status; /* restore current game status */
1689 /* scroll micro level, if needed */
1690 if ((lev_fieldx > STD_LEV_FIELDX || lev_fieldy > STD_LEV_FIELDY) &&
1691 DelayReached(&scroll_delay, MICROLEVEL_SCROLL_DELAY))
1693 switch (scroll_direction)
1699 scroll_direction = MV_UP;
1703 if (from_x < lev_fieldx - STD_LEV_FIELDX)
1706 scroll_direction = MV_DOWN;
1713 scroll_direction = MV_RIGHT;
1717 if (from_y < lev_fieldy - STD_LEV_FIELDY)
1720 scroll_direction = MV_LEFT;
1727 DrawMicroLevelExt(xpos, ypos, from_x, from_y);
1730 /* redraw micro level label, if needed */
1731 if (strcmp(level.name, NAMELESS_LEVEL_NAME) != 0 &&
1732 strcmp(level.author, ANONYMOUS_NAME) != 0 &&
1733 strcmp(level.author, leveldir_current->name) != 0 &&
1734 DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
1736 int max_label_counter = 23;
1738 if (leveldir_current->imported_from != NULL)
1739 max_label_counter += 14;
1741 label_counter = (label_counter + 1) % max_label_counter;
1742 label_state = (label_counter >= 0 && label_counter <= 7 ?
1743 MICROLABEL_LEVEL_NAME :
1744 label_counter >= 9 && label_counter <= 12 ?
1745 MICROLABEL_CREATED_BY :
1746 label_counter >= 14 && label_counter <= 21 ?
1747 MICROLABEL_LEVEL_AUTHOR :
1748 label_counter >= 23 && label_counter <= 26 ?
1749 MICROLABEL_IMPORTED_FROM :
1750 label_counter >= 28 && label_counter <= 35 ?
1751 MICROLABEL_LEVEL_IMPORT_INFO : MICROLABEL_EMPTY);
1752 DrawMicroLevelLabelExt(label_state);
1755 game_status = last_game_status; /* restore current game status */
1758 int REQ_in_range(int x, int y)
1760 if (y > DY+249 && y < DY+278)
1762 if (x > DX+1 && x < DX+48)
1764 else if (x > DX+51 && x < DX+98)
1770 #define MAX_REQUEST_LINES 13
1771 #define MAX_REQUEST_LINE_LEN 7
1773 boolean Request(char *text, unsigned int req_state)
1775 int mx, my, ty, result = -1;
1776 unsigned int old_door_state;
1777 int last_game_status = game_status; /* save current game status */
1779 #if defined(PLATFORM_UNIX)
1780 /* pause network game while waiting for request to answer */
1781 if (options.network &&
1782 game_status == GAME_MODE_PLAYING &&
1783 req_state & REQUEST_WAIT_FOR)
1784 SendToServer_PausePlaying();
1787 old_door_state = GetDoorState();
1789 /* simulate releasing mouse button over last gadget, if still pressed */
1791 HandleGadgets(-1, -1, 0);
1795 CloseDoor(DOOR_CLOSE_1);
1797 /* save old door content */
1798 BlitBitmap(bitmap_db_door, bitmap_db_door,
1799 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
1800 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
1802 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
1804 /* clear door drawing field */
1805 DrawBackground(DX, DY, DXSIZE, DYSIZE);
1807 /* force DOOR font on preview level */
1808 game_status = GAME_MODE_PSEUDO_DOOR;
1810 /* write text for request */
1811 for(ty=0; ty < MAX_REQUEST_LINES; ty++)
1813 char text_line[MAX_REQUEST_LINE_LEN + 1];
1819 for(tl=0,tx=0; tx < MAX_REQUEST_LINE_LEN; tl++,tx++)
1822 if (!tc || tc == ' ')
1833 strncpy(text_line, text, tl);
1836 DrawText(DX + (DXSIZE - tl * getFontWidth(FONT_TEXT_2)) / 2,
1837 DY + 8 + ty * (getFontHeight(FONT_TEXT_2) + 2),
1838 text_line, FONT_TEXT_2);
1840 text += tl + (tc == ' ' ? 1 : 0);
1843 game_status = last_game_status; /* restore current game status */
1845 if (req_state & REQ_ASK)
1847 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
1848 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
1850 else if (req_state & REQ_CONFIRM)
1852 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
1854 else if (req_state & REQ_PLAYER)
1856 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
1857 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
1858 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
1859 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
1862 /* copy request gadgets to door backbuffer */
1863 BlitBitmap(drawto, bitmap_db_door,
1864 DX, DY, DXSIZE, DYSIZE,
1865 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
1867 OpenDoor(DOOR_OPEN_1);
1873 if (!(req_state & REQUEST_WAIT_FOR))
1875 SetDrawBackgroundMask(REDRAW_FIELD);
1880 if (game_status != GAME_MODE_MAIN)
1883 button_status = MB_RELEASED;
1885 request_gadget_id = -1;
1887 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
1899 case EVENT_BUTTONPRESS:
1900 case EVENT_BUTTONRELEASE:
1901 case EVENT_MOTIONNOTIFY:
1903 if (event.type == EVENT_MOTIONNOTIFY)
1905 if (!PointerInWindow(window))
1906 continue; /* window and pointer are on different screens */
1911 motion_status = TRUE;
1912 mx = ((MotionEvent *) &event)->x;
1913 my = ((MotionEvent *) &event)->y;
1917 motion_status = FALSE;
1918 mx = ((ButtonEvent *) &event)->x;
1919 my = ((ButtonEvent *) &event)->y;
1920 if (event.type == EVENT_BUTTONPRESS)
1921 button_status = ((ButtonEvent *) &event)->button;
1923 button_status = MB_RELEASED;
1926 /* this sets 'request_gadget_id' */
1927 HandleGadgets(mx, my, button_status);
1929 switch(request_gadget_id)
1931 case TOOL_CTRL_ID_YES:
1934 case TOOL_CTRL_ID_NO:
1937 case TOOL_CTRL_ID_CONFIRM:
1938 result = TRUE | FALSE;
1941 case TOOL_CTRL_ID_PLAYER_1:
1944 case TOOL_CTRL_ID_PLAYER_2:
1947 case TOOL_CTRL_ID_PLAYER_3:
1950 case TOOL_CTRL_ID_PLAYER_4:
1961 case EVENT_KEYPRESS:
1962 switch(GetEventKey((KeyEvent *)&event, TRUE))
1975 if (req_state & REQ_PLAYER)
1979 case EVENT_KEYRELEASE:
1980 ClearPlayerAction();
1984 HandleOtherEvents(&event);
1988 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
1990 int joy = AnyJoystick();
1992 if (joy & JOY_BUTTON_1)
1994 else if (joy & JOY_BUTTON_2)
2000 /* don't eat all CPU time */
2004 if (game_status != GAME_MODE_MAIN)
2009 if (!(req_state & REQ_STAY_OPEN))
2011 CloseDoor(DOOR_CLOSE_1);
2013 if (!(req_state & REQ_STAY_CLOSED) && (old_door_state & DOOR_OPEN_1))
2015 BlitBitmap(bitmap_db_door, bitmap_db_door,
2016 DOOR_GFX_PAGEX2,DOOR_GFX_PAGEY1, DXSIZE,DYSIZE,
2017 DOOR_GFX_PAGEX1,DOOR_GFX_PAGEY1);
2018 OpenDoor(DOOR_OPEN_1);
2024 SetDrawBackgroundMask(REDRAW_FIELD);
2026 #if defined(PLATFORM_UNIX)
2027 /* continue network game after request */
2028 if (options.network &&
2029 game_status == GAME_MODE_PLAYING &&
2030 req_state & REQUEST_WAIT_FOR)
2031 SendToServer_ContinuePlaying();
2037 unsigned int OpenDoor(unsigned int door_state)
2039 unsigned int new_door_state;
2041 if (door_state & DOOR_COPY_BACK)
2043 BlitBitmap(bitmap_db_door, bitmap_db_door,
2044 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE + VYSIZE,
2045 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2046 door_state &= ~DOOR_COPY_BACK;
2049 new_door_state = MoveDoor(door_state);
2051 return(new_door_state);
2054 unsigned int CloseDoor(unsigned int door_state)
2056 unsigned int new_door_state;
2058 BlitBitmap(backbuffer, bitmap_db_door,
2059 DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2060 BlitBitmap(backbuffer, bitmap_db_door,
2061 VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
2063 new_door_state = MoveDoor(door_state);
2065 return(new_door_state);
2068 unsigned int GetDoorState()
2070 return MoveDoor(DOOR_GET_STATE);
2073 unsigned int SetDoorState(unsigned int door_state)
2075 return MoveDoor(door_state | DOOR_SET_STATE);
2078 unsigned int MoveDoor(unsigned int door_state)
2080 static int door1 = DOOR_OPEN_1;
2081 static int door2 = DOOR_CLOSE_2;
2082 static unsigned long door_delay = 0;
2083 int x, start, stepsize = door.step_offset;
2084 unsigned long door_delay_value = door.step_delay;
2086 if (door_state == DOOR_GET_STATE)
2087 return(door1 | door2);
2089 if (door_state & DOOR_SET_STATE)
2091 if (door_state & DOOR_ACTION_1)
2092 door1 = door_state & DOOR_ACTION_1;
2093 if (door_state & DOOR_ACTION_2)
2094 door2 = door_state & DOOR_ACTION_2;
2096 return(door1 | door2);
2099 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
2100 door_state &= ~DOOR_OPEN_1;
2101 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
2102 door_state &= ~DOOR_CLOSE_1;
2103 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
2104 door_state &= ~DOOR_OPEN_2;
2105 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
2106 door_state &= ~DOOR_CLOSE_2;
2108 if (setup.quick_doors)
2111 door_delay_value = 0;
2113 StopSound(SND_DOOR_OPENING);
2114 StopSound(SND_DOOR_CLOSING);
2117 if (global.autoplay_leveldir)
2119 door_state |= DOOR_NO_DELAY;
2120 door_state &= ~DOOR_CLOSE_ALL;
2123 if (door_state & DOOR_ACTION)
2125 if (!(door_state & DOOR_NO_DELAY))
2127 /* opening door sound has priority over simultaneously closing door */
2128 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
2129 PlaySoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
2130 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
2131 PlaySoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
2134 start = ((door_state & DOOR_NO_DELAY) ? DXSIZE : 0);
2136 for(x=start; x<=DXSIZE; x+=stepsize)
2138 Bitmap *bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
2139 GC gc = bitmap->stored_clip_gc;
2141 if (!(door_state & DOOR_NO_DELAY))
2142 WaitUntilDelayReached(&door_delay, door_delay_value);
2144 if (door_state & DOOR_ACTION_1)
2146 int i = (door_state & DOOR_OPEN_1 ? DXSIZE-x : x);
2147 int j = (DXSIZE - i) / 3;
2149 BlitBitmap(bitmap_db_door, drawto,
2150 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + i/2,
2151 DXSIZE,DYSIZE - i/2, DX, DY);
2153 ClearRectangle(drawto, DX, DY + DYSIZE - i/2, DXSIZE,i/2);
2155 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2156 BlitBitmapMasked(bitmap, drawto,
2157 DXSIZE, DOOR_GFX_PAGEY1, i, 77,
2158 DX + DXSIZE - i, DY + j);
2159 BlitBitmapMasked(bitmap, drawto,
2160 DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63,
2161 DX + DXSIZE - i, DY + 140 + j);
2162 SetClipOrigin(bitmap, gc, DX - DXSIZE + i, DY - (DOOR_GFX_PAGEY1 + j));
2163 BlitBitmapMasked(bitmap, drawto,
2164 DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j,
2166 BlitBitmapMasked(bitmap, drawto,
2167 DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63,
2170 BlitBitmapMasked(bitmap, drawto,
2171 DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
2173 BlitBitmapMasked(bitmap, drawto,
2174 DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
2176 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2177 BlitBitmapMasked(bitmap, drawto,
2178 DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
2179 DX + DXSIZE - i, DY + 77 + j);
2180 BlitBitmapMasked(bitmap, drawto,
2181 DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
2182 DX + DXSIZE - i, DY + 203 + j);
2184 redraw_mask |= REDRAW_DOOR_1;
2187 if (door_state & DOOR_ACTION_2)
2189 int i = (door_state & DOOR_OPEN_2 ? VXSIZE - x : x);
2190 int j = (VXSIZE - i) / 3;
2192 BlitBitmap(bitmap_db_door, drawto,
2193 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + i/2,
2194 VXSIZE, VYSIZE - i/2, VX, VY);
2196 ClearRectangle(drawto, VX, VY + VYSIZE-i/2, VXSIZE, i/2);
2198 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2199 BlitBitmapMasked(bitmap, drawto,
2200 VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2,
2201 VX + VXSIZE-i, VY+j);
2202 SetClipOrigin(bitmap, gc,
2203 VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
2204 BlitBitmapMasked(bitmap, drawto,
2205 VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j,
2208 BlitBitmapMasked(bitmap, drawto,
2209 VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2,
2210 i, VYSIZE / 2, VX, VY + VYSIZE / 2 - j);
2211 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2212 BlitBitmapMasked(bitmap, drawto,
2213 VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2,
2215 VX + VXSIZE - i, VY + VYSIZE / 2 + j);
2217 redraw_mask |= REDRAW_DOOR_2;
2222 if (game_status == GAME_MODE_MAIN)
2227 if (setup.quick_doors)
2229 StopSound(SND_DOOR_OPENING);
2230 StopSound(SND_DOOR_CLOSING);
2233 if (door_state & DOOR_ACTION_1)
2234 door1 = door_state & DOOR_ACTION_1;
2235 if (door_state & DOOR_ACTION_2)
2236 door2 = door_state & DOOR_ACTION_2;
2238 return (door1 | door2);
2241 void DrawSpecialEditorDoor()
2243 /* draw bigger toolbox window */
2244 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
2245 DOOR_GFX_PAGEX7, 0, EXSIZE + 8, 8,
2247 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
2248 EX - 4, VY - 4, EXSIZE + 8, EYSIZE - VYSIZE + 4,
2251 redraw_mask |= REDRAW_ALL;
2254 void UndrawSpecialEditorDoor()
2256 /* draw normal tape recorder window */
2257 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
2258 EX - 4, EY - 12, EXSIZE + 8, EYSIZE - VYSIZE + 12,
2261 redraw_mask |= REDRAW_ALL;
2265 /* ---------- new tool button stuff ---------------------------------------- */
2267 /* graphic position values for tool buttons */
2268 #define TOOL_BUTTON_YES_XPOS 2
2269 #define TOOL_BUTTON_YES_YPOS 250
2270 #define TOOL_BUTTON_YES_GFX_YPOS 0
2271 #define TOOL_BUTTON_YES_XSIZE 46
2272 #define TOOL_BUTTON_YES_YSIZE 28
2273 #define TOOL_BUTTON_NO_XPOS 52
2274 #define TOOL_BUTTON_NO_YPOS TOOL_BUTTON_YES_YPOS
2275 #define TOOL_BUTTON_NO_GFX_YPOS TOOL_BUTTON_YES_GFX_YPOS
2276 #define TOOL_BUTTON_NO_XSIZE TOOL_BUTTON_YES_XSIZE
2277 #define TOOL_BUTTON_NO_YSIZE TOOL_BUTTON_YES_YSIZE
2278 #define TOOL_BUTTON_CONFIRM_XPOS TOOL_BUTTON_YES_XPOS
2279 #define TOOL_BUTTON_CONFIRM_YPOS TOOL_BUTTON_YES_YPOS
2280 #define TOOL_BUTTON_CONFIRM_GFX_YPOS 30
2281 #define TOOL_BUTTON_CONFIRM_XSIZE 96
2282 #define TOOL_BUTTON_CONFIRM_YSIZE TOOL_BUTTON_YES_YSIZE
2283 #define TOOL_BUTTON_PLAYER_XSIZE 30
2284 #define TOOL_BUTTON_PLAYER_YSIZE 30
2285 #define TOOL_BUTTON_PLAYER_GFX_XPOS 5
2286 #define TOOL_BUTTON_PLAYER_GFX_YPOS 185
2287 #define TOOL_BUTTON_PLAYER_XPOS (5 + TOOL_BUTTON_PLAYER_XSIZE / 2)
2288 #define TOOL_BUTTON_PLAYER_YPOS (215 - TOOL_BUTTON_PLAYER_YSIZE / 2)
2289 #define TOOL_BUTTON_PLAYER1_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2290 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2291 #define TOOL_BUTTON_PLAYER2_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2292 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2293 #define TOOL_BUTTON_PLAYER3_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2294 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2295 #define TOOL_BUTTON_PLAYER4_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2296 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2297 #define TOOL_BUTTON_PLAYER1_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2298 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2299 #define TOOL_BUTTON_PLAYER2_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2300 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2301 #define TOOL_BUTTON_PLAYER3_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2302 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2303 #define TOOL_BUTTON_PLAYER4_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2304 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2313 } toolbutton_info[NUM_TOOL_BUTTONS] =
2316 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_GFX_YPOS,
2317 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_YPOS,
2318 TOOL_BUTTON_YES_XSIZE, TOOL_BUTTON_YES_YSIZE,
2323 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_GFX_YPOS,
2324 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_YPOS,
2325 TOOL_BUTTON_NO_XSIZE, TOOL_BUTTON_NO_YSIZE,
2330 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_GFX_YPOS,
2331 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_YPOS,
2332 TOOL_BUTTON_CONFIRM_XSIZE, TOOL_BUTTON_CONFIRM_YSIZE,
2333 TOOL_CTRL_ID_CONFIRM,
2337 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2338 TOOL_BUTTON_PLAYER1_XPOS, TOOL_BUTTON_PLAYER1_YPOS,
2339 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2340 TOOL_CTRL_ID_PLAYER_1,
2344 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2345 TOOL_BUTTON_PLAYER2_XPOS, TOOL_BUTTON_PLAYER2_YPOS,
2346 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2347 TOOL_CTRL_ID_PLAYER_2,
2351 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2352 TOOL_BUTTON_PLAYER3_XPOS, TOOL_BUTTON_PLAYER3_YPOS,
2353 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2354 TOOL_CTRL_ID_PLAYER_3,
2358 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2359 TOOL_BUTTON_PLAYER4_XPOS, TOOL_BUTTON_PLAYER4_YPOS,
2360 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2361 TOOL_CTRL_ID_PLAYER_4,
2366 void CreateToolButtons()
2370 for (i=0; i<NUM_TOOL_BUTTONS; i++)
2372 Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
2373 Bitmap *deco_bitmap = None;
2374 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
2375 struct GadgetInfo *gi;
2376 unsigned long event_mask;
2377 int gd_xoffset, gd_yoffset;
2378 int gd_x1, gd_x2, gd_y;
2381 event_mask = GD_EVENT_RELEASED;
2383 gd_xoffset = toolbutton_info[i].xpos;
2384 gd_yoffset = toolbutton_info[i].ypos;
2385 gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
2386 gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
2387 gd_y = DOOR_GFX_PAGEY1 + gd_yoffset;
2389 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
2391 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
2393 getMiniGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr),
2394 &deco_bitmap, &deco_x, &deco_y);
2395 deco_xpos = (toolbutton_info[i].width - MINI_TILEX) / 2;
2396 deco_ypos = (toolbutton_info[i].height - MINI_TILEY) / 2;
2399 gi = CreateGadget(GDI_CUSTOM_ID, id,
2400 GDI_INFO_TEXT, toolbutton_info[i].infotext,
2401 GDI_X, DX + toolbutton_info[i].x,
2402 GDI_Y, DY + toolbutton_info[i].y,
2403 GDI_WIDTH, toolbutton_info[i].width,
2404 GDI_HEIGHT, toolbutton_info[i].height,
2405 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
2406 GDI_STATE, GD_BUTTON_UNPRESSED,
2407 GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
2408 GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
2409 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
2410 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
2411 GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
2412 GDI_DECORATION_SHIFTING, 1, 1,
2413 GDI_EVENT_MASK, event_mask,
2414 GDI_CALLBACK_ACTION, HandleToolButtons,
2418 Error(ERR_EXIT, "cannot create gadget");
2420 tool_gadget[id] = gi;
2424 void FreeToolButtons()
2428 for (i=0; i<NUM_TOOL_BUTTONS; i++)
2429 FreeGadget(tool_gadget[i]);
2432 static void UnmapToolButtons()
2436 for (i=0; i<NUM_TOOL_BUTTONS; i++)
2437 UnmapGadget(tool_gadget[i]);
2440 static void HandleToolButtons(struct GadgetInfo *gi)
2442 request_gadget_id = gi->custom_id;
2445 int get_next_element(int element)
2449 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
2450 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
2451 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
2452 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
2453 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
2454 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
2455 case EL_AMOEBA_DROPPING: return EL_AMOEBA_WET;
2457 default: return element;
2461 int el_act_dir2img(int element, int action, int direction)
2463 element = GFX_ELEMENT(element);
2464 direction = MV_DIR_BIT(direction);
2466 return element_info[element].direction_graphic[action][direction];
2469 static int el_act_dir2crm(int element, int action, int direction)
2471 element = GFX_ELEMENT(element);
2472 direction = MV_DIR_BIT(direction);
2474 return element_info[element].direction_crumbled[action][direction];
2477 int el_act2img(int element, int action)
2479 element = GFX_ELEMENT(element);
2481 return element_info[element].graphic[action];
2484 int el_dir2img(int element, int direction)
2486 element = GFX_ELEMENT(element);
2488 return el_act_dir2img(element, ACTION_DEFAULT, direction);
2491 int el2img(int element)
2493 element = GFX_ELEMENT(element);
2495 return element_info[element].graphic[ACTION_DEFAULT];
2498 int el2edimg(int element)
2500 element = GFX_ELEMENT(element);
2502 return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
2505 int el2preimg(int element)
2507 element = GFX_ELEMENT(element);
2509 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];