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, getFontHeight(FONT_SPECIAL_GAME),
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, FONT_DEFAULT_SMALL, 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].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].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_INDESTRUCTIBLE(Feld[x][y]))
430 BorderElement = EL_STEELWALL;
432 if (y != 0 && y != lev_fieldy - 1 && x != lev_fieldx - 1)
438 void SetRandomAnimationValue(int x, int y)
440 anim.random_frame = GfxRandom[x][y];
443 inline int getGraphicAnimationFrame(int graphic, int sync_frame)
445 /* animation synchronized with global frame counter, not move position */
446 if (graphic_info[graphic].anim_global_sync || sync_frame < 0)
447 sync_frame = FrameCounter;
449 return getAnimationFrame(graphic_info[graphic].anim_frames,
450 graphic_info[graphic].anim_delay,
451 graphic_info[graphic].anim_mode,
452 graphic_info[graphic].anim_start_frame,
456 inline void DrawGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
457 int graphic, int sync_frame, int mask_mode)
459 int frame = getGraphicAnimationFrame(graphic, sync_frame);
461 if (mask_mode == USE_MASKING)
462 DrawGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
464 DrawGraphicExt(dst_bitmap, x, y, graphic, frame);
467 inline void DrawGraphicAnimation(int x, int y, int graphic)
469 int lx = LEVELX(x), ly = LEVELY(y);
471 if (!IN_SCR_FIELD(x, y))
474 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
475 graphic, GfxFrame[lx][ly], NO_MASKING);
479 void DrawLevelGraphicAnimation(int x, int y, int graphic)
481 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
484 void DrawLevelElementAnimation(int x, int y, int element)
486 DrawGraphicAnimation(SCREENX(x), SCREENY(y), el2img(element));
489 inline void DrawLevelGraphicAnimationIfNeeded(int x, int y, int graphic)
491 int sx = SCREENX(x), sy = SCREENY(y);
493 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
496 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
499 DrawGraphicAnimation(sx, sy, graphic);
502 void DrawLevelElementAnimationIfNeeded(int x, int y, int element)
504 int sx = SCREENX(x), sy = SCREENY(y);
507 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
510 graphic = el_act_dir2img(element, GfxAction[x][y], MovDir[x][y]);
512 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
515 DrawGraphicAnimation(sx, sy, graphic);
518 void DrawAllPlayers()
522 for(i=0; i<MAX_PLAYERS; i++)
523 if (stored_player[i].active)
524 DrawPlayer(&stored_player[i]);
527 void DrawPlayerField(int x, int y)
529 if (!IS_PLAYER(x, y))
532 DrawPlayer(PLAYERINFO(x, y));
535 void DrawPlayer(struct PlayerInfo *player)
537 int jx = player->jx, jy = player->jy;
538 int last_jx = player->last_jx, last_jy = player->last_jy;
539 int next_jx = jx + (jx - last_jx), next_jy = jy + (jy - last_jy);
540 int sx = SCREENX(jx), sy = SCREENY(jy);
541 int sxx = 0, syy = 0;
542 int element = Feld[jx][jy], last_element = Feld[last_jx][last_jy];
545 boolean player_is_moving = (last_jx != jx || last_jy != jy ? TRUE : FALSE);
547 if (!player->active || !IN_SCR_FIELD(SCREENX(last_jx), SCREENY(last_jy)))
551 if (!IN_LEV_FIELD(jx,jy))
553 printf("DrawPlayerField(): x = %d, y = %d\n",jx,jy);
554 printf("DrawPlayerField(): sx = %d, sy = %d\n",sx,sy);
555 printf("DrawPlayerField(): This should never happen!\n");
560 if (element == EL_EXPLOSION)
563 /* draw things in the field the player is leaving, if needed */
565 if (player_is_moving)
567 if (Store[last_jx][last_jy] && IS_DRAWABLE(last_element))
569 DrawLevelElement(last_jx, last_jy, Store[last_jx][last_jy]);
571 if (last_element == EL_DYNAMITE_ACTIVE)
572 DrawDynamite(last_jx, last_jy);
574 DrawLevelFieldThruMask(last_jx, last_jy);
576 else if (last_element == EL_DYNAMITE_ACTIVE)
577 DrawDynamite(last_jx, last_jy);
579 DrawLevelField(last_jx, last_jy);
581 if (player->Pushing && IN_SCR_FIELD(SCREENX(next_jx), SCREENY(next_jy)))
585 if (Feld[next_jx][next_jy] == EL_SOKOBAN_FIELD_FULL)
586 DrawLevelElement(next_jx, next_jy, EL_SOKOBAN_FIELD_EMPTY);
588 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
591 DrawLevelField(next_jx, next_jy);
595 if (!IN_SCR_FIELD(sx, sy))
598 if (setup.direct_draw)
599 SetDrawtoField(DRAW_BUFFERED);
601 /* draw things behind the player, if needed */
604 DrawLevelElement(jx, jy, Store[jx][jy]);
605 else if (!IS_ACTIVE_BOMB(element))
606 DrawLevelField(jx, jy);
608 DrawLevelElement(jx, jy, EL_EMPTY);
610 /* draw player himself */
612 if (player->use_murphy_graphic)
614 static int last_dir = MV_LEFT;
615 int action = (player->programmed_action ? player->programmed_action :
617 boolean action_moving =
619 ((action & (MV_LEFT | MV_RIGHT | MV_UP | MV_DOWN)) &&
620 !(action & ~(MV_LEFT | MV_RIGHT | MV_UP | MV_DOWN))));
622 graphic = IMG_SP_MURPHY;
626 if (player->MovDir == MV_LEFT)
627 graphic = IMG_SP_MURPHY_PUSHING_LEFT;
628 else if (player->MovDir == MV_RIGHT)
629 graphic = IMG_SP_MURPHY_PUSHING_RIGHT;
630 else if (player->MovDir & (MV_UP | MV_DOWN) && last_dir == MV_LEFT)
631 graphic = IMG_SP_MURPHY_PUSHING_LEFT;
632 else if (player->MovDir & (MV_UP | MV_DOWN) && last_dir == MV_RIGHT)
633 graphic = IMG_SP_MURPHY_PUSHING_RIGHT;
635 else if (player->snapped)
637 if (player->MovDir == MV_LEFT)
638 graphic = IMG_SP_MURPHY_SNAPPING_LEFT;
639 else if (player->MovDir == MV_RIGHT)
640 graphic = IMG_SP_MURPHY_SNAPPING_RIGHT;
641 else if (player->MovDir == MV_UP)
642 graphic = IMG_SP_MURPHY_SNAPPING_UP;
643 else if (player->MovDir == MV_DOWN)
644 graphic = IMG_SP_MURPHY_SNAPPING_DOWN;
646 else if (action_moving)
648 if (player->MovDir == MV_LEFT)
649 graphic = IMG_SP_MURPHY_MOVING_LEFT;
650 else if (player->MovDir == MV_RIGHT)
651 graphic = IMG_SP_MURPHY_MOVING_RIGHT;
652 else if (player->MovDir & (MV_UP | MV_DOWN) && last_dir == MV_LEFT)
653 graphic = IMG_SP_MURPHY_MOVING_LEFT;
654 else if (player->MovDir & (MV_UP | MV_DOWN) && last_dir == MV_RIGHT)
655 graphic = IMG_SP_MURPHY_MOVING_RIGHT;
657 graphic = IMG_SP_MURPHY_MOVING_LEFT;
659 frame = getGraphicAnimationFrame(graphic, -1);
662 if (player->MovDir == MV_LEFT || player->MovDir == MV_RIGHT)
663 last_dir = player->MovDir;
667 if (player->MovDir == MV_LEFT)
668 graphic = (player->Pushing ? IMG_PLAYER1_PUSHING_LEFT :
669 player->is_digging ? IMG_PLAYER1_DIGGING_LEFT :
670 player->is_moving ? IMG_PLAYER1_MOVING_LEFT :
671 player->snapped ? IMG_PLAYER1_SNAPPING_LEFT :
673 else if (player->MovDir == MV_RIGHT)
674 graphic = (player->Pushing ? IMG_PLAYER1_PUSHING_RIGHT :
675 player->is_digging ? IMG_PLAYER1_DIGGING_RIGHT :
676 player->is_moving ? IMG_PLAYER1_MOVING_RIGHT :
677 player->snapped ? IMG_PLAYER1_SNAPPING_RIGHT :
679 else if (player->MovDir == MV_UP)
680 graphic = (player->Pushing ? IMG_PLAYER1_PUSHING_UP :
681 player->is_digging ? IMG_PLAYER1_DIGGING_UP :
682 player->is_moving ? IMG_PLAYER1_MOVING_UP :
683 player->snapped ? IMG_PLAYER1_SNAPPING_UP :
685 else /* MV_DOWN || MV_NO_MOVING */
686 graphic = (player->Pushing ? IMG_PLAYER1_PUSHING_DOWN :
687 player->is_digging ? IMG_PLAYER1_DIGGING_DOWN :
688 player->is_moving ? IMG_PLAYER1_MOVING_DOWN :
689 player->snapped ? IMG_PLAYER1_SNAPPING_DOWN :
692 graphic = PLAYER_NR_GFX(graphic, player->index_nr);
695 frame = player->Frame;
697 frame = getGraphicAnimationFrame(graphic, player->Frame);
703 if (player->MovDir == MV_LEFT || player->MovDir == MV_RIGHT)
704 sxx = player->GfxPos;
706 syy = player->GfxPos;
709 if (!setup.soft_scrolling && ScreenMovPos)
714 printf("-> %d\n", player->Frame);
717 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
719 if (SHIELD_ON(player))
721 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
722 IMG_SHIELD_NORMAL_ACTIVE);
723 int frame = getGraphicAnimationFrame(graphic, -1);
725 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
729 if (player->Pushing && player->GfxPos)
731 if (player->Pushing && player_is_moving)
734 int px = SCREENX(next_jx), py = SCREENY(next_jy);
737 (element == EL_SOKOBAN_FIELD_EMPTY ||
738 Feld[next_jx][next_jy] == EL_SOKOBAN_FIELD_FULL))
739 DrawGraphicShiftedThruMask(px, py, sxx, syy, IMG_SOKOBAN_OBJECT, 0,
743 int element = Feld[next_jx][next_jy];
744 int graphic = el2img(element);
749 if ((sxx || syy) && IS_PUSHABLE(element))
751 graphic = el_act_dir2img(element, ACTION_MOVING, player->MovDir);
753 frame = getGraphicAnimationFrame(graphic, player->GfxPos);
755 frame = getGraphicAnimationFrame(graphic, player->Frame);
759 printf("-> %d [%d]\n", player->Frame, player->GfxPos);
764 if (player->MovDir == MV_LEFT)
769 frame = (player->GfxPos / (TILEX / 4));
771 if (player->MovDir == MV_RIGHT)
772 frame = (frame + 4) % 4;
776 DrawGraphicShifted(px, py, sxx, syy, graphic, frame,
777 NO_CUTTING, NO_MASKING);
781 /* draw things in front of player (active dynamite or dynabombs) */
783 if (IS_ACTIVE_BOMB(element))
785 graphic = el2img(element);
788 if (element == EL_DYNAMITE_ACTIVE)
790 if ((frame = (96 - MovDelay[jx][jy]) / 12) > 6)
795 if ((frame = ((96 - MovDelay[jx][jy]) / 6) % 8) > 3)
801 frame = getGraphicAnimationFrame(graphic, 96 - MovDelay[jx][jy]);
803 frame = getGraphicAnimationFrame(graphic, GfxFrame[jx][jy]);
808 if (game.emulation == EMU_SUPAPLEX)
809 DrawGraphic(sx, sy, IMG_SP_DISK_RED, frame);
811 DrawGraphicThruMask(sx, sy, graphic, frame);
814 if (player_is_moving && last_element == EL_EXPLOSION)
816 int stored = Store[last_jx][last_jy];
817 int graphic = (game.emulation != EMU_SUPAPLEX ? IMG_EXPLOSION :
818 stored == EL_SP_INFOTRON ? IMG_SP_EXPLOSION_INFOTRON :
820 int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
821 int phase = ExplodePhase[last_jx][last_jy] - 1;
822 int frame = getGraphicAnimationFrame(graphic, phase - delay);
825 DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy), graphic, frame);
828 /* draw elements that stay over the player */
829 /* handle the field the player is leaving ... */
830 if (player_is_moving && IS_OVER_PLAYER(last_element))
831 DrawLevelField(last_jx, last_jy);
833 /* ... and the field the player is entering */
834 if (IS_OVER_PLAYER(element))
835 DrawLevelField(jx, jy);
837 if (setup.direct_draw)
839 int dest_x = SX + SCREENX(MIN(jx, last_jx)) * TILEX;
840 int dest_y = SY + SCREENY(MIN(jy, last_jy)) * TILEY;
841 int x_size = TILEX * (1 + ABS(jx - last_jx));
842 int y_size = TILEY * (1 + ABS(jy - last_jy));
844 BlitBitmap(drawto_field, window,
845 dest_x, dest_y, x_size, y_size, dest_x, dest_y);
846 SetDrawtoField(DRAW_DIRECT);
849 MarkTileDirty(sx,sy);
852 void getGraphicSource(int graphic, int frame, Bitmap **bitmap, int *x, int *y)
854 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
855 int offset_x = graphic_info[graphic].offset_x;
856 int offset_y = graphic_info[graphic].offset_y;
857 int src_x = graphic_info[graphic].src_x + frame * offset_x;
858 int src_y = graphic_info[graphic].src_y + frame * offset_y;
860 *bitmap = src_bitmap;
865 void DrawGraphic(int x, int y, int graphic, int frame)
868 if (!IN_SCR_FIELD(x, y))
870 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
871 printf("DrawGraphic(): This should never happen!\n");
876 DrawGraphicExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic, frame);
881 void DrawOldGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic)
886 getOldGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
887 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
891 void DrawGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
898 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
900 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
901 int src_x = graphic_info[graphic].src_x;
902 int src_y = graphic_info[graphic].src_y;
903 int offset_x = graphic_info[graphic].offset_x;
904 int offset_y = graphic_info[graphic].offset_y;
906 src_x += frame * offset_x;
907 src_y += frame * offset_y;
910 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
913 void DrawGraphicThruMask(int x, int y, int graphic, int frame)
916 if (!IN_SCR_FIELD(x, y))
918 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
919 printf("DrawGraphicThruMask(): This should never happen!\n");
924 DrawGraphicThruMaskExt(drawto_field, FX + x * TILEX, FY + y *TILEY, graphic,
929 void DrawGraphicThruMaskExt(DrawBuffer *d, int dest_x, int dest_y, int graphic,
937 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
938 drawing_gc = src_bitmap->stored_clip_gc;
940 GC drawing_gc = src_bitmap->stored_clip_gc;
941 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
942 int src_x = graphic_info[graphic].src_x;
943 int src_y = graphic_info[graphic].src_y;
944 int offset_x = graphic_info[graphic].offset_x;
945 int offset_y = graphic_info[graphic].offset_y;
947 src_x += frame * offset_x;
948 src_y += frame * offset_y;
952 SetClipOrigin(src_bitmap, drawing_gc, dest_x - src_x, dest_y - src_y);
953 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX, TILEY, dest_x, dest_y);
956 void DrawMiniGraphic(int x, int y, int graphic)
958 DrawMiniGraphicExt(drawto, SX + x * MINI_TILEX,SY + y * MINI_TILEY, graphic);
959 MarkTileDirty(x / 2, y / 2);
962 void getMiniGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
964 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
966 int mini_starty = src_bitmap->height * 2 / 3;
967 int src_x = mini_startx + graphic_info[graphic].src_x / 2;
968 int src_y = mini_starty + graphic_info[graphic].src_y / 2;
971 /* !!! not needed anymore, because of automatically created mini graphics */
972 if (src_x + MINI_TILEX > src_bitmap->width ||
973 src_y + MINI_TILEY > src_bitmap->height)
975 /* graphic of desired size seems not to be contained in this image;
976 dirty workaround: get it from the middle of the normal sized image */
978 printf("::: using dirty workaround for %d (%d, %d)\n",
979 graphic, src_bitmap->width, src_bitmap->height);
981 getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
982 src_x += (TILEX / 2 - MINI_TILEX / 2);
983 src_y += (TILEY / 2 - MINI_TILEY / 2);
987 *bitmap = src_bitmap;
992 void DrawMiniGraphicExt(DrawBuffer *d, int x, int y, int graphic)
997 getMiniGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
998 BlitBitmap(src_bitmap, d, src_x, src_y, MINI_TILEX, MINI_TILEY, x, y);
1001 void DrawGraphicShifted(int x,int y, int dx,int dy, int graphic, int frame,
1002 int cut_mode, int mask_mode)
1011 int width = TILEX, height = TILEY;
1017 DrawGraphic(x, y, graphic, frame);
1021 if (dx || dy) /* shifted graphic */
1023 if (x < BX1) /* object enters playfield from the left */
1030 else if (x > BX2) /* object enters playfield from the right */
1036 else if (x==BX1 && dx < 0) /* object leaves playfield to the left */
1042 else if (x==BX2 && dx > 0) /* object leaves playfield to the right */
1044 else if (dx) /* general horizontal movement */
1045 MarkTileDirty(x + SIGN(dx), y);
1047 if (y < BY1) /* object enters playfield from the top */
1049 if (cut_mode==CUT_BELOW) /* object completely above top border */
1057 else if (y > BY2) /* object enters playfield from the bottom */
1063 else if (y==BY1 && dy < 0) /* object leaves playfield to the top */
1069 else if (dy > 0 && cut_mode == CUT_ABOVE)
1071 if (y == BY2) /* object completely above bottom border */
1077 MarkTileDirty(x, y + 1);
1078 } /* object leaves playfield to the bottom */
1079 else if (dy > 0 && (y == BY2 || cut_mode == CUT_BELOW))
1081 else if (dy) /* general vertical movement */
1082 MarkTileDirty(x, y + SIGN(dy));
1085 src_bitmap = graphic_info[graphic].bitmap;
1086 src_x = graphic_info[graphic].src_x;
1087 src_y = graphic_info[graphic].src_y;
1088 offset_x = graphic_info[graphic].offset_x;
1089 offset_y = graphic_info[graphic].offset_y;
1091 drawing_gc = src_bitmap->stored_clip_gc;
1093 src_x += frame * offset_x;
1094 src_y += frame * offset_y;
1099 dest_x = FX + x * TILEX + dx;
1100 dest_y = FY + y * TILEY + dy;
1103 if (!IN_SCR_FIELD(x,y))
1105 printf("DrawGraphicShifted(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
1106 printf("DrawGraphicShifted(): This should never happen!\n");
1111 if (mask_mode == USE_MASKING)
1113 SetClipOrigin(src_bitmap, drawing_gc, dest_x - src_x, dest_y - src_y);
1114 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1118 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1124 void DrawGraphicShiftedThruMask(int x, int y, int dx, int dy, int graphic,
1125 int frame, int cut_mode)
1127 DrawGraphicShifted(x,y, dx,dy, graphic, frame, cut_mode, USE_MASKING);
1130 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
1131 int cut_mode, int mask_mode)
1133 int lx = LEVELX(x), ly = LEVELY(y);
1137 if (IN_LEV_FIELD(lx, ly))
1139 SetRandomAnimationValue(lx, ly);
1141 graphic = el_act_dir2img(element, GfxAction[lx][ly], MovDir[lx][ly]);
1142 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1144 else /* border element */
1146 graphic = el2img(element);
1147 frame = getGraphicAnimationFrame(graphic, -1);
1150 if (element == EL_WALL_GROWING)
1152 boolean left_stopped = FALSE, right_stopped = FALSE;
1154 if (!IN_LEV_FIELD(lx - 1, ly) || IS_MAUER(Feld[lx - 1][ly]))
1155 left_stopped = TRUE;
1156 if (!IN_LEV_FIELD(lx + 1, ly) || IS_MAUER(Feld[lx + 1][ly]))
1157 right_stopped = TRUE;
1159 if (left_stopped && right_stopped)
1161 else if (left_stopped)
1163 graphic = IMG_WALL_GROWING_ACTIVE_RIGHT;
1164 frame = graphic_info[graphic].anim_frames - 1;
1166 else if (right_stopped)
1168 graphic = IMG_WALL_GROWING_ACTIVE_LEFT;
1169 frame = graphic_info[graphic].anim_frames - 1;
1173 else if (IS_AMOEBOID(element) || element == EL_AMOEBA_DRIPPING)
1175 graphic = (element == EL_BD_AMOEBA ? IMG_BD_AMOEBA_PART1 :
1176 element == EL_AMOEBA_WET ? IMG_AMOEBA_WET_PART1 :
1177 element == EL_AMOEBA_DRY ? IMG_AMOEBA_DRY_PART1 :
1178 element == EL_AMOEBA_FULL ? IMG_AMOEBA_FULL_PART1 :
1179 IMG_AMOEBA_DEAD_PART1);
1181 graphic += (x + 2 * y + 4) % 4;
1186 if (IS_AMOEBOID(element) || element == EL_AMOEBA_DRIPPING)
1188 if (Feld[lx][ly] == EL_AMOEBA_DRIPPING)
1189 printf("---> %d -> %d / %d [%d]\n",
1190 element, graphic, frame, GfxRandom[lx][ly]);
1195 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, mask_mode);
1196 else if (mask_mode == USE_MASKING)
1197 DrawGraphicThruMask(x, y, graphic, frame);
1199 DrawGraphic(x, y, graphic, frame);
1202 void DrawLevelElementExt(int x, int y, int dx, int dy, int element,
1203 int cut_mode, int mask_mode)
1205 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1206 DrawScreenElementExt(SCREENX(x), SCREENY(y), dx, dy, element,
1207 cut_mode, mask_mode);
1210 void DrawScreenElementShifted(int x, int y, int dx, int dy, int element,
1213 DrawScreenElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1216 void DrawLevelElementShifted(int x, int y, int dx, int dy, int element,
1219 DrawLevelElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1223 void DrawOldScreenElementThruMask(int x, int y, int element)
1225 DrawOldScreenElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1228 void DrawScreenElementThruMask(int x, int y, int element)
1230 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1234 void DrawLevelElementThruMask(int x, int y, int element)
1236 DrawLevelElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1239 void DrawLevelFieldThruMask(int x, int y)
1241 DrawLevelElementExt(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
1244 void DrawCrumbledSand(int x, int y)
1248 int i, width, height, cx,cy;
1249 int lx = LEVELX(x), ly = LEVELY(y);
1250 int element, graphic;
1252 static int xy[4][2] =
1260 if (!IN_LEV_FIELD(lx, ly))
1263 element = Feld[lx][ly];
1265 if (element == EL_SAND ||
1266 element == EL_LANDMINE ||
1267 element == EL_TRAP ||
1268 element == EL_TRAP_ACTIVE)
1270 if (!IN_SCR_FIELD(x, y))
1273 graphic = IMG_SAND_CRUMBLED;
1275 src_bitmap = graphic_info[graphic].bitmap;
1276 src_x = graphic_info[graphic].src_x;
1277 src_y = graphic_info[graphic].src_y;
1283 lxx = lx + xy[i][0];
1284 lyy = ly + xy[i][1];
1285 if (!IN_LEV_FIELD(lxx, lyy))
1286 element = EL_STEELWALL;
1288 element = Feld[lxx][lyy];
1290 if (element == EL_SAND ||
1291 element == EL_LANDMINE ||
1292 element == EL_TRAP ||
1293 element == EL_TRAP_ACTIVE)
1296 if (i == 1 || i == 2)
1300 cx = (i == 2 ? TILEX - snip : 0);
1308 cy = (i == 3 ? TILEY - snip : 0);
1311 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1312 width, height, FX + x * TILEX + cx, FY + y * TILEY + cy);
1315 MarkTileDirty(x, y);
1319 graphic = IMG_SAND_CRUMBLED;
1321 src_bitmap = graphic_info[graphic].bitmap;
1322 src_x = graphic_info[graphic].src_x;
1323 src_y = graphic_info[graphic].src_y;
1327 int xx, yy, lxx, lyy;
1331 lxx = lx + xy[i][0];
1332 lyy = ly + xy[i][1];
1334 if (!IN_LEV_FIELD(lxx, lyy) ||
1335 (Feld[lxx][lyy] != EL_SAND &&
1336 Feld[lxx][lyy] != EL_LANDMINE &&
1337 Feld[lxx][lyy] != EL_TRAP &&
1338 Feld[lxx][lyy] != EL_TRAP_ACTIVE) ||
1339 !IN_SCR_FIELD(xx, yy))
1342 if (i == 1 || i == 2)
1346 cx = (i == 1 ? TILEX - snip : 0);
1354 cy = (i==0 ? TILEY-snip : 0);
1357 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1358 width, height, FX + xx * TILEX + cx, FY + yy * TILEY + cy);
1360 MarkTileDirty(xx, yy);
1365 static int getBorderElement(int x, int y)
1369 { EL_STEELWALL_TOPLEFT, EL_INVISIBLE_STEELWALL_TOPLEFT },
1370 { EL_STEELWALL_TOPRIGHT, EL_INVISIBLE_STEELWALL_TOPRIGHT },
1371 { EL_STEELWALL_BOTTOMLEFT, EL_INVISIBLE_STEELWALL_BOTTOMLEFT },
1372 { EL_STEELWALL_BOTTOMRIGHT, EL_INVISIBLE_STEELWALL_BOTTOMRIGHT },
1373 { EL_STEELWALL_VERTICAL, EL_INVISIBLE_STEELWALL_VERTICAL },
1374 { EL_STEELWALL_HORIZONTAL, EL_INVISIBLE_STEELWALL_HORIZONTAL },
1375 { EL_STEELWALL, EL_INVISIBLE_STEELWALL }
1377 int steel_type = (BorderElement == EL_STEELWALL ? 0 : 1);
1378 int steel_position = (x == -1 && y == -1 ? 0 :
1379 x == lev_fieldx && y == -1 ? 1 :
1380 x == -1 && y == lev_fieldy ? 2 :
1381 x == lev_fieldx && y == lev_fieldy ? 3 :
1382 x == -1 || x == lev_fieldx ? 4 :
1383 y == -1 || y == lev_fieldy ? 5 : 6);
1385 return border[steel_position][steel_type];
1388 void DrawScreenElement(int x, int y, int element)
1390 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
1391 DrawCrumbledSand(x, y);
1394 void DrawLevelElement(int x, int y, int element)
1396 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1397 DrawScreenElement(SCREENX(x), SCREENY(y), element);
1400 void DrawScreenField(int x, int y)
1402 int lx = LEVELX(x), ly = LEVELY(y);
1403 int element, content;
1405 if (!IN_LEV_FIELD(lx, ly))
1407 if (lx < -1 || lx > lev_fieldx || ly < -1 || ly > lev_fieldy)
1410 element = getBorderElement(lx, ly);
1412 DrawScreenElement(x, y, element);
1416 element = Feld[lx][ly];
1417 content = Store[lx][ly];
1419 if (IS_MOVING(lx, ly))
1421 int horiz_move = (MovDir[lx][ly] == MV_LEFT || MovDir[lx][ly] == MV_RIGHT);
1422 boolean cut_mode = NO_CUTTING;
1424 if (element == EL_QUICKSAND_EMPTYING ||
1425 element == EL_MAGIC_WALL_EMPTYING ||
1426 element == EL_BD_MAGIC_WALL_EMPTYING ||
1427 element == EL_AMOEBA_DRIPPING)
1428 cut_mode = CUT_ABOVE;
1429 else if (element == EL_QUICKSAND_FILLING ||
1430 element == EL_MAGIC_WALL_FILLING ||
1431 element == EL_BD_MAGIC_WALL_FILLING)
1432 cut_mode = CUT_BELOW;
1434 if (cut_mode == CUT_ABOVE)
1435 DrawScreenElementShifted(x, y, 0, 0, element, NO_CUTTING);
1437 DrawScreenElement(x, y, EL_EMPTY);
1440 DrawScreenElementShifted(x, y, MovPos[lx][ly], 0, element, NO_CUTTING);
1441 else if (cut_mode == NO_CUTTING)
1442 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], element, cut_mode);
1444 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], content, cut_mode);
1446 if (content == EL_ACID)
1447 DrawLevelElementThruMask(lx, ly + 1, EL_ACID);
1449 else if (IS_BLOCKED(lx, ly))
1454 boolean cut_mode = NO_CUTTING;
1455 int element_old, content_old;
1457 Blocked2Moving(lx, ly, &oldx, &oldy);
1460 horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
1461 MovDir[oldx][oldy] == MV_RIGHT);
1463 element_old = Feld[oldx][oldy];
1464 content_old = Store[oldx][oldy];
1466 if (element_old == EL_QUICKSAND_EMPTYING ||
1467 element_old == EL_MAGIC_WALL_EMPTYING ||
1468 element_old == EL_BD_MAGIC_WALL_EMPTYING ||
1469 element_old == EL_AMOEBA_DRIPPING)
1470 cut_mode = CUT_ABOVE;
1472 DrawScreenElement(x, y, EL_EMPTY);
1475 DrawScreenElementShifted(sx, sy, MovPos[oldx][oldy], 0, element_old,
1477 else if (cut_mode == NO_CUTTING)
1478 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], element_old,
1481 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], content_old,
1484 else if (IS_DRAWABLE(element))
1485 DrawScreenElement(x, y, element);
1487 DrawScreenElement(x, y, EL_EMPTY);
1490 void DrawLevelField(int x, int y)
1492 if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1493 DrawScreenField(SCREENX(x), SCREENY(y));
1494 else if (IS_MOVING(x, y))
1498 Moving2Blocked(x, y, &newx, &newy);
1499 if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
1500 DrawScreenField(SCREENX(newx), SCREENY(newy));
1502 else if (IS_BLOCKED(x, y))
1506 Blocked2Moving(x, y, &oldx, &oldy);
1507 if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
1508 DrawScreenField(SCREENX(oldx), SCREENY(oldy));
1512 void DrawMiniElement(int x, int y, int element)
1516 graphic = el2edimg(element);
1517 DrawMiniGraphic(x, y, graphic);
1520 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
1522 int x = sx + scroll_x, y = sy + scroll_y;
1524 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
1525 DrawMiniElement(sx, sy, EL_EMPTY);
1526 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
1527 DrawMiniElement(sx, sy, Feld[x][y]);
1529 DrawMiniGraphic(sx, sy, el2edimg(getBorderElement(x, y)));
1532 void getMicroGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
1534 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
1535 int mini_startx = src_bitmap->width * 3 / 4;
1536 int mini_starty = src_bitmap->height * 2 / 3;
1537 int src_x = mini_startx + graphic_info[graphic].src_x / 8;
1538 int src_y = mini_starty + graphic_info[graphic].src_y / 8;
1540 if (src_x + MICRO_TILEX > src_bitmap->width ||
1541 src_y + MICRO_TILEY > src_bitmap->height)
1543 /* graphic of desired size seems not to be contained in this image;
1544 dirty workaround: get it from the middle of the normal sized image */
1546 getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
1547 src_x += (TILEX / 2 - MICRO_TILEX / 2);
1548 src_y += (TILEY / 2 - MICRO_TILEY / 2);
1551 *bitmap = src_bitmap;
1556 void DrawMicroElement(int xpos, int ypos, int element)
1560 int graphic = el2preimg(element);
1562 getMicroGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
1563 BlitBitmap(src_bitmap, drawto, src_x, src_y, MICRO_TILEX, MICRO_TILEY,
1571 SetDrawBackgroundMask(REDRAW_NONE);
1574 for(x=BX1; x<=BX2; x++)
1575 for(y=BY1; y<=BY2; y++)
1576 DrawScreenField(x, y);
1578 redraw_mask |= REDRAW_FIELD;
1581 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
1585 for(x=0; x<size_x; x++)
1586 for(y=0; y<size_y; y++)
1587 DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
1589 redraw_mask |= REDRAW_FIELD;
1592 static void DrawMicroLevelExt(int xpos, int ypos, int from_x, int from_y)
1596 DrawBackground(xpos, ypos, MICROLEV_XSIZE, MICROLEV_YSIZE);
1598 if (lev_fieldx < STD_LEV_FIELDX)
1599 xpos += (STD_LEV_FIELDX - lev_fieldx) / 2 * MICRO_TILEX;
1600 if (lev_fieldy < STD_LEV_FIELDY)
1601 ypos += (STD_LEV_FIELDY - lev_fieldy) / 2 * MICRO_TILEY;
1603 xpos += MICRO_TILEX;
1604 ypos += MICRO_TILEY;
1606 for(x=-1; x<=STD_LEV_FIELDX; x++)
1608 for(y=-1; y<=STD_LEV_FIELDY; y++)
1610 int lx = from_x + x, ly = from_y + y;
1612 if (lx >= 0 && lx < lev_fieldx && ly >= 0 && ly < lev_fieldy)
1613 DrawMicroElement(xpos + x * MICRO_TILEX, ypos + y * MICRO_TILEY,
1615 else if (lx >= -1 && lx < lev_fieldx+1 && ly >= -1 && ly < lev_fieldy+1
1616 && BorderElement != EL_EMPTY)
1617 DrawMicroElement(xpos + x * MICRO_TILEX, ypos + y * MICRO_TILEY,
1618 getBorderElement(lx, ly));
1622 redraw_mask |= REDRAW_MICROLEVEL;
1625 #define MICROLABEL_EMPTY 0
1626 #define MICROLABEL_LEVEL_NAME 1
1627 #define MICROLABEL_CREATED_BY 2
1628 #define MICROLABEL_LEVEL_AUTHOR 3
1629 #define MICROLABEL_IMPORTED_FROM 4
1630 #define MICROLABEL_LEVEL_IMPORT_INFO 5
1632 static void DrawMicroLevelLabelExt(int mode)
1634 char label_text[MAX_OUTPUT_LINESIZE + 1];
1635 int max_len_label_text = SXSIZE / getFontWidth(FONT_SPECIAL_GAME);
1637 DrawBackground(SX, MICROLABEL_YPOS, SXSIZE,getFontHeight(FONT_SPECIAL_GAME));
1639 strncpy(label_text, (mode == MICROLABEL_LEVEL_NAME ? level.name :
1640 mode == MICROLABEL_CREATED_BY ? "created by" :
1641 mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
1642 mode == MICROLABEL_IMPORTED_FROM ? "imported from" :
1643 mode == MICROLABEL_LEVEL_IMPORT_INFO ?
1644 leveldir_current->imported_from : ""),
1645 max_len_label_text);
1646 label_text[max_len_label_text] = '\0';
1648 if (strlen(label_text) > 0)
1650 int text_width = strlen(label_text) * getFontWidth(FONT_SPECIAL_GAME);
1651 int lxpos = SX + (SXSIZE - text_width) / 2;
1652 int lypos = MICROLABEL_YPOS;
1654 DrawText(lxpos, lypos, label_text, FONT_SPECIAL_GAME);
1657 redraw_mask |= REDRAW_MICROLEVEL;
1660 void DrawMicroLevel(int xpos, int ypos, boolean restart)
1662 static unsigned long scroll_delay = 0;
1663 static unsigned long label_delay = 0;
1664 static int from_x, from_y, scroll_direction;
1665 static int label_state, label_counter;
1669 from_x = from_y = 0;
1670 scroll_direction = MV_RIGHT;
1674 DrawMicroLevelExt(xpos, ypos, from_x, from_y);
1675 DrawMicroLevelLabelExt(label_state);
1677 /* initialize delay counters */
1678 DelayReached(&scroll_delay, 0);
1679 DelayReached(&label_delay, 0);
1684 /* scroll micro level, if needed */
1685 if ((lev_fieldx > STD_LEV_FIELDX || lev_fieldy > STD_LEV_FIELDY) &&
1686 DelayReached(&scroll_delay, MICROLEVEL_SCROLL_DELAY))
1688 switch (scroll_direction)
1694 scroll_direction = MV_UP;
1698 if (from_x < lev_fieldx - STD_LEV_FIELDX)
1701 scroll_direction = MV_DOWN;
1708 scroll_direction = MV_RIGHT;
1712 if (from_y < lev_fieldy - STD_LEV_FIELDY)
1715 scroll_direction = MV_LEFT;
1722 DrawMicroLevelExt(xpos, ypos, from_x, from_y);
1725 /* redraw micro level label, if needed */
1726 if (strcmp(level.name, NAMELESS_LEVEL_NAME) != 0 &&
1727 strcmp(level.author, ANONYMOUS_NAME) != 0 &&
1728 strcmp(level.author, leveldir_current->name) != 0 &&
1729 DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
1731 int max_label_counter = 23;
1733 if (leveldir_current->imported_from != NULL)
1734 max_label_counter += 14;
1736 label_counter = (label_counter + 1) % max_label_counter;
1737 label_state = (label_counter >= 0 && label_counter <= 7 ?
1738 MICROLABEL_LEVEL_NAME :
1739 label_counter >= 9 && label_counter <= 12 ?
1740 MICROLABEL_CREATED_BY :
1741 label_counter >= 14 && label_counter <= 21 ?
1742 MICROLABEL_LEVEL_AUTHOR :
1743 label_counter >= 23 && label_counter <= 26 ?
1744 MICROLABEL_IMPORTED_FROM :
1745 label_counter >= 28 && label_counter <= 35 ?
1746 MICROLABEL_LEVEL_IMPORT_INFO : MICROLABEL_EMPTY);
1747 DrawMicroLevelLabelExt(label_state);
1751 int REQ_in_range(int x, int y)
1753 if (y > DY+249 && y < DY+278)
1755 if (x > DX+1 && x < DX+48)
1757 else if (x > DX+51 && x < DX+98)
1763 #define MAX_REQUEST_LINES 13
1764 #define MAX_REQUEST_LINE_LEN 7
1766 boolean Request(char *text, unsigned int req_state)
1768 int mx, my, ty, result = -1;
1769 unsigned int old_door_state;
1771 #if defined(PLATFORM_UNIX)
1772 /* pause network game while waiting for request to answer */
1773 if (options.network &&
1774 game_status == PLAYING &&
1775 req_state & REQUEST_WAIT_FOR)
1776 SendToServer_PausePlaying();
1779 old_door_state = GetDoorState();
1783 CloseDoor(DOOR_CLOSE_1);
1785 /* save old door content */
1786 BlitBitmap(bitmap_db_door, bitmap_db_door,
1787 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
1788 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
1790 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
1792 /* clear door drawing field */
1793 DrawBackground(DX, DY, DXSIZE, DYSIZE);
1795 /* write text for request */
1796 for(ty=0; ty < MAX_REQUEST_LINES; ty++)
1798 char text_line[MAX_REQUEST_LINE_LEN + 1];
1804 for(tl=0,tx=0; tx < MAX_REQUEST_LINE_LEN; tl++,tx++)
1807 if (!tc || tc == ' ')
1818 strncpy(text_line, text, tl);
1821 DrawText(DX + 50 - (tl * 14)/2, DY + 8 + ty * 16,
1822 text_line, FONT_DEFAULT_SMALL);
1824 text += tl + (tc == ' ' ? 1 : 0);
1827 if (req_state & REQ_ASK)
1829 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
1830 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
1832 else if (req_state & REQ_CONFIRM)
1834 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
1836 else if (req_state & REQ_PLAYER)
1838 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
1839 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
1840 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
1841 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
1844 /* copy request gadgets to door backbuffer */
1845 BlitBitmap(drawto, bitmap_db_door,
1846 DX, DY, DXSIZE, DYSIZE,
1847 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
1849 OpenDoor(DOOR_OPEN_1);
1855 if (!(req_state & REQUEST_WAIT_FOR))
1857 SetDrawBackgroundMask(REDRAW_FIELD);
1862 if (game_status != MAINMENU)
1865 button_status = MB_RELEASED;
1867 request_gadget_id = -1;
1869 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
1881 case EVENT_BUTTONPRESS:
1882 case EVENT_BUTTONRELEASE:
1883 case EVENT_MOTIONNOTIFY:
1885 if (event.type == EVENT_MOTIONNOTIFY)
1887 if (!PointerInWindow(window))
1888 continue; /* window and pointer are on different screens */
1893 motion_status = TRUE;
1894 mx = ((MotionEvent *) &event)->x;
1895 my = ((MotionEvent *) &event)->y;
1899 motion_status = FALSE;
1900 mx = ((ButtonEvent *) &event)->x;
1901 my = ((ButtonEvent *) &event)->y;
1902 if (event.type == EVENT_BUTTONPRESS)
1903 button_status = ((ButtonEvent *) &event)->button;
1905 button_status = MB_RELEASED;
1908 /* this sets 'request_gadget_id' */
1909 HandleGadgets(mx, my, button_status);
1911 switch(request_gadget_id)
1913 case TOOL_CTRL_ID_YES:
1916 case TOOL_CTRL_ID_NO:
1919 case TOOL_CTRL_ID_CONFIRM:
1920 result = TRUE | FALSE;
1923 case TOOL_CTRL_ID_PLAYER_1:
1926 case TOOL_CTRL_ID_PLAYER_2:
1929 case TOOL_CTRL_ID_PLAYER_3:
1932 case TOOL_CTRL_ID_PLAYER_4:
1943 case EVENT_KEYPRESS:
1944 switch(GetEventKey((KeyEvent *)&event, TRUE))
1957 if (req_state & REQ_PLAYER)
1961 case EVENT_KEYRELEASE:
1962 ClearPlayerAction();
1966 HandleOtherEvents(&event);
1970 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
1972 int joy = AnyJoystick();
1974 if (joy & JOY_BUTTON_1)
1976 else if (joy & JOY_BUTTON_2)
1982 /* don't eat all CPU time */
1986 if (game_status != MAINMENU)
1991 if (!(req_state & REQ_STAY_OPEN))
1993 CloseDoor(DOOR_CLOSE_1);
1995 if (!(req_state & REQ_STAY_CLOSED) && (old_door_state & DOOR_OPEN_1))
1997 BlitBitmap(bitmap_db_door, bitmap_db_door,
1998 DOOR_GFX_PAGEX2,DOOR_GFX_PAGEY1, DXSIZE,DYSIZE,
1999 DOOR_GFX_PAGEX1,DOOR_GFX_PAGEY1);
2000 OpenDoor(DOOR_OPEN_1);
2006 SetDrawBackgroundMask(REDRAW_FIELD);
2008 #if defined(PLATFORM_UNIX)
2009 /* continue network game after request */
2010 if (options.network &&
2011 game_status == PLAYING &&
2012 req_state & REQUEST_WAIT_FOR)
2013 SendToServer_ContinuePlaying();
2019 unsigned int OpenDoor(unsigned int door_state)
2021 unsigned int new_door_state;
2023 if (door_state & DOOR_COPY_BACK)
2025 BlitBitmap(bitmap_db_door, bitmap_db_door,
2026 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE + VYSIZE,
2027 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2028 door_state &= ~DOOR_COPY_BACK;
2031 new_door_state = MoveDoor(door_state);
2033 return(new_door_state);
2036 unsigned int CloseDoor(unsigned int door_state)
2038 unsigned int new_door_state;
2040 BlitBitmap(backbuffer, bitmap_db_door,
2041 DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2042 BlitBitmap(backbuffer, bitmap_db_door,
2043 VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
2045 new_door_state = MoveDoor(door_state);
2047 return(new_door_state);
2050 unsigned int GetDoorState()
2052 return MoveDoor(DOOR_GET_STATE);
2055 unsigned int SetDoorState(unsigned int door_state)
2057 return MoveDoor(door_state | DOOR_SET_STATE);
2060 unsigned int MoveDoor(unsigned int door_state)
2062 static int door1 = DOOR_OPEN_1;
2063 static int door2 = DOOR_CLOSE_2;
2064 static unsigned long door_delay = 0;
2065 int x, start, stepsize = 2;
2066 unsigned long door_delay_value = stepsize * 5;
2068 if (door_state == DOOR_GET_STATE)
2069 return(door1 | door2);
2071 if (door_state & DOOR_SET_STATE)
2073 if (door_state & DOOR_ACTION_1)
2074 door1 = door_state & DOOR_ACTION_1;
2075 if (door_state & DOOR_ACTION_2)
2076 door2 = door_state & DOOR_ACTION_2;
2078 return(door1 | door2);
2081 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
2082 door_state &= ~DOOR_OPEN_1;
2083 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
2084 door_state &= ~DOOR_CLOSE_1;
2085 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
2086 door_state &= ~DOOR_OPEN_2;
2087 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
2088 door_state &= ~DOOR_CLOSE_2;
2090 if (setup.quick_doors)
2093 door_delay_value = 0;
2095 StopSound(SND_MENU_DOOR_OPENING);
2096 StopSound(SND_MENU_DOOR_CLOSING);
2099 if (global.autoplay_leveldir)
2101 door_state |= DOOR_NO_DELAY;
2102 door_state &= ~DOOR_CLOSE_ALL;
2105 if (door_state & DOOR_ACTION)
2107 if (!(door_state & DOOR_NO_DELAY))
2109 /* opening door sound has priority over simultaneously closing door */
2110 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
2111 PlaySoundStereo(SND_MENU_DOOR_OPENING, SOUND_MAX_RIGHT);
2112 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
2113 PlaySoundStereo(SND_MENU_DOOR_CLOSING, SOUND_MAX_RIGHT);
2116 start = ((door_state & DOOR_NO_DELAY) ? DXSIZE : 0);
2118 for(x=start; x<=DXSIZE; x+=stepsize)
2120 Bitmap *bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
2121 GC gc = bitmap->stored_clip_gc;
2123 if (!(door_state & DOOR_NO_DELAY))
2124 WaitUntilDelayReached(&door_delay, door_delay_value);
2126 if (door_state & DOOR_ACTION_1)
2128 int i = (door_state & DOOR_OPEN_1 ? DXSIZE-x : x);
2129 int j = (DXSIZE - i) / 3;
2131 BlitBitmap(bitmap_db_door, drawto,
2132 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + i/2,
2133 DXSIZE,DYSIZE - i/2, DX, DY);
2135 ClearRectangle(drawto, DX, DY + DYSIZE - i/2, DXSIZE,i/2);
2137 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2138 BlitBitmapMasked(bitmap, drawto,
2139 DXSIZE, DOOR_GFX_PAGEY1, i, 77,
2140 DX + DXSIZE - i, DY + j);
2141 BlitBitmapMasked(bitmap, drawto,
2142 DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63,
2143 DX + DXSIZE - i, DY + 140 + j);
2144 SetClipOrigin(bitmap, gc, DX - DXSIZE + i, DY - (DOOR_GFX_PAGEY1 + j));
2145 BlitBitmapMasked(bitmap, drawto,
2146 DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j,
2148 BlitBitmapMasked(bitmap, drawto,
2149 DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63,
2152 BlitBitmapMasked(bitmap, drawto,
2153 DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
2155 BlitBitmapMasked(bitmap, drawto,
2156 DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
2158 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2159 BlitBitmapMasked(bitmap, drawto,
2160 DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
2161 DX + DXSIZE - i, DY + 77 + j);
2162 BlitBitmapMasked(bitmap, drawto,
2163 DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
2164 DX + DXSIZE - i, DY + 203 + j);
2166 redraw_mask |= REDRAW_DOOR_1;
2169 if (door_state & DOOR_ACTION_2)
2171 int i = (door_state & DOOR_OPEN_2 ? VXSIZE - x : x);
2172 int j = (VXSIZE - i) / 3;
2174 BlitBitmap(bitmap_db_door, drawto,
2175 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + i/2,
2176 VXSIZE, VYSIZE - i/2, VX, VY);
2178 ClearRectangle(drawto, VX, VY + VYSIZE-i/2, VXSIZE, i/2);
2180 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2181 BlitBitmapMasked(bitmap, drawto,
2182 VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2,
2183 VX + VXSIZE-i, VY+j);
2184 SetClipOrigin(bitmap, gc,
2185 VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
2186 BlitBitmapMasked(bitmap, drawto,
2187 VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j,
2190 BlitBitmapMasked(bitmap, drawto,
2191 VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2,
2192 i, VYSIZE / 2, VX, VY + VYSIZE / 2 - j);
2193 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2194 BlitBitmapMasked(bitmap, drawto,
2195 VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2,
2197 VX + VXSIZE - i, VY + VYSIZE / 2 + j);
2199 redraw_mask |= REDRAW_DOOR_2;
2204 if (game_status == MAINMENU)
2209 if (setup.quick_doors)
2211 StopSound(SND_MENU_DOOR_OPENING);
2212 StopSound(SND_MENU_DOOR_CLOSING);
2215 if (door_state & DOOR_ACTION_1)
2216 door1 = door_state & DOOR_ACTION_1;
2217 if (door_state & DOOR_ACTION_2)
2218 door2 = door_state & DOOR_ACTION_2;
2220 return (door1 | door2);
2223 void DrawSpecialEditorDoor()
2225 /* draw bigger toolbox window */
2226 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
2227 DOOR_GFX_PAGEX7, 0, EXSIZE + 8, 8,
2229 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
2230 EX - 4, VY - 4, EXSIZE + 8, EYSIZE - VYSIZE + 4,
2233 redraw_mask |= REDRAW_ALL;
2236 void UndrawSpecialEditorDoor()
2238 /* draw normal tape recorder window */
2239 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
2240 EX - 4, EY - 12, EXSIZE + 8, EYSIZE - VYSIZE + 12,
2243 redraw_mask |= REDRAW_ALL;
2247 int ReadPixel(DrawBuffer *bitmap, int x, int y)
2249 XImage *pixel_image;
2250 unsigned long pixel_value;
2252 pixel_image = XGetImage(display, bitmap->drawable,
2253 x, y, 1, 1, AllPlanes, ZPixmap);
2254 pixel_value = XGetPixel(pixel_image, 0, 0);
2256 XDestroyImage(pixel_image);
2262 /* ---------- new tool button stuff ---------------------------------------- */
2264 /* graphic position values for tool buttons */
2265 #define TOOL_BUTTON_YES_XPOS 2
2266 #define TOOL_BUTTON_YES_YPOS 250
2267 #define TOOL_BUTTON_YES_GFX_YPOS 0
2268 #define TOOL_BUTTON_YES_XSIZE 46
2269 #define TOOL_BUTTON_YES_YSIZE 28
2270 #define TOOL_BUTTON_NO_XPOS 52
2271 #define TOOL_BUTTON_NO_YPOS TOOL_BUTTON_YES_YPOS
2272 #define TOOL_BUTTON_NO_GFX_YPOS TOOL_BUTTON_YES_GFX_YPOS
2273 #define TOOL_BUTTON_NO_XSIZE TOOL_BUTTON_YES_XSIZE
2274 #define TOOL_BUTTON_NO_YSIZE TOOL_BUTTON_YES_YSIZE
2275 #define TOOL_BUTTON_CONFIRM_XPOS TOOL_BUTTON_YES_XPOS
2276 #define TOOL_BUTTON_CONFIRM_YPOS TOOL_BUTTON_YES_YPOS
2277 #define TOOL_BUTTON_CONFIRM_GFX_YPOS 30
2278 #define TOOL_BUTTON_CONFIRM_XSIZE 96
2279 #define TOOL_BUTTON_CONFIRM_YSIZE TOOL_BUTTON_YES_YSIZE
2280 #define TOOL_BUTTON_PLAYER_XSIZE 30
2281 #define TOOL_BUTTON_PLAYER_YSIZE 30
2282 #define TOOL_BUTTON_PLAYER_GFX_XPOS 5
2283 #define TOOL_BUTTON_PLAYER_GFX_YPOS 185
2284 #define TOOL_BUTTON_PLAYER_XPOS (5 + TOOL_BUTTON_PLAYER_XSIZE / 2)
2285 #define TOOL_BUTTON_PLAYER_YPOS (215 - TOOL_BUTTON_PLAYER_YSIZE / 2)
2286 #define TOOL_BUTTON_PLAYER1_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2287 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2288 #define TOOL_BUTTON_PLAYER2_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2289 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2290 #define TOOL_BUTTON_PLAYER3_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2291 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2292 #define TOOL_BUTTON_PLAYER4_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2293 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2294 #define TOOL_BUTTON_PLAYER1_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2295 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2296 #define TOOL_BUTTON_PLAYER2_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2297 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2298 #define TOOL_BUTTON_PLAYER3_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2299 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2300 #define TOOL_BUTTON_PLAYER4_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2301 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2310 } toolbutton_info[NUM_TOOL_BUTTONS] =
2313 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_GFX_YPOS,
2314 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_YPOS,
2315 TOOL_BUTTON_YES_XSIZE, TOOL_BUTTON_YES_YSIZE,
2320 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_GFX_YPOS,
2321 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_YPOS,
2322 TOOL_BUTTON_NO_XSIZE, TOOL_BUTTON_NO_YSIZE,
2327 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_GFX_YPOS,
2328 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_YPOS,
2329 TOOL_BUTTON_CONFIRM_XSIZE, TOOL_BUTTON_CONFIRM_YSIZE,
2330 TOOL_CTRL_ID_CONFIRM,
2334 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2335 TOOL_BUTTON_PLAYER1_XPOS, TOOL_BUTTON_PLAYER1_YPOS,
2336 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2337 TOOL_CTRL_ID_PLAYER_1,
2341 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2342 TOOL_BUTTON_PLAYER2_XPOS, TOOL_BUTTON_PLAYER2_YPOS,
2343 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2344 TOOL_CTRL_ID_PLAYER_2,
2348 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2349 TOOL_BUTTON_PLAYER3_XPOS, TOOL_BUTTON_PLAYER3_YPOS,
2350 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2351 TOOL_CTRL_ID_PLAYER_3,
2355 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2356 TOOL_BUTTON_PLAYER4_XPOS, TOOL_BUTTON_PLAYER4_YPOS,
2357 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2358 TOOL_CTRL_ID_PLAYER_4,
2363 void CreateToolButtons()
2367 for (i=0; i<NUM_TOOL_BUTTONS; i++)
2369 Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
2370 Bitmap *deco_bitmap = None;
2371 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
2372 struct GadgetInfo *gi;
2373 unsigned long event_mask;
2374 int gd_xoffset, gd_yoffset;
2375 int gd_x1, gd_x2, gd_y;
2378 event_mask = GD_EVENT_RELEASED;
2380 gd_xoffset = toolbutton_info[i].xpos;
2381 gd_yoffset = toolbutton_info[i].ypos;
2382 gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
2383 gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
2384 gd_y = DOOR_GFX_PAGEY1 + gd_yoffset;
2386 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
2388 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
2390 getMiniGraphicSource(PLAYER_NR_GFX(IMG_PLAYER1, player_nr),
2391 &deco_bitmap, &deco_x, &deco_y);
2392 deco_xpos = (toolbutton_info[i].width - MINI_TILEX) / 2;
2393 deco_ypos = (toolbutton_info[i].height - MINI_TILEY) / 2;
2396 gi = CreateGadget(GDI_CUSTOM_ID, id,
2397 GDI_INFO_TEXT, toolbutton_info[i].infotext,
2398 GDI_X, DX + toolbutton_info[i].x,
2399 GDI_Y, DY + toolbutton_info[i].y,
2400 GDI_WIDTH, toolbutton_info[i].width,
2401 GDI_HEIGHT, toolbutton_info[i].height,
2402 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
2403 GDI_STATE, GD_BUTTON_UNPRESSED,
2404 GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
2405 GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
2406 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
2407 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
2408 GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
2409 GDI_DECORATION_SHIFTING, 1, 1,
2410 GDI_EVENT_MASK, event_mask,
2411 GDI_CALLBACK_ACTION, HandleToolButtons,
2415 Error(ERR_EXIT, "cannot create gadget");
2417 tool_gadget[id] = gi;
2421 void FreeToolButtons()
2425 for (i=0; i<NUM_TOOL_BUTTONS; i++)
2426 FreeGadget(tool_gadget[i]);
2429 static void UnmapToolButtons()
2433 for (i=0; i<NUM_TOOL_BUTTONS; i++)
2434 UnmapGadget(tool_gadget[i]);
2437 static void HandleToolButtons(struct GadgetInfo *gi)
2439 request_gadget_id = gi->custom_id;
2442 int get_next_element(int element)
2446 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
2447 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
2448 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
2449 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
2450 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
2451 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
2452 case EL_AMOEBA_DRIPPING: return EL_AMOEBA_WET;
2454 default: return element;
2458 int el_act_dir2img(int element, int action, int direction)
2460 direction = MV_DIR_BIT(direction);
2462 return element_info[element].direction_graphic[action][direction];
2465 int el_act2img(int element, int action)
2467 return element_info[element].graphic[action];
2470 int el_dir2img(int element, int direction)
2472 return el_act_dir2img(element, ACTION_DEFAULT, direction);
2475 int el2img(int element)
2477 return element_info[element].graphic[ACTION_DEFAULT];
2480 int el2edimg(int element)
2482 return element_info[element].editor_graphic;
2485 int el2preimg(int element)
2487 return element_info[element].preview_graphic;