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 *);
38 static struct GadgetInfo *tool_gadget[NUM_TOOL_BUTTONS];
39 static int request_gadget_id = -1;
41 void SetDrawtoField(int mode)
43 if (mode == DRAW_BUFFERED && setup.soft_scrolling)
54 drawto_field = fieldbuffer;
56 else /* DRAW_DIRECT, DRAW_BACKBUFFER */
67 drawto_field = (mode == DRAW_DIRECT ? window : backbuffer);
71 void RedrawPlayfield(boolean force_redraw, int x, int y, int width, int height)
73 if (game_status == PLAYING)
79 width = gfx.sxsize + 2 * TILEX;
80 height = gfx.sysize + 2 * TILEY;
83 if (force_redraw || setup.direct_draw)
86 int x1 = (x - SX) / TILEX, y1 = (y - SY) / TILEY;
87 int x2 = (x - SX + width) / TILEX, y2 = (y - SY + height) / TILEY;
89 if (setup.direct_draw)
90 SetDrawtoField(DRAW_BACKBUFFER);
92 for(xx=BX1; xx<=BX2; xx++)
93 for(yy=BY1; yy<=BY2; yy++)
94 if (xx >= x1 && xx <= x2 && yy >= y1 && yy <= y2)
95 DrawScreenField(xx, yy);
98 if (setup.direct_draw)
99 SetDrawtoField(DRAW_DIRECT);
102 if (setup.soft_scrolling)
104 int fx = FX, fy = FY;
106 fx += (ScreenMovDir & (MV_LEFT|MV_RIGHT) ? ScreenGfxPos : 0);
107 fy += (ScreenMovDir & (MV_UP|MV_DOWN) ? ScreenGfxPos : 0);
109 BlitBitmap(fieldbuffer, backbuffer, fx,fy, SXSIZE,SYSIZE, SX,SY);
113 BlitBitmap(drawto, window, x, y, width, height, x, y);
119 DrawBuffer *buffer = (drawto_field == window ? backbuffer : drawto_field);
121 if (setup.direct_draw && game_status == PLAYING)
122 redraw_mask &= ~REDRAW_MAIN;
124 if (redraw_mask & REDRAW_TILES && redraw_tiles > REDRAWTILES_THRESHOLD)
125 redraw_mask |= REDRAW_FIELD;
127 if (redraw_mask & REDRAW_FIELD)
128 redraw_mask &= ~REDRAW_TILES;
130 if (redraw_mask == REDRAW_NONE)
133 if (global.fps_slowdown && game_status == PLAYING)
135 static boolean last_frame_skipped = FALSE;
136 boolean skip_even_when_not_scrolling = TRUE;
137 boolean just_scrolling = (ScreenMovDir != 0);
138 boolean verbose = FALSE;
140 if (global.fps_slowdown_factor > 1 &&
141 (FrameCounter % global.fps_slowdown_factor) &&
142 (just_scrolling || skip_even_when_not_scrolling))
144 redraw_mask &= ~REDRAW_MAIN;
146 last_frame_skipped = TRUE;
149 printf("FRAME SKIPPED\n");
153 if (last_frame_skipped)
154 redraw_mask |= REDRAW_FIELD;
156 last_frame_skipped = FALSE;
159 printf("frame not skipped\n");
163 /* synchronize X11 graphics at this point; if we would synchronize the
164 display immediately after the buffer switching (after the XFlush),
165 this could mean that we have to wait for the graphics to complete,
166 although we could go on doing calculations for the next frame */
170 if (redraw_mask & REDRAW_ALL)
172 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
176 if (redraw_mask & REDRAW_FIELD)
178 if (game_status != PLAYING || redraw_mask & REDRAW_FROM_BACKBUFFER)
180 BlitBitmap(backbuffer, window,
181 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE, REAL_SX, REAL_SY);
185 int fx = FX, fy = FY;
187 if (setup.soft_scrolling)
189 fx += (ScreenMovDir & (MV_LEFT | MV_RIGHT) ? ScreenGfxPos : 0);
190 fy += (ScreenMovDir & (MV_UP | MV_DOWN) ? ScreenGfxPos : 0);
193 if (setup.soft_scrolling ||
194 ABS(ScreenMovPos) + ScrollStepSize == TILEX ||
195 ABS(ScreenMovPos) == ScrollStepSize ||
196 redraw_tiles > REDRAWTILES_THRESHOLD)
198 BlitBitmap(buffer, window, fx, fy, SXSIZE, SYSIZE, SX, SY);
202 printf("redrawing all (ScreenGfxPos == %d) because %s\n",
204 (setup.soft_scrolling ?
205 "setup.soft_scrolling" :
206 ABS(ScreenGfxPos) + ScrollStepSize == TILEX ?
207 "ABS(ScreenGfxPos) + ScrollStepSize == TILEX" :
208 ABS(ScreenGfxPos) == ScrollStepSize ?
209 "ABS(ScreenGfxPos) == ScrollStepSize" :
210 "redraw_tiles > REDRAWTILES_THRESHOLD"));
216 redraw_mask &= ~REDRAW_MAIN;
219 if (redraw_mask & REDRAW_DOORS)
221 if (redraw_mask & REDRAW_DOOR_1)
222 BlitBitmap(backbuffer, window, DX, DY, DXSIZE, DYSIZE, DX, DY);
223 if (redraw_mask & REDRAW_DOOR_2)
225 if ((redraw_mask & REDRAW_DOOR_2) == REDRAW_DOOR_2)
226 BlitBitmap(backbuffer, window, VX,VY, VXSIZE,VYSIZE, VX,VY);
229 if (redraw_mask & REDRAW_VIDEO_1)
230 BlitBitmap(backbuffer, window,
231 VX+VIDEO_DISPLAY1_XPOS,VY+VIDEO_DISPLAY1_YPOS,
232 VIDEO_DISPLAY_XSIZE,VIDEO_DISPLAY_YSIZE,
233 VX+VIDEO_DISPLAY1_XPOS,VY+VIDEO_DISPLAY1_YPOS);
234 if (redraw_mask & REDRAW_VIDEO_2)
235 BlitBitmap(backbuffer, window,
236 VX+VIDEO_DISPLAY2_XPOS,VY+VIDEO_DISPLAY2_YPOS,
237 VIDEO_DISPLAY_XSIZE,VIDEO_DISPLAY_YSIZE,
238 VX+VIDEO_DISPLAY2_XPOS,VY+VIDEO_DISPLAY2_YPOS);
239 if (redraw_mask & REDRAW_VIDEO_3)
240 BlitBitmap(backbuffer, window,
241 VX+VIDEO_CONTROL_XPOS,VY+VIDEO_CONTROL_YPOS,
242 VIDEO_CONTROL_XSIZE,VIDEO_CONTROL_YSIZE,
243 VX+VIDEO_CONTROL_XPOS,VY+VIDEO_CONTROL_YPOS);
246 if (redraw_mask & REDRAW_DOOR_3)
247 BlitBitmap(backbuffer, window, EX, EY, EXSIZE, EYSIZE, EX, EY);
248 redraw_mask &= ~REDRAW_DOORS;
251 if (redraw_mask & REDRAW_MICROLEVEL)
253 BlitBitmap(backbuffer, window,
254 MICROLEV_XPOS, MICROLEV_YPOS, MICROLEV_XSIZE, MICROLEV_YSIZE,
255 MICROLEV_XPOS, MICROLEV_YPOS);
256 BlitBitmap(backbuffer, window,
257 SX, MICROLABEL_YPOS, SXSIZE, FONT4_YSIZE,
258 SX, MICROLABEL_YPOS);
259 redraw_mask &= ~REDRAW_MICROLEVEL;
262 if (redraw_mask & REDRAW_TILES)
264 for(x=0; x<SCR_FIELDX; x++)
265 for(y=0; y<SCR_FIELDY; y++)
266 if (redraw[redraw_x1 + x][redraw_y1 + y])
267 BlitBitmap(buffer, window,
268 FX + x * TILEX, FX + y * TILEY, TILEX, TILEY,
269 SX + x * TILEX, SY + y * TILEY);
272 if (redraw_mask & REDRAW_FPS) /* display frames per second */
277 sprintf(info1, " (only every %d. frame)", global.fps_slowdown_factor);
278 if (!global.fps_slowdown)
281 sprintf(text, "%.1f fps%s", global.frames_per_second, info1);
282 DrawTextExt(window, SX, SY, text, FS_SMALL, FC_YELLOW, FONT_OPAQUE);
287 for(x=0; x<MAX_BUF_XSIZE; x++)
288 for(y=0; y<MAX_BUF_YSIZE; y++)
291 redraw_mask = REDRAW_NONE;
297 long fading_delay = 300;
299 if (setup.fading && (redraw_mask & REDRAW_FIELD))
306 ClearRectangle(window, REAL_SX,REAL_SY,FULL_SXSIZE,FULL_SYSIZE);
309 for(i=0;i<2*FULL_SYSIZE;i++)
311 for(y=0;y<FULL_SYSIZE;y++)
313 BlitBitmap(backbuffer, window,
314 REAL_SX,REAL_SY+i, FULL_SXSIZE,1, REAL_SX,REAL_SY+i);
322 for(i=1;i<FULL_SYSIZE;i+=2)
323 BlitBitmap(backbuffer, window,
324 REAL_SX,REAL_SY+i, FULL_SXSIZE,1, REAL_SX,REAL_SY+i);
330 SetClipOrigin(clip_gc[PIX_FADEMASK], 0, 0);
331 BlitBitmapMasked(backbuffer, window,
332 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
337 SetClipOrigin(clip_gc[PIX_FADEMASK], -1, -1);
338 BlitBitmapMasked(backbuffer, window,
339 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
344 SetClipOrigin(clip_gc[PIX_FADEMASK], 0, -1);
345 BlitBitmapMasked(backbuffer, window,
346 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
351 SetClipOrigin(clip_gc[PIX_FADEMASK], -1, 0);
352 BlitBitmapMasked(backbuffer, window,
353 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
358 redraw_mask &= ~REDRAW_MAIN;
365 void SetMainBackgroundImage(int graphic)
367 SetMainBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
368 graphic_info[graphic].bitmap ?
369 graphic_info[graphic].bitmap :
370 graphic_info[IMG_BACKGROUND_DEFAULT].bitmap);
373 void SetDoorBackgroundImage(int graphic)
375 SetDoorBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
376 graphic_info[graphic].bitmap ?
377 graphic_info[graphic].bitmap :
378 graphic_info[IMG_BACKGROUND_DEFAULT].bitmap);
381 void DrawBackground(int dest_x, int dest_y, int width, int height)
383 ClearRectangleOnBackground(backbuffer, dest_x, dest_y, width, height);
385 redraw_mask |= REDRAW_FIELD;
390 DrawBackground(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
392 if (setup.soft_scrolling && game_status == PLAYING)
394 ClearRectangle(fieldbuffer, 0, 0, FXSIZE, FYSIZE);
395 SetDrawtoField(DRAW_BUFFERED);
398 SetDrawtoField(DRAW_BACKBUFFER);
400 if (setup.direct_draw && game_status == PLAYING)
402 ClearRectangle(window, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
403 SetDrawtoField(DRAW_DIRECT);
407 void MarkTileDirty(int x, int y)
409 int xx = redraw_x1 + x;
410 int yy = redraw_y1 + y;
415 redraw[xx][yy] = TRUE;
416 redraw_mask |= REDRAW_TILES;
419 void SetBorderElement()
423 BorderElement = EL_EMPTY;
425 for(y=0; y<lev_fieldy && BorderElement == EL_EMPTY; y++)
427 for(x=0; x<lev_fieldx; x++)
429 if (!IS_MASSIVE(Feld[x][y]))
430 BorderElement = EL_STEELWALL;
432 if (y != 0 && y != lev_fieldy - 1 && x != lev_fieldx - 1)
438 static int getGraphicAnimationPhase(int frames, int delay, int mode)
442 if (mode & ANIM_PINGPONG)
444 int max_anim_frames = 2 * frames - 2;
446 phase = (FrameCounter % (delay * max_anim_frames)) / delay;
447 phase = (phase < frames ? phase : max_anim_frames - phase);
450 phase = (FrameCounter % (delay * frames)) / delay;
452 if (mode & ANIM_REVERSE)
458 void SetRandomAnimationValue(int x, int y)
460 anim.random_frame = GfxRandom[x][y];
463 inline int getGraphicAnimationFrame(int graphic, int sync_frame)
465 /* animation synchronized with global frame counter, not move position */
466 if (graphic_info[graphic].anim_global_sync || sync_frame < 0)
467 sync_frame = FrameCounter;
469 return getAnimationFrame(graphic_info[graphic].anim_frames,
470 graphic_info[graphic].anim_delay,
471 graphic_info[graphic].anim_mode,
472 graphic_info[graphic].anim_start_frame,
476 inline void DrawGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
477 int graphic, int sync_frame, int mask_mode)
479 int frame = getGraphicAnimationFrame(graphic, sync_frame);
481 if (mask_mode == USE_MASKING)
482 DrawGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
484 DrawGraphicExt(dst_bitmap, x, y, graphic, frame);
487 inline boolean checkDrawGraphicAnimation(int sx, int sy, int graphic)
489 int lx = LEVELX(sx), ly = LEVELY(sy);
491 return (IN_SCR_FIELD(sx, sy) && IS_NEW_FRAME(GfxFrame[lx][ly], graphic));
494 inline boolean checkDrawLevelGraphicAnimation(int lx, int ly, int graphic)
496 int sx = SCREENX(lx), sy = SCREENY(ly);
498 return (IN_SCR_FIELD(sx, sy) && IS_NEW_FRAME(GfxFrame[lx][ly], graphic));
501 inline boolean DrawGraphicAnimation(int x, int y, int graphic)
503 int lx = LEVELX(x), ly = LEVELY(y);
506 if (!checkDrawGraphicAnimation(x, y, graphic))
509 if (!IN_SCR_FIELD(x, y))
513 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
514 graphic, GfxFrame[lx][ly], NO_MASKING);
520 boolean DrawLevelGraphicAnimation(int x, int y, int graphic)
522 return DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
525 boolean DrawLevelElementAnimation(int x, int y, int element)
527 return DrawGraphicAnimation(SCREENX(x), SCREENY(y), el2img(element));
530 inline void ContinueLevelGraphicAnimation(int x, int y, int graphic)
532 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
535 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
538 void ContinueLevelElementAnimation(int x, int y, int element)
540 ContinueLevelGraphicAnimation(x, y, el2img(element));
543 void DrawAllPlayers()
547 for(i=0; i<MAX_PLAYERS; i++)
548 if (stored_player[i].active)
549 DrawPlayer(&stored_player[i]);
552 void DrawPlayerField(int x, int y)
554 if (!IS_PLAYER(x, y))
557 DrawPlayer(PLAYERINFO(x, y));
560 void DrawPlayer(struct PlayerInfo *player)
562 int jx = player->jx, jy = player->jy;
563 int last_jx = player->last_jx, last_jy = player->last_jy;
564 int next_jx = jx + (jx - last_jx), next_jy = jy + (jy - last_jy);
565 int sx = SCREENX(jx), sy = SCREENY(jy);
566 int sxx = 0, syy = 0;
567 int element = Feld[jx][jy], last_element = Feld[last_jx][last_jy];
570 boolean player_is_moving = (last_jx != jx || last_jy != jy ? TRUE : FALSE);
572 if (!player->active || !IN_SCR_FIELD(SCREENX(last_jx), SCREENY(last_jy)))
576 if (!IN_LEV_FIELD(jx,jy))
578 printf("DrawPlayerField(): x = %d, y = %d\n",jx,jy);
579 printf("DrawPlayerField(): sx = %d, sy = %d\n",sx,sy);
580 printf("DrawPlayerField(): This should never happen!\n");
585 if (element == EL_EXPLOSION)
588 /* draw things in the field the player is leaving, if needed */
590 if (player_is_moving)
592 if (Store[last_jx][last_jy] && IS_DRAWABLE(last_element))
594 DrawLevelElement(last_jx, last_jy, Store[last_jx][last_jy]);
596 if (last_element == EL_DYNAMITE_ACTIVE)
597 DrawDynamite(last_jx, last_jy);
599 DrawLevelFieldThruMask(last_jx, last_jy);
601 else if (last_element == EL_DYNAMITE_ACTIVE)
602 DrawDynamite(last_jx, last_jy);
604 DrawLevelField(last_jx, last_jy);
606 if (player->Pushing && IN_SCR_FIELD(SCREENX(next_jx), SCREENY(next_jy)))
610 if (Feld[next_jx][next_jy] == EL_SOKOBAN_FIELD_FULL)
611 DrawLevelElement(next_jx, next_jy, EL_SOKOBAN_FIELD_EMPTY);
613 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
616 DrawLevelField(next_jx, next_jy);
620 if (!IN_SCR_FIELD(sx, sy))
623 if (setup.direct_draw)
624 SetDrawtoField(DRAW_BUFFERED);
626 /* draw things behind the player, if needed */
629 DrawLevelElement(jx, jy, Store[jx][jy]);
630 else if (!IS_ACTIVE_BOMB(element))
631 DrawLevelField(jx, jy);
633 DrawLevelElement(jx, jy, EL_EMPTY);
635 /* draw player himself */
637 if (game.emulation == EMU_SUPAPLEX)
639 static int last_dir = MV_LEFT;
640 int action = (player->programmed_action ? player->programmed_action :
642 boolean action_moving =
644 ((action & (MV_LEFT | MV_RIGHT | MV_UP | MV_DOWN)) &&
645 !(action & ~(MV_LEFT | MV_RIGHT | MV_UP | MV_DOWN))));
647 graphic = IMG_SP_MURPHY;
651 if (player->MovDir == MV_LEFT)
652 graphic = IMG_SP_MURPHY_PUSHING_LEFT;
653 else if (player->MovDir == MV_RIGHT)
654 graphic = IMG_SP_MURPHY_PUSHING_RIGHT;
655 else if (player->MovDir & (MV_UP | MV_DOWN) && last_dir == MV_LEFT)
656 graphic = IMG_SP_MURPHY_PUSHING_LEFT;
657 else if (player->MovDir & (MV_UP | MV_DOWN) && last_dir == MV_RIGHT)
658 graphic = IMG_SP_MURPHY_PUSHING_RIGHT;
660 else if (player->snapped)
662 if (player->MovDir == MV_LEFT)
663 graphic = IMG_SP_MURPHY_SNAPPING_LEFT;
664 else if (player->MovDir == MV_RIGHT)
665 graphic = IMG_SP_MURPHY_SNAPPING_RIGHT;
666 else if (player->MovDir == MV_UP)
667 graphic = IMG_SP_MURPHY_SNAPPING_UP;
668 else if (player->MovDir == MV_DOWN)
669 graphic = IMG_SP_MURPHY_SNAPPING_DOWN;
671 else if (action_moving)
673 if (player->MovDir == MV_LEFT)
674 graphic = IMG_SP_MURPHY_MOVING_LEFT;
675 else if (player->MovDir == MV_RIGHT)
676 graphic = IMG_SP_MURPHY_MOVING_RIGHT;
677 else if (player->MovDir & (MV_UP | MV_DOWN) && last_dir == MV_LEFT)
678 graphic = IMG_SP_MURPHY_MOVING_LEFT;
679 else if (player->MovDir & (MV_UP | MV_DOWN) && last_dir == MV_RIGHT)
680 graphic = IMG_SP_MURPHY_MOVING_RIGHT;
682 graphic = IMG_SP_MURPHY_MOVING_LEFT;
684 frame = getGraphicAnimationFrame(graphic, -1);
687 if (player->MovDir == MV_LEFT || player->MovDir == MV_RIGHT)
688 last_dir = player->MovDir;
692 if (player->MovDir == MV_LEFT)
693 graphic = (player->Pushing ? IMG_PLAYER1_PUSHING_LEFT :
694 player->is_moving ? IMG_PLAYER1_MOVING_LEFT :
696 else if (player->MovDir == MV_RIGHT)
697 graphic = (player->Pushing ? IMG_PLAYER1_PUSHING_RIGHT :
698 player->is_moving ? IMG_PLAYER1_MOVING_RIGHT :
700 else if (player->MovDir == MV_UP)
701 graphic = (player->Pushing ? IMG_PLAYER1_PUSHING_UP :
702 player->is_moving ? IMG_PLAYER1_MOVING_UP :
704 else /* MV_DOWN || MV_NO_MOVING */
705 graphic = (player->Pushing ? IMG_PLAYER1_PUSHING_DOWN :
706 player->is_moving ? IMG_PLAYER1_MOVING_DOWN :
709 graphic = PLAYER_NR_GFX(graphic, player->index_nr);
712 frame = player->Frame;
714 frame = getGraphicAnimationFrame(graphic, player->Frame);
720 if (player->MovDir == MV_LEFT || player->MovDir == MV_RIGHT)
721 sxx = player->GfxPos;
723 syy = player->GfxPos;
726 if (!setup.soft_scrolling && ScreenMovPos)
731 printf("-> %d\n", player->Frame);
734 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
736 if (SHIELD_ON(player))
738 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
739 IMG_SHIELD_NORMAL_ACTIVE);
740 int frame = getGraphicAnimationFrame(graphic, -1);
742 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
746 if (player->Pushing && player->GfxPos)
748 if (player->Pushing && player_is_moving)
751 int px = SCREENX(next_jx), py = SCREENY(next_jy);
754 (element == EL_SOKOBAN_FIELD_EMPTY ||
755 Feld[next_jx][next_jy] == EL_SOKOBAN_FIELD_FULL))
756 DrawGraphicShiftedThruMask(px, py, sxx, syy, IMG_SOKOBAN_OBJECT, 0,
760 int element = Feld[next_jx][next_jy];
761 int graphic = el2img(element);
766 if ((sxx || syy) && IS_PUSHABLE(element))
768 graphic = el_dir_act2img(element, player->MovDir, ACTION_MOVING);
770 frame = getGraphicAnimationFrame(graphic, player->GfxPos);
772 frame = getGraphicAnimationFrame(graphic, player->Frame);
776 printf("-> %d [%d]\n", player->Frame, player->GfxPos);
781 if (player->MovDir == MV_LEFT)
786 frame = (player->GfxPos / (TILEX / 4));
788 if (player->MovDir == MV_RIGHT)
789 frame = (frame + 4) % 4;
793 DrawGraphicShifted(px, py, sxx, syy, graphic, frame,
794 NO_CUTTING, NO_MASKING);
798 /* draw things in front of player (active dynamite or dynabombs) */
800 if (IS_ACTIVE_BOMB(element))
802 graphic = el2img(element);
805 if (element == EL_DYNAMITE_ACTIVE)
807 if ((frame = (96 - MovDelay[jx][jy]) / 12) > 6)
812 if ((frame = ((96 - MovDelay[jx][jy]) / 6) % 8) > 3)
818 frame = getGraphicAnimationFrame(graphic, 96 - MovDelay[jx][jy]);
820 frame = getGraphicAnimationFrame(graphic, GfxFrame[jx][jy]);
825 if (game.emulation == EMU_SUPAPLEX)
826 DrawGraphic(sx, sy, IMG_SP_DISK_RED, frame);
828 DrawGraphicThruMask(sx, sy, graphic, frame);
831 if (player_is_moving && last_element == EL_EXPLOSION)
833 int stored = Store[last_jx][last_jy];
834 int graphic = (game.emulation != EMU_SUPAPLEX ? IMG_EXPLOSION :
835 stored == EL_SP_INFOTRON ? IMG_SP_EXPLOSION_INFOTRON :
837 int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
838 int phase = ExplodePhase[last_jx][last_jy] - 1;
839 int frame = getGraphicAnimationFrame(graphic, phase - delay);
842 DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy), graphic, frame);
845 /* draw elements that stay over the player */
846 /* handle the field the player is leaving ... */
847 if (player_is_moving && IS_OVER_PLAYER(last_element))
848 DrawLevelField(last_jx, last_jy);
850 /* ... and the field the player is entering */
851 if (IS_OVER_PLAYER(element))
852 DrawLevelField(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 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
872 int offset_x = graphic_info[graphic].offset_x;
873 int offset_y = graphic_info[graphic].offset_y;
874 int src_x = graphic_info[graphic].src_x + frame * offset_x;
875 int src_y = graphic_info[graphic].src_y + frame * offset_y;
877 *bitmap = src_bitmap;
882 void DrawGraphic(int x, int y, int graphic, int frame)
885 if (!IN_SCR_FIELD(x, y))
887 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
888 printf("DrawGraphic(): This should never happen!\n");
893 DrawGraphicExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic, frame);
898 void DrawOldGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic)
903 getOldGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
904 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
908 void DrawGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
915 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
917 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
918 int src_x = graphic_info[graphic].src_x;
919 int src_y = graphic_info[graphic].src_y;
920 int offset_x = graphic_info[graphic].offset_x;
921 int offset_y = graphic_info[graphic].offset_y;
923 src_x += frame * offset_x;
924 src_y += frame * offset_y;
927 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
930 void DrawGraphicThruMask(int x, int y, int graphic, int frame)
933 if (!IN_SCR_FIELD(x, y))
935 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
936 printf("DrawGraphicThruMask(): This should never happen!\n");
941 DrawGraphicThruMaskExt(drawto_field, FX + x * TILEX, FY + y *TILEY, graphic,
946 void DrawGraphicThruMaskExt(DrawBuffer *d, int dest_x, int dest_y, int graphic,
954 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
955 drawing_gc = src_bitmap->stored_clip_gc;
957 GC drawing_gc = src_bitmap->stored_clip_gc;
958 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
959 int src_x = graphic_info[graphic].src_x;
960 int src_y = graphic_info[graphic].src_y;
961 int offset_x = graphic_info[graphic].offset_x;
962 int offset_y = graphic_info[graphic].offset_y;
964 src_x += frame * offset_x;
965 src_y += frame * offset_y;
969 SetClipOrigin(src_bitmap, drawing_gc, dest_x - src_x, dest_y - src_y);
970 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX, TILEY, dest_x, dest_y);
973 void DrawMiniGraphic(int x, int y, int graphic)
975 DrawMiniGraphicExt(drawto, SX + x * MINI_TILEX,SY + y * MINI_TILEY, graphic);
976 MarkTileDirty(x / 2, y / 2);
979 void getMiniGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
981 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
983 int mini_starty = src_bitmap->height * 2 / 3;
984 int src_x = mini_startx + graphic_info[graphic].src_x / 2;
985 int src_y = mini_starty + graphic_info[graphic].src_y / 2;
987 if (src_x + MINI_TILEX > src_bitmap->width ||
988 src_y + MINI_TILEY > src_bitmap->height)
990 /* graphic of desired size seems not to be contained in this image;
991 dirty workaround: get it from the middle of the normal sized image */
993 getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
994 src_x += (TILEX / 2 - MINI_TILEX / 2);
995 src_y += (TILEY / 2 - MINI_TILEY / 2);
998 *bitmap = src_bitmap;
1003 void DrawMiniGraphicExt(DrawBuffer *d, int x, int y, int graphic)
1008 getMiniGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
1009 BlitBitmap(src_bitmap, d, src_x, src_y, MINI_TILEX, MINI_TILEY, x, y);
1012 void DrawGraphicShifted(int x,int y, int dx,int dy, int graphic, int frame,
1013 int cut_mode, int mask_mode)
1022 int width = TILEX, height = TILEY;
1028 DrawGraphic(x, y, graphic, frame);
1032 if (dx || dy) /* shifted graphic */
1034 if (x < BX1) /* object enters playfield from the left */
1041 else if (x > BX2) /* object enters playfield from the right */
1047 else if (x==BX1 && dx < 0) /* object leaves playfield to the left */
1053 else if (x==BX2 && dx > 0) /* object leaves playfield to the right */
1055 else if (dx) /* general horizontal movement */
1056 MarkTileDirty(x + SIGN(dx), y);
1058 if (y < BY1) /* object enters playfield from the top */
1060 if (cut_mode==CUT_BELOW) /* object completely above top border */
1068 else if (y > BY2) /* object enters playfield from the bottom */
1074 else if (y==BY1 && dy < 0) /* object leaves playfield to the top */
1080 else if (dy > 0 && cut_mode == CUT_ABOVE)
1082 if (y == BY2) /* object completely above bottom border */
1088 MarkTileDirty(x, y + 1);
1089 } /* object leaves playfield to the bottom */
1090 else if (dy > 0 && (y == BY2 || cut_mode == CUT_BELOW))
1092 else if (dy) /* general vertical movement */
1093 MarkTileDirty(x, y + SIGN(dy));
1096 src_bitmap = graphic_info[graphic].bitmap;
1097 src_x = graphic_info[graphic].src_x;
1098 src_y = graphic_info[graphic].src_y;
1099 offset_x = graphic_info[graphic].offset_x;
1100 offset_y = graphic_info[graphic].offset_y;
1102 drawing_gc = src_bitmap->stored_clip_gc;
1104 src_x += frame * offset_x;
1105 src_y += frame * offset_y;
1110 dest_x = FX + x * TILEX + dx;
1111 dest_y = FY + y * TILEY + dy;
1114 if (!IN_SCR_FIELD(x,y))
1116 printf("DrawGraphicShifted(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
1117 printf("DrawGraphicShifted(): This should never happen!\n");
1122 if (mask_mode == USE_MASKING)
1124 SetClipOrigin(src_bitmap, drawing_gc, dest_x - src_x, dest_y - src_y);
1125 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1129 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1135 void DrawGraphicShiftedThruMask(int x,int y, int dx,int dy, int graphic,
1136 int frame, int cut_mode)
1138 DrawGraphicShifted(x,y, dx,dy, graphic, frame, cut_mode, USE_MASKING);
1141 inline static int getFramePosition(int x, int y)
1143 int frame_pos = -1; /* default: global synchronization */
1145 int element = Feld[x][y];
1147 if (element == EL_QUICKSAND_FULL ||
1148 element == EL_MAGIC_WALL_FULL ||
1149 element == EL_BD_MAGIC_WALL_FULL)
1151 else if (IS_MOVING(x, y) || CAN_MOVE(element) || CAN_FALL(element))
1152 frame_pos = ABS(MovPos[x][y]) / (TILEX / 8);
1155 frame_pos = ABS(MovPos[x][y]) / (TILEX / 8);
1157 frame_pos = GfxFrame[x][y];
1164 inline static int getGfxAction(int x, int y)
1166 int gfx_action = ACTION_DEFAULT;
1169 if (GfxAction[x][y] != ACTION_DEFAULT)
1170 gfx_action = GfxAction[x][y];
1171 else if (IS_MOVING(x, y))
1172 gfx_action = ACTION_MOVING;
1174 gfx_action = GfxAction[x][y];
1179 printf("getGfxAction: THIS SHOULD NEVER HAPPEN: GfxAction[%d][%d] == %d\n",
1186 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
1187 int cut_mode, int mask_mode)
1189 int ux = LEVELX(x), uy = LEVELY(y);
1193 if (IN_LEV_FIELD(ux, uy))
1195 int move_dir = MovDir[ux][uy];
1196 int move_pos = getFramePosition(ux, uy);
1197 int gfx_action = getGfxAction(ux, uy);
1199 SetRandomAnimationValue(ux, uy);
1201 graphic = el_dir_act2img(element, move_dir, gfx_action);
1202 frame = getGraphicAnimationFrame(graphic, move_pos);
1206 graphic = el2img(element);
1207 frame = getGraphicAnimationFrame(graphic, 0);
1210 if (element == EL_WALL_GROWING)
1212 boolean left_stopped = FALSE, right_stopped = FALSE;
1214 if (!IN_LEV_FIELD(ux - 1, uy) || IS_MAUER(Feld[ux - 1][uy]))
1215 left_stopped = TRUE;
1216 if (!IN_LEV_FIELD(ux + 1, uy) || IS_MAUER(Feld[ux + 1][uy]))
1217 right_stopped = TRUE;
1219 if (left_stopped && right_stopped)
1221 else if (left_stopped)
1223 graphic = IMG_WALL_GROWING_ACTIVE_RIGHT;
1224 frame = graphic_info[graphic].anim_frames - 1;
1226 else if (right_stopped)
1228 graphic = IMG_WALL_GROWING_ACTIVE_LEFT;
1229 frame = graphic_info[graphic].anim_frames - 1;
1232 else if (IS_AMOEBOID(element) || element == EL_AMOEBA_DRIPPING)
1234 graphic = (element == EL_BD_AMOEBA ? IMG_BD_AMOEBA_PART1 :
1235 element == EL_AMOEBA_WET ? IMG_AMOEBA_WET_PART1 :
1236 element == EL_AMOEBA_DRY ? IMG_AMOEBA_DRY_PART1 :
1237 element == EL_AMOEBA_FULL ? IMG_AMOEBA_FULL_PART1 :
1238 IMG_AMOEBA_DEAD_PART1);
1240 graphic += (x + 2 * y + 4) % 4;
1244 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, mask_mode);
1245 else if (mask_mode == USE_MASKING)
1246 DrawGraphicThruMask(x, y, graphic, frame);
1248 DrawGraphic(x, y, graphic, frame);
1251 void DrawLevelElementExt(int x, int y, int dx, int dy, int element,
1252 int cut_mode, int mask_mode)
1254 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1255 DrawScreenElementExt(SCREENX(x), SCREENY(y), dx, dy, element,
1256 cut_mode, mask_mode);
1259 void DrawScreenElementShifted(int x, int y, int dx, int dy, int element,
1262 DrawScreenElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1265 void DrawLevelElementShifted(int x, int y, int dx, int dy, int element,
1268 DrawLevelElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1272 void DrawOldScreenElementThruMask(int x, int y, int element)
1274 DrawOldScreenElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1277 void DrawScreenElementThruMask(int x, int y, int element)
1279 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1283 void DrawLevelElementThruMask(int x, int y, int element)
1285 DrawLevelElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1288 void DrawLevelFieldThruMask(int x, int y)
1290 DrawLevelElementExt(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
1293 void DrawCrumbledSand(int x, int y)
1297 int i, width, height, cx,cy;
1298 int ux = LEVELX(x), uy = LEVELY(y);
1299 int element, graphic;
1301 static int xy[4][2] =
1309 if (!IN_LEV_FIELD(ux, uy))
1312 element = Feld[ux][uy];
1314 if (element == EL_SAND ||
1315 element == EL_LANDMINE ||
1316 element == EL_TRAP ||
1317 element == EL_TRAP_ACTIVE)
1319 if (!IN_SCR_FIELD(x, y))
1322 graphic = IMG_SAND_CRUMBLED;
1324 src_bitmap = graphic_info[graphic].bitmap;
1325 src_x = graphic_info[graphic].src_x;
1326 src_y = graphic_info[graphic].src_y;
1332 uxx = ux + xy[i][0];
1333 uyy = uy + xy[i][1];
1334 if (!IN_LEV_FIELD(uxx, uyy))
1335 element = EL_STEELWALL;
1337 element = Feld[uxx][uyy];
1339 if (element == EL_SAND ||
1340 element == EL_LANDMINE ||
1341 element == EL_TRAP ||
1342 element == EL_TRAP_ACTIVE)
1345 if (i == 1 || i == 2)
1349 cx = (i == 2 ? TILEX - snip : 0);
1357 cy = (i == 3 ? TILEY - snip : 0);
1360 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1361 width, height, FX + x * TILEX + cx, FY + y * TILEY + cy);
1364 MarkTileDirty(x, y);
1368 graphic = IMG_SAND_CRUMBLED;
1370 src_bitmap = graphic_info[graphic].bitmap;
1371 src_x = graphic_info[graphic].src_x;
1372 src_y = graphic_info[graphic].src_y;
1376 int xx, yy, uxx, uyy;
1380 uxx = ux + xy[i][0];
1381 uyy = uy + xy[i][1];
1383 if (!IN_LEV_FIELD(uxx, uyy) ||
1384 (Feld[uxx][uyy] != EL_SAND &&
1385 Feld[uxx][uyy] != EL_LANDMINE &&
1386 Feld[uxx][uyy] != EL_TRAP &&
1387 Feld[uxx][uyy] != EL_TRAP_ACTIVE) ||
1388 !IN_SCR_FIELD(xx, yy))
1391 if (i == 1 || i == 2)
1395 cx = (i == 1 ? TILEX - snip : 0);
1403 cy = (i==0 ? TILEY-snip : 0);
1406 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1407 width, height, FX + xx * TILEX + cx, FY + yy * TILEY + cy);
1409 MarkTileDirty(xx, yy);
1414 void DrawScreenElement(int x, int y, int element)
1416 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
1417 DrawCrumbledSand(x, y);
1420 void DrawLevelElement(int x, int y, int element)
1422 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1423 DrawScreenElement(SCREENX(x), SCREENY(y), element);
1426 void DrawScreenField(int x, int y)
1428 int ux = LEVELX(x), uy = LEVELY(y);
1429 int element, content;
1431 if (!IN_LEV_FIELD(ux, uy))
1433 if (ux < -1 || ux > lev_fieldx || uy < -1 || uy > lev_fieldy)
1436 element = BorderElement;
1438 DrawScreenElement(x, y, element);
1442 element = Feld[ux][uy];
1443 content = Store[ux][uy];
1445 if (IS_MOVING(ux, uy))
1447 int horiz_move = (MovDir[ux][uy] == MV_LEFT || MovDir[ux][uy] == MV_RIGHT);
1448 boolean cut_mode = NO_CUTTING;
1450 if (element == EL_QUICKSAND_EMPTYING ||
1451 element == EL_MAGIC_WALL_EMPTYING ||
1452 element == EL_BD_MAGIC_WALL_EMPTYING ||
1453 element == EL_AMOEBA_DRIPPING)
1454 cut_mode = CUT_ABOVE;
1455 else if (element == EL_QUICKSAND_FILLING ||
1456 element == EL_MAGIC_WALL_FILLING ||
1457 element == EL_BD_MAGIC_WALL_FILLING)
1458 cut_mode = CUT_BELOW;
1460 if (cut_mode == CUT_ABOVE)
1461 DrawScreenElementShifted(x, y, 0, 0, element, NO_CUTTING);
1463 DrawScreenElement(x, y, EL_EMPTY);
1466 DrawScreenElementShifted(x, y, MovPos[ux][uy], 0, element, NO_CUTTING);
1467 else if (cut_mode == NO_CUTTING)
1468 DrawScreenElementShifted(x, y, 0, MovPos[ux][uy], element, cut_mode);
1470 DrawScreenElementShifted(x, y, 0, MovPos[ux][uy], content, cut_mode);
1472 if (content == EL_ACID)
1473 DrawLevelElementThruMask(ux, uy + 1, EL_ACID);
1475 else if (IS_BLOCKED(ux, uy))
1480 boolean cut_mode = NO_CUTTING;
1481 int element_old, content_old;
1483 Blocked2Moving(ux, uy, &oldx, &oldy);
1486 horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
1487 MovDir[oldx][oldy] == MV_RIGHT);
1489 element_old = Feld[oldx][oldy];
1490 content_old = Store[oldx][oldy];
1492 if (element_old == EL_QUICKSAND_EMPTYING ||
1493 element_old == EL_MAGIC_WALL_EMPTYING ||
1494 element_old == EL_BD_MAGIC_WALL_EMPTYING ||
1495 element_old == EL_AMOEBA_DRIPPING)
1496 cut_mode = CUT_ABOVE;
1498 DrawScreenElement(x, y, EL_EMPTY);
1501 DrawScreenElementShifted(sx, sy, MovPos[oldx][oldy], 0, element_old,
1503 else if (cut_mode == NO_CUTTING)
1504 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], element_old,
1507 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], content_old,
1510 else if (IS_DRAWABLE(element))
1511 DrawScreenElement(x, y, element);
1513 DrawScreenElement(x, y, EL_EMPTY);
1516 void DrawLevelField(int x, int y)
1518 if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1519 DrawScreenField(SCREENX(x), SCREENY(y));
1520 else if (IS_MOVING(x, y))
1524 Moving2Blocked(x, y, &newx, &newy);
1525 if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
1526 DrawScreenField(SCREENX(newx), SCREENY(newy));
1528 else if (IS_BLOCKED(x, y))
1532 Blocked2Moving(x, y, &oldx, &oldy);
1533 if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
1534 DrawScreenField(SCREENX(oldx), SCREENY(oldy));
1538 void DrawMiniElement(int x, int y, int element)
1542 graphic = el2img(element);
1543 DrawMiniGraphic(x, y, graphic);
1546 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
1548 int x = sx + scroll_x, y = sy + scroll_y;
1550 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
1551 DrawMiniElement(sx, sy, EL_EMPTY);
1552 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
1553 DrawMiniElement(sx, sy, Feld[x][y]);
1556 int steel_type, steel_position;
1559 { IMG_STEELWALL_TOPLEFT, IMG_INVISIBLE_STEELWALL_TOPLEFT },
1560 { IMG_STEELWALL_TOPRIGHT, IMG_INVISIBLE_STEELWALL_TOPRIGHT },
1561 { IMG_STEELWALL_BOTTOMLEFT, IMG_INVISIBLE_STEELWALL_BOTTOMLEFT },
1562 { IMG_STEELWALL_BOTTOMRIGHT, IMG_INVISIBLE_STEELWALL_BOTTOMRIGHT },
1563 { IMG_STEELWALL_VERTICAL, IMG_INVISIBLE_STEELWALL_VERTICAL },
1564 { IMG_STEELWALL_HORIZONTAL, IMG_INVISIBLE_STEELWALL_HORIZONTAL }
1567 steel_type = (BorderElement == EL_STEELWALL ? 0 : 1);
1568 steel_position = (x == -1 && y == -1 ? 0 :
1569 x == lev_fieldx && y == -1 ? 1 :
1570 x == -1 && y == lev_fieldy ? 2 :
1571 x == lev_fieldx && y == lev_fieldy ? 3 :
1572 x == -1 || x == lev_fieldx ? 4 :
1573 y == -1 || y == lev_fieldy ? 5 : -1);
1575 if (steel_position != -1)
1576 DrawMiniGraphic(sx, sy, border[steel_position][steel_type]);
1580 void getMicroGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
1582 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
1583 int mini_startx = src_bitmap->width * 3 / 4;
1584 int mini_starty = src_bitmap->height * 2 / 3;
1585 int src_x = mini_startx + graphic_info[graphic].src_x / 8;
1586 int src_y = mini_starty + graphic_info[graphic].src_y / 8;
1588 if (src_x + MICRO_TILEX > src_bitmap->width ||
1589 src_y + MICRO_TILEY > src_bitmap->height)
1591 /* graphic of desired size seems not to be contained in this image;
1592 dirty workaround: get it from the middle of the normal sized image */
1594 getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
1595 src_x += (TILEX / 2 - MICRO_TILEX / 2);
1596 src_y += (TILEY / 2 - MICRO_TILEY / 2);
1599 *bitmap = src_bitmap;
1604 void DrawMicroElement(int xpos, int ypos, int element)
1608 int graphic = el2img(element);
1610 getMicroGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
1611 BlitBitmap(src_bitmap, drawto, src_x, src_y, MICRO_TILEX, MICRO_TILEY,
1619 SetDrawBackgroundMask(REDRAW_NONE);
1622 for(x=BX1; x<=BX2; x++)
1623 for(y=BY1; y<=BY2; y++)
1624 DrawScreenField(x, y);
1626 redraw_mask |= REDRAW_FIELD;
1629 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
1633 for(x=0; x<size_x; x++)
1634 for(y=0; y<size_y; y++)
1635 DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
1637 redraw_mask |= REDRAW_FIELD;
1640 static void DrawMicroLevelExt(int xpos, int ypos, int from_x, int from_y)
1644 DrawBackground(xpos, ypos, MICROLEV_XSIZE, MICROLEV_YSIZE);
1646 if (lev_fieldx < STD_LEV_FIELDX)
1647 xpos += (STD_LEV_FIELDX - lev_fieldx) / 2 * MICRO_TILEX;
1648 if (lev_fieldy < STD_LEV_FIELDY)
1649 ypos += (STD_LEV_FIELDY - lev_fieldy) / 2 * MICRO_TILEY;
1651 xpos += MICRO_TILEX;
1652 ypos += MICRO_TILEY;
1654 for(x=-1; x<=STD_LEV_FIELDX; x++)
1656 for(y=-1; y<=STD_LEV_FIELDY; y++)
1658 int lx = from_x + x, ly = from_y + y;
1660 if (lx >= 0 && lx < lev_fieldx && ly >= 0 && ly < lev_fieldy)
1661 DrawMicroElement(xpos + x * MICRO_TILEX, ypos + y * MICRO_TILEY,
1663 else if (lx >= -1 && lx < lev_fieldx+1 && ly >= -1 && ly < lev_fieldy+1
1664 && BorderElement != EL_EMPTY)
1665 DrawMicroElement(xpos + x * MICRO_TILEX, ypos + y * MICRO_TILEY,
1670 redraw_mask |= REDRAW_MICROLEVEL;
1673 #define MICROLABEL_EMPTY 0
1674 #define MICROLABEL_LEVEL_NAME 1
1675 #define MICROLABEL_CREATED_BY 2
1676 #define MICROLABEL_LEVEL_AUTHOR 3
1677 #define MICROLABEL_IMPORTED_FROM 4
1678 #define MICROLABEL_LEVEL_IMPORT_INFO 5
1680 #define MAX_MICROLABEL_SIZE (SXSIZE / FONT4_XSIZE)
1682 static void DrawMicroLevelLabelExt(int mode)
1684 char label_text[MAX_MICROLABEL_SIZE + 1];
1686 DrawBackground(SX, MICROLABEL_YPOS, SXSIZE, FONT4_YSIZE);
1688 strncpy(label_text, (mode == MICROLABEL_LEVEL_NAME ? level.name :
1689 mode == MICROLABEL_CREATED_BY ? "created by" :
1690 mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
1691 mode == MICROLABEL_IMPORTED_FROM ? "imported from" :
1692 mode == MICROLABEL_LEVEL_IMPORT_INFO ?
1693 leveldir_current->imported_from : ""),
1694 MAX_MICROLABEL_SIZE);
1695 label_text[MAX_MICROLABEL_SIZE] = '\0';
1697 if (strlen(label_text) > 0)
1699 int lxpos = SX + (SXSIZE - strlen(label_text) * FONT4_XSIZE) / 2;
1700 int lypos = MICROLABEL_YPOS;
1702 DrawText(lxpos, lypos, label_text, FS_SMALL, FC_SPECIAL2);
1705 redraw_mask |= REDRAW_MICROLEVEL;
1708 void DrawMicroLevel(int xpos, int ypos, boolean restart)
1710 static unsigned long scroll_delay = 0;
1711 static unsigned long label_delay = 0;
1712 static int from_x, from_y, scroll_direction;
1713 static int label_state, label_counter;
1717 from_x = from_y = 0;
1718 scroll_direction = MV_RIGHT;
1722 DrawMicroLevelExt(xpos, ypos, from_x, from_y);
1723 DrawMicroLevelLabelExt(label_state);
1725 /* initialize delay counters */
1726 DelayReached(&scroll_delay, 0);
1727 DelayReached(&label_delay, 0);
1732 /* scroll micro level, if needed */
1733 if ((lev_fieldx > STD_LEV_FIELDX || lev_fieldy > STD_LEV_FIELDY) &&
1734 DelayReached(&scroll_delay, MICROLEVEL_SCROLL_DELAY))
1736 switch (scroll_direction)
1742 scroll_direction = MV_UP;
1746 if (from_x < lev_fieldx - STD_LEV_FIELDX)
1749 scroll_direction = MV_DOWN;
1756 scroll_direction = MV_RIGHT;
1760 if (from_y < lev_fieldy - STD_LEV_FIELDY)
1763 scroll_direction = MV_LEFT;
1770 DrawMicroLevelExt(xpos, ypos, from_x, from_y);
1773 /* redraw micro level label, if needed */
1774 if (strcmp(level.name, NAMELESS_LEVEL_NAME) != 0 &&
1775 strcmp(level.author, ANONYMOUS_NAME) != 0 &&
1776 strcmp(level.author, leveldir_current->name) != 0 &&
1777 DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
1779 int max_label_counter = 23;
1781 if (leveldir_current->imported_from != NULL)
1782 max_label_counter += 14;
1784 label_counter = (label_counter + 1) % max_label_counter;
1785 label_state = (label_counter >= 0 && label_counter <= 7 ?
1786 MICROLABEL_LEVEL_NAME :
1787 label_counter >= 9 && label_counter <= 12 ?
1788 MICROLABEL_CREATED_BY :
1789 label_counter >= 14 && label_counter <= 21 ?
1790 MICROLABEL_LEVEL_AUTHOR :
1791 label_counter >= 23 && label_counter <= 26 ?
1792 MICROLABEL_IMPORTED_FROM :
1793 label_counter >= 28 && label_counter <= 35 ?
1794 MICROLABEL_LEVEL_IMPORT_INFO : MICROLABEL_EMPTY);
1795 DrawMicroLevelLabelExt(label_state);
1799 int REQ_in_range(int x, int y)
1801 if (y > DY+249 && y < DY+278)
1803 if (x > DX+1 && x < DX+48)
1805 else if (x > DX+51 && x < DX+98)
1811 #define MAX_REQUEST_LINES 13
1812 #define MAX_REQUEST_LINE_LEN 7
1814 boolean Request(char *text, unsigned int req_state)
1816 int mx, my, ty, result = -1;
1817 unsigned int old_door_state;
1819 #if defined(PLATFORM_UNIX)
1820 /* pause network game while waiting for request to answer */
1821 if (options.network &&
1822 game_status == PLAYING &&
1823 req_state & REQUEST_WAIT_FOR)
1824 SendToServer_PausePlaying();
1827 old_door_state = GetDoorState();
1831 CloseDoor(DOOR_CLOSE_1);
1833 /* save old door content */
1834 BlitBitmap(bitmap_db_door, bitmap_db_door,
1835 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
1836 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
1838 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
1840 /* clear door drawing field */
1841 DrawBackground(DX, DY, DXSIZE, DYSIZE);
1843 /* write text for request */
1844 for(ty=0; ty < MAX_REQUEST_LINES; ty++)
1846 char text_line[MAX_REQUEST_LINE_LEN + 1];
1852 for(tl=0,tx=0; tx < MAX_REQUEST_LINE_LEN; tl++,tx++)
1855 if (!tc || tc == ' ')
1866 strncpy(text_line, text, tl);
1869 DrawText(DX + 50 - (tl * 14)/2, DY + 8 + ty * 16,
1870 text_line, FS_SMALL, FC_YELLOW);
1872 text += tl + (tc == ' ' ? 1 : 0);
1875 if (req_state & REQ_ASK)
1877 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
1878 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
1880 else if (req_state & REQ_CONFIRM)
1882 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
1884 else if (req_state & REQ_PLAYER)
1886 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
1887 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
1888 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
1889 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
1892 /* copy request gadgets to door backbuffer */
1893 BlitBitmap(drawto, bitmap_db_door,
1894 DX, DY, DXSIZE, DYSIZE,
1895 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
1897 OpenDoor(DOOR_OPEN_1);
1903 if (!(req_state & REQUEST_WAIT_FOR))
1905 SetDrawBackgroundMask(REDRAW_FIELD);
1910 if (game_status != MAINMENU)
1913 button_status = MB_RELEASED;
1915 request_gadget_id = -1;
1917 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
1929 case EVENT_BUTTONPRESS:
1930 case EVENT_BUTTONRELEASE:
1931 case EVENT_MOTIONNOTIFY:
1933 if (event.type == EVENT_MOTIONNOTIFY)
1935 if (!PointerInWindow(window))
1936 continue; /* window and pointer are on different screens */
1941 motion_status = TRUE;
1942 mx = ((MotionEvent *) &event)->x;
1943 my = ((MotionEvent *) &event)->y;
1947 motion_status = FALSE;
1948 mx = ((ButtonEvent *) &event)->x;
1949 my = ((ButtonEvent *) &event)->y;
1950 if (event.type == EVENT_BUTTONPRESS)
1951 button_status = ((ButtonEvent *) &event)->button;
1953 button_status = MB_RELEASED;
1956 /* this sets 'request_gadget_id' */
1957 HandleGadgets(mx, my, button_status);
1959 switch(request_gadget_id)
1961 case TOOL_CTRL_ID_YES:
1964 case TOOL_CTRL_ID_NO:
1967 case TOOL_CTRL_ID_CONFIRM:
1968 result = TRUE | FALSE;
1971 case TOOL_CTRL_ID_PLAYER_1:
1974 case TOOL_CTRL_ID_PLAYER_2:
1977 case TOOL_CTRL_ID_PLAYER_3:
1980 case TOOL_CTRL_ID_PLAYER_4:
1991 case EVENT_KEYPRESS:
1992 switch(GetEventKey((KeyEvent *)&event, TRUE))
2005 if (req_state & REQ_PLAYER)
2009 case EVENT_KEYRELEASE:
2010 ClearPlayerAction();
2014 HandleOtherEvents(&event);
2018 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
2020 int joy = AnyJoystick();
2022 if (joy & JOY_BUTTON_1)
2024 else if (joy & JOY_BUTTON_2)
2030 /* don't eat all CPU time */
2034 if (game_status != MAINMENU)
2039 if (!(req_state & REQ_STAY_OPEN))
2041 CloseDoor(DOOR_CLOSE_1);
2043 if (!(req_state & REQ_STAY_CLOSED) && (old_door_state & DOOR_OPEN_1))
2045 BlitBitmap(bitmap_db_door, bitmap_db_door,
2046 DOOR_GFX_PAGEX2,DOOR_GFX_PAGEY1, DXSIZE,DYSIZE,
2047 DOOR_GFX_PAGEX1,DOOR_GFX_PAGEY1);
2048 OpenDoor(DOOR_OPEN_1);
2054 SetDrawBackgroundMask(REDRAW_FIELD);
2056 #if defined(PLATFORM_UNIX)
2057 /* continue network game after request */
2058 if (options.network &&
2059 game_status == PLAYING &&
2060 req_state & REQUEST_WAIT_FOR)
2061 SendToServer_ContinuePlaying();
2067 unsigned int OpenDoor(unsigned int door_state)
2069 unsigned int new_door_state;
2071 if (door_state & DOOR_COPY_BACK)
2073 BlitBitmap(bitmap_db_door, bitmap_db_door,
2074 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE + VYSIZE,
2075 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2076 door_state &= ~DOOR_COPY_BACK;
2079 new_door_state = MoveDoor(door_state);
2081 return(new_door_state);
2084 unsigned int CloseDoor(unsigned int door_state)
2086 unsigned int new_door_state;
2088 BlitBitmap(backbuffer, bitmap_db_door,
2089 DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2090 BlitBitmap(backbuffer, bitmap_db_door,
2091 VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
2093 new_door_state = MoveDoor(door_state);
2095 return(new_door_state);
2098 unsigned int GetDoorState()
2100 return MoveDoor(DOOR_GET_STATE);
2103 unsigned int SetDoorState(unsigned int door_state)
2105 return MoveDoor(door_state | DOOR_SET_STATE);
2108 unsigned int MoveDoor(unsigned int door_state)
2110 static int door1 = DOOR_OPEN_1;
2111 static int door2 = DOOR_CLOSE_2;
2112 static unsigned long door_delay = 0;
2113 int x, start, stepsize = 2;
2114 unsigned long door_delay_value = stepsize * 5;
2116 if (door_state == DOOR_GET_STATE)
2117 return(door1 | door2);
2119 if (door_state & DOOR_SET_STATE)
2121 if (door_state & DOOR_ACTION_1)
2122 door1 = door_state & DOOR_ACTION_1;
2123 if (door_state & DOOR_ACTION_2)
2124 door2 = door_state & DOOR_ACTION_2;
2126 return(door1 | door2);
2129 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
2130 door_state &= ~DOOR_OPEN_1;
2131 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
2132 door_state &= ~DOOR_CLOSE_1;
2133 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
2134 door_state &= ~DOOR_OPEN_2;
2135 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
2136 door_state &= ~DOOR_CLOSE_2;
2138 if (setup.quick_doors)
2141 door_delay_value = 0;
2143 StopSound(SND_MENU_DOOR_OPENING);
2144 StopSound(SND_MENU_DOOR_CLOSING);
2147 if (global.autoplay_leveldir)
2149 door_state |= DOOR_NO_DELAY;
2150 door_state &= ~DOOR_CLOSE_ALL;
2153 if (door_state & DOOR_ACTION)
2155 if (!(door_state & DOOR_NO_DELAY))
2157 /* opening door sound has priority over simultaneously closing door */
2158 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
2159 PlaySoundStereo(SND_MENU_DOOR_OPENING, SOUND_MAX_RIGHT);
2160 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
2161 PlaySoundStereo(SND_MENU_DOOR_CLOSING, SOUND_MAX_RIGHT);
2164 start = ((door_state & DOOR_NO_DELAY) ? DXSIZE : 0);
2166 for(x=start; x<=DXSIZE; x+=stepsize)
2168 Bitmap *bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
2169 GC gc = bitmap->stored_clip_gc;
2171 if (!(door_state & DOOR_NO_DELAY))
2172 WaitUntilDelayReached(&door_delay, door_delay_value);
2174 if (door_state & DOOR_ACTION_1)
2176 int i = (door_state & DOOR_OPEN_1 ? DXSIZE-x : x);
2177 int j = (DXSIZE - i) / 3;
2179 BlitBitmap(bitmap_db_door, drawto,
2180 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + i/2,
2181 DXSIZE,DYSIZE - i/2, DX, DY);
2183 ClearRectangle(drawto, DX, DY + DYSIZE - i/2, DXSIZE,i/2);
2185 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2186 BlitBitmapMasked(bitmap, drawto,
2187 DXSIZE, DOOR_GFX_PAGEY1, i, 77,
2188 DX + DXSIZE - i, DY + j);
2189 BlitBitmapMasked(bitmap, drawto,
2190 DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63,
2191 DX + DXSIZE - i, DY + 140 + j);
2192 SetClipOrigin(bitmap, gc, DX - DXSIZE + i, DY - (DOOR_GFX_PAGEY1 + j));
2193 BlitBitmapMasked(bitmap, drawto,
2194 DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j,
2196 BlitBitmapMasked(bitmap, drawto,
2197 DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63,
2200 BlitBitmapMasked(bitmap, drawto,
2201 DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
2203 BlitBitmapMasked(bitmap, drawto,
2204 DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
2206 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2207 BlitBitmapMasked(bitmap, drawto,
2208 DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
2209 DX + DXSIZE - i, DY + 77 + j);
2210 BlitBitmapMasked(bitmap, drawto,
2211 DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
2212 DX + DXSIZE - i, DY + 203 + j);
2214 redraw_mask |= REDRAW_DOOR_1;
2217 if (door_state & DOOR_ACTION_2)
2219 int i = (door_state & DOOR_OPEN_2 ? VXSIZE - x : x);
2220 int j = (VXSIZE - i) / 3;
2222 BlitBitmap(bitmap_db_door, drawto,
2223 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + i/2,
2224 VXSIZE, VYSIZE - i/2, VX, VY);
2226 ClearRectangle(drawto, VX, VY + VYSIZE-i/2, VXSIZE, i/2);
2228 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2229 BlitBitmapMasked(bitmap, drawto,
2230 VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2,
2231 VX + VXSIZE-i, VY+j);
2232 SetClipOrigin(bitmap, gc,
2233 VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
2234 BlitBitmapMasked(bitmap, drawto,
2235 VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j,
2238 BlitBitmapMasked(bitmap, drawto,
2239 VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2,
2240 i, VYSIZE / 2, VX, VY + VYSIZE / 2 - j);
2241 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2242 BlitBitmapMasked(bitmap, drawto,
2243 VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2,
2245 VX + VXSIZE - i, VY + VYSIZE / 2 + j);
2247 redraw_mask |= REDRAW_DOOR_2;
2252 if (game_status == MAINMENU)
2257 if (setup.quick_doors)
2259 StopSound(SND_MENU_DOOR_OPENING);
2260 StopSound(SND_MENU_DOOR_CLOSING);
2263 if (door_state & DOOR_ACTION_1)
2264 door1 = door_state & DOOR_ACTION_1;
2265 if (door_state & DOOR_ACTION_2)
2266 door2 = door_state & DOOR_ACTION_2;
2268 return (door1 | door2);
2271 void DrawSpecialEditorDoor()
2273 /* draw bigger toolbox window */
2274 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
2275 DOOR_GFX_PAGEX7, 0, EXSIZE + 8, 8,
2277 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
2278 EX - 4, VY - 4, EXSIZE + 8, EYSIZE - VYSIZE + 4,
2281 redraw_mask |= REDRAW_ALL;
2284 void UndrawSpecialEditorDoor()
2286 /* draw normal tape recorder window */
2287 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
2288 EX - 4, EY - 12, EXSIZE + 8, EYSIZE - VYSIZE + 12,
2291 redraw_mask |= REDRAW_ALL;
2295 int ReadPixel(DrawBuffer *bitmap, int x, int y)
2297 XImage *pixel_image;
2298 unsigned long pixel_value;
2300 pixel_image = XGetImage(display, bitmap->drawable,
2301 x, y, 1, 1, AllPlanes, ZPixmap);
2302 pixel_value = XGetPixel(pixel_image, 0, 0);
2304 XDestroyImage(pixel_image);
2310 /* ---------- new tool button stuff ---------------------------------------- */
2312 /* graphic position values for tool buttons */
2313 #define TOOL_BUTTON_YES_XPOS 2
2314 #define TOOL_BUTTON_YES_YPOS 250
2315 #define TOOL_BUTTON_YES_GFX_YPOS 0
2316 #define TOOL_BUTTON_YES_XSIZE 46
2317 #define TOOL_BUTTON_YES_YSIZE 28
2318 #define TOOL_BUTTON_NO_XPOS 52
2319 #define TOOL_BUTTON_NO_YPOS TOOL_BUTTON_YES_YPOS
2320 #define TOOL_BUTTON_NO_GFX_YPOS TOOL_BUTTON_YES_GFX_YPOS
2321 #define TOOL_BUTTON_NO_XSIZE TOOL_BUTTON_YES_XSIZE
2322 #define TOOL_BUTTON_NO_YSIZE TOOL_BUTTON_YES_YSIZE
2323 #define TOOL_BUTTON_CONFIRM_XPOS TOOL_BUTTON_YES_XPOS
2324 #define TOOL_BUTTON_CONFIRM_YPOS TOOL_BUTTON_YES_YPOS
2325 #define TOOL_BUTTON_CONFIRM_GFX_YPOS 30
2326 #define TOOL_BUTTON_CONFIRM_XSIZE 96
2327 #define TOOL_BUTTON_CONFIRM_YSIZE TOOL_BUTTON_YES_YSIZE
2328 #define TOOL_BUTTON_PLAYER_XSIZE 30
2329 #define TOOL_BUTTON_PLAYER_YSIZE 30
2330 #define TOOL_BUTTON_PLAYER_GFX_XPOS 5
2331 #define TOOL_BUTTON_PLAYER_GFX_YPOS 185
2332 #define TOOL_BUTTON_PLAYER_XPOS (5 + TOOL_BUTTON_PLAYER_XSIZE / 2)
2333 #define TOOL_BUTTON_PLAYER_YPOS (215 - TOOL_BUTTON_PLAYER_YSIZE / 2)
2334 #define TOOL_BUTTON_PLAYER1_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2335 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2336 #define TOOL_BUTTON_PLAYER2_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2337 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2338 #define TOOL_BUTTON_PLAYER3_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2339 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2340 #define TOOL_BUTTON_PLAYER4_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2341 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2342 #define TOOL_BUTTON_PLAYER1_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2343 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2344 #define TOOL_BUTTON_PLAYER2_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2345 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2346 #define TOOL_BUTTON_PLAYER3_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2347 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2348 #define TOOL_BUTTON_PLAYER4_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2349 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2358 } toolbutton_info[NUM_TOOL_BUTTONS] =
2361 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_GFX_YPOS,
2362 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_YPOS,
2363 TOOL_BUTTON_YES_XSIZE, TOOL_BUTTON_YES_YSIZE,
2368 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_GFX_YPOS,
2369 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_YPOS,
2370 TOOL_BUTTON_NO_XSIZE, TOOL_BUTTON_NO_YSIZE,
2375 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_GFX_YPOS,
2376 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_YPOS,
2377 TOOL_BUTTON_CONFIRM_XSIZE, TOOL_BUTTON_CONFIRM_YSIZE,
2378 TOOL_CTRL_ID_CONFIRM,
2382 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2383 TOOL_BUTTON_PLAYER1_XPOS, TOOL_BUTTON_PLAYER1_YPOS,
2384 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2385 TOOL_CTRL_ID_PLAYER_1,
2389 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2390 TOOL_BUTTON_PLAYER2_XPOS, TOOL_BUTTON_PLAYER2_YPOS,
2391 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2392 TOOL_CTRL_ID_PLAYER_2,
2396 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2397 TOOL_BUTTON_PLAYER3_XPOS, TOOL_BUTTON_PLAYER3_YPOS,
2398 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2399 TOOL_CTRL_ID_PLAYER_3,
2403 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2404 TOOL_BUTTON_PLAYER4_XPOS, TOOL_BUTTON_PLAYER4_YPOS,
2405 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2406 TOOL_CTRL_ID_PLAYER_4,
2411 void CreateToolButtons()
2415 for (i=0; i<NUM_TOOL_BUTTONS; i++)
2417 Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
2418 Bitmap *deco_bitmap = None;
2419 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
2420 struct GadgetInfo *gi;
2421 unsigned long event_mask;
2422 int gd_xoffset, gd_yoffset;
2423 int gd_x1, gd_x2, gd_y;
2426 event_mask = GD_EVENT_RELEASED;
2428 gd_xoffset = toolbutton_info[i].xpos;
2429 gd_yoffset = toolbutton_info[i].ypos;
2430 gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
2431 gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
2432 gd_y = DOOR_GFX_PAGEY1 + gd_yoffset;
2434 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
2436 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
2438 getMiniGraphicSource(PLAYER_NR_GFX(IMG_PLAYER1, player_nr),
2439 &deco_bitmap, &deco_x, &deco_y);
2440 deco_xpos = (toolbutton_info[i].width - MINI_TILEX) / 2;
2441 deco_ypos = (toolbutton_info[i].height - MINI_TILEY) / 2;
2444 gi = CreateGadget(GDI_CUSTOM_ID, id,
2445 GDI_INFO_TEXT, toolbutton_info[i].infotext,
2446 GDI_X, DX + toolbutton_info[i].x,
2447 GDI_Y, DY + toolbutton_info[i].y,
2448 GDI_WIDTH, toolbutton_info[i].width,
2449 GDI_HEIGHT, toolbutton_info[i].height,
2450 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
2451 GDI_STATE, GD_BUTTON_UNPRESSED,
2452 GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
2453 GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
2454 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
2455 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
2456 GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
2457 GDI_DECORATION_SHIFTING, 1, 1,
2458 GDI_EVENT_MASK, event_mask,
2459 GDI_CALLBACK_ACTION, HandleToolButtons,
2463 Error(ERR_EXIT, "cannot create gadget");
2465 tool_gadget[id] = gi;
2469 void FreeToolButtons()
2473 for (i=0; i<NUM_TOOL_BUTTONS; i++)
2474 FreeGadget(tool_gadget[i]);
2477 static void UnmapToolButtons()
2481 for (i=0; i<NUM_TOOL_BUTTONS; i++)
2482 UnmapGadget(tool_gadget[i]);
2485 static void HandleToolButtons(struct GadgetInfo *gi)
2487 request_gadget_id = gi->custom_id;
2490 int get_next_element(int element)
2494 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
2495 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
2496 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
2497 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
2498 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
2499 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
2500 case EL_AMOEBA_DRIPPING: return EL_AMOEBA_WET;
2502 default: return element;
2506 int el2img(int element)
2508 int graphic = element_info[element].graphic[ACTION_DEFAULT];
2512 Error(ERR_WARN, "element %d -> graphic %d -- probably crashing now...",
2519 int el_dir2img(int element, int direction)
2521 return el_dir_act2img(element, direction, ACTION_DEFAULT);
2524 int el_dir_act2img(int element, int direction, int action)
2529 printf("el_dir_act2img: THIS SHOULD NEVER HAPPEN: element == %d\n",
2537 printf("el_dir_act2img: THIS SHOULD NEVER HAPPEN: action == %d\n",
2544 direction = MV_DIR_BIT(direction);
2546 return element_info[element].direction_graphic[action][direction];