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 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 (game.emulation == EMU_SUPAPLEX)
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_moving ? IMG_PLAYER1_MOVING_LEFT :
671 else if (player->MovDir == MV_RIGHT)
672 graphic = (player->Pushing ? IMG_PLAYER1_PUSHING_RIGHT :
673 player->is_moving ? IMG_PLAYER1_MOVING_RIGHT :
675 else if (player->MovDir == MV_UP)
676 graphic = (player->Pushing ? IMG_PLAYER1_PUSHING_UP :
677 player->is_moving ? IMG_PLAYER1_MOVING_UP :
679 else /* MV_DOWN || MV_NO_MOVING */
680 graphic = (player->Pushing ? IMG_PLAYER1_PUSHING_DOWN :
681 player->is_moving ? IMG_PLAYER1_MOVING_DOWN :
684 graphic = PLAYER_NR_GFX(graphic, player->index_nr);
687 frame = player->Frame;
689 frame = getGraphicAnimationFrame(graphic, player->Frame);
695 if (player->MovDir == MV_LEFT || player->MovDir == MV_RIGHT)
696 sxx = player->GfxPos;
698 syy = player->GfxPos;
701 if (!setup.soft_scrolling && ScreenMovPos)
706 printf("-> %d\n", player->Frame);
709 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
711 if (SHIELD_ON(player))
713 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
714 IMG_SHIELD_NORMAL_ACTIVE);
715 int frame = getGraphicAnimationFrame(graphic, -1);
717 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
721 if (player->Pushing && player->GfxPos)
723 if (player->Pushing && player_is_moving)
726 int px = SCREENX(next_jx), py = SCREENY(next_jy);
729 (element == EL_SOKOBAN_FIELD_EMPTY ||
730 Feld[next_jx][next_jy] == EL_SOKOBAN_FIELD_FULL))
731 DrawGraphicShiftedThruMask(px, py, sxx, syy, IMG_SOKOBAN_OBJECT, 0,
735 int element = Feld[next_jx][next_jy];
736 int graphic = el2img(element);
741 if ((sxx || syy) && IS_PUSHABLE(element))
743 graphic = el_act_dir2img(element, ACTION_MOVING, player->MovDir);
745 frame = getGraphicAnimationFrame(graphic, player->GfxPos);
747 frame = getGraphicAnimationFrame(graphic, player->Frame);
751 printf("-> %d [%d]\n", player->Frame, player->GfxPos);
756 if (player->MovDir == MV_LEFT)
761 frame = (player->GfxPos / (TILEX / 4));
763 if (player->MovDir == MV_RIGHT)
764 frame = (frame + 4) % 4;
768 DrawGraphicShifted(px, py, sxx, syy, graphic, frame,
769 NO_CUTTING, NO_MASKING);
773 /* draw things in front of player (active dynamite or dynabombs) */
775 if (IS_ACTIVE_BOMB(element))
777 graphic = el2img(element);
780 if (element == EL_DYNAMITE_ACTIVE)
782 if ((frame = (96 - MovDelay[jx][jy]) / 12) > 6)
787 if ((frame = ((96 - MovDelay[jx][jy]) / 6) % 8) > 3)
793 frame = getGraphicAnimationFrame(graphic, 96 - MovDelay[jx][jy]);
795 frame = getGraphicAnimationFrame(graphic, GfxFrame[jx][jy]);
800 if (game.emulation == EMU_SUPAPLEX)
801 DrawGraphic(sx, sy, IMG_SP_DISK_RED, frame);
803 DrawGraphicThruMask(sx, sy, graphic, frame);
806 if (player_is_moving && last_element == EL_EXPLOSION)
808 int stored = Store[last_jx][last_jy];
809 int graphic = (game.emulation != EMU_SUPAPLEX ? IMG_EXPLOSION :
810 stored == EL_SP_INFOTRON ? IMG_SP_EXPLOSION_INFOTRON :
812 int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
813 int phase = ExplodePhase[last_jx][last_jy] - 1;
814 int frame = getGraphicAnimationFrame(graphic, phase - delay);
817 DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy), graphic, frame);
820 /* draw elements that stay over the player */
821 /* handle the field the player is leaving ... */
822 if (player_is_moving && IS_OVER_PLAYER(last_element))
823 DrawLevelField(last_jx, last_jy);
825 /* ... and the field the player is entering */
826 if (IS_OVER_PLAYER(element))
827 DrawLevelField(jx, jy);
829 if (setup.direct_draw)
831 int dest_x = SX + SCREENX(MIN(jx, last_jx)) * TILEX;
832 int dest_y = SY + SCREENY(MIN(jy, last_jy)) * TILEY;
833 int x_size = TILEX * (1 + ABS(jx - last_jx));
834 int y_size = TILEY * (1 + ABS(jy - last_jy));
836 BlitBitmap(drawto_field, window,
837 dest_x, dest_y, x_size, y_size, dest_x, dest_y);
838 SetDrawtoField(DRAW_DIRECT);
841 MarkTileDirty(sx,sy);
844 void getGraphicSource(int graphic, int frame, Bitmap **bitmap, int *x, int *y)
846 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
847 int offset_x = graphic_info[graphic].offset_x;
848 int offset_y = graphic_info[graphic].offset_y;
849 int src_x = graphic_info[graphic].src_x + frame * offset_x;
850 int src_y = graphic_info[graphic].src_y + frame * offset_y;
852 *bitmap = src_bitmap;
857 void DrawGraphic(int x, int y, int graphic, int frame)
860 if (!IN_SCR_FIELD(x, y))
862 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
863 printf("DrawGraphic(): This should never happen!\n");
868 DrawGraphicExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic, frame);
873 void DrawOldGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic)
878 getOldGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
879 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
883 void DrawGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
890 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
892 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
893 int src_x = graphic_info[graphic].src_x;
894 int src_y = graphic_info[graphic].src_y;
895 int offset_x = graphic_info[graphic].offset_x;
896 int offset_y = graphic_info[graphic].offset_y;
898 src_x += frame * offset_x;
899 src_y += frame * offset_y;
902 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
905 void DrawGraphicThruMask(int x, int y, int graphic, int frame)
908 if (!IN_SCR_FIELD(x, y))
910 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
911 printf("DrawGraphicThruMask(): This should never happen!\n");
916 DrawGraphicThruMaskExt(drawto_field, FX + x * TILEX, FY + y *TILEY, graphic,
921 void DrawGraphicThruMaskExt(DrawBuffer *d, int dest_x, int dest_y, int graphic,
929 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
930 drawing_gc = src_bitmap->stored_clip_gc;
932 GC drawing_gc = src_bitmap->stored_clip_gc;
933 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
934 int src_x = graphic_info[graphic].src_x;
935 int src_y = graphic_info[graphic].src_y;
936 int offset_x = graphic_info[graphic].offset_x;
937 int offset_y = graphic_info[graphic].offset_y;
939 src_x += frame * offset_x;
940 src_y += frame * offset_y;
944 SetClipOrigin(src_bitmap, drawing_gc, dest_x - src_x, dest_y - src_y);
945 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX, TILEY, dest_x, dest_y);
948 void DrawMiniGraphic(int x, int y, int graphic)
950 DrawMiniGraphicExt(drawto, SX + x * MINI_TILEX,SY + y * MINI_TILEY, graphic);
951 MarkTileDirty(x / 2, y / 2);
954 void getMiniGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
956 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
958 int mini_starty = src_bitmap->height * 2 / 3;
959 int src_x = mini_startx + graphic_info[graphic].src_x / 2;
960 int src_y = mini_starty + graphic_info[graphic].src_y / 2;
963 /* !!! not needed anymore, because of automatically created mini graphics */
964 if (src_x + MINI_TILEX > src_bitmap->width ||
965 src_y + MINI_TILEY > src_bitmap->height)
967 /* graphic of desired size seems not to be contained in this image;
968 dirty workaround: get it from the middle of the normal sized image */
970 printf("::: using dirty workaround for %d (%d, %d)\n",
971 graphic, src_bitmap->width, src_bitmap->height);
973 getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
974 src_x += (TILEX / 2 - MINI_TILEX / 2);
975 src_y += (TILEY / 2 - MINI_TILEY / 2);
979 *bitmap = src_bitmap;
984 void DrawMiniGraphicExt(DrawBuffer *d, int x, int y, int graphic)
989 getMiniGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
990 BlitBitmap(src_bitmap, d, src_x, src_y, MINI_TILEX, MINI_TILEY, x, y);
993 void DrawGraphicShifted(int x,int y, int dx,int dy, int graphic, int frame,
994 int cut_mode, int mask_mode)
1003 int width = TILEX, height = TILEY;
1009 DrawGraphic(x, y, graphic, frame);
1013 if (dx || dy) /* shifted graphic */
1015 if (x < BX1) /* object enters playfield from the left */
1022 else if (x > BX2) /* object enters playfield from the right */
1028 else if (x==BX1 && dx < 0) /* object leaves playfield to the left */
1034 else if (x==BX2 && dx > 0) /* object leaves playfield to the right */
1036 else if (dx) /* general horizontal movement */
1037 MarkTileDirty(x + SIGN(dx), y);
1039 if (y < BY1) /* object enters playfield from the top */
1041 if (cut_mode==CUT_BELOW) /* object completely above top border */
1049 else if (y > BY2) /* object enters playfield from the bottom */
1055 else if (y==BY1 && dy < 0) /* object leaves playfield to the top */
1061 else if (dy > 0 && cut_mode == CUT_ABOVE)
1063 if (y == BY2) /* object completely above bottom border */
1069 MarkTileDirty(x, y + 1);
1070 } /* object leaves playfield to the bottom */
1071 else if (dy > 0 && (y == BY2 || cut_mode == CUT_BELOW))
1073 else if (dy) /* general vertical movement */
1074 MarkTileDirty(x, y + SIGN(dy));
1077 src_bitmap = graphic_info[graphic].bitmap;
1078 src_x = graphic_info[graphic].src_x;
1079 src_y = graphic_info[graphic].src_y;
1080 offset_x = graphic_info[graphic].offset_x;
1081 offset_y = graphic_info[graphic].offset_y;
1083 drawing_gc = src_bitmap->stored_clip_gc;
1085 src_x += frame * offset_x;
1086 src_y += frame * offset_y;
1091 dest_x = FX + x * TILEX + dx;
1092 dest_y = FY + y * TILEY + dy;
1095 if (!IN_SCR_FIELD(x,y))
1097 printf("DrawGraphicShifted(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
1098 printf("DrawGraphicShifted(): This should never happen!\n");
1103 if (mask_mode == USE_MASKING)
1105 SetClipOrigin(src_bitmap, drawing_gc, dest_x - src_x, dest_y - src_y);
1106 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1110 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1116 void DrawGraphicShiftedThruMask(int x, int y, int dx, int dy, int graphic,
1117 int frame, int cut_mode)
1119 DrawGraphicShifted(x,y, dx,dy, graphic, frame, cut_mode, USE_MASKING);
1122 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
1123 int cut_mode, int mask_mode)
1125 int lx = LEVELX(x), ly = LEVELY(y);
1129 if (IN_LEV_FIELD(lx, ly))
1131 SetRandomAnimationValue(lx, ly);
1133 graphic = el_act_dir2img(element, GfxAction[lx][ly], MovDir[lx][ly]);
1134 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1136 else /* border element */
1138 graphic = el2img(element);
1139 frame = getGraphicAnimationFrame(graphic, -1);
1142 if (element == EL_WALL_GROWING)
1144 boolean left_stopped = FALSE, right_stopped = FALSE;
1146 if (!IN_LEV_FIELD(lx - 1, ly) || IS_MAUER(Feld[lx - 1][ly]))
1147 left_stopped = TRUE;
1148 if (!IN_LEV_FIELD(lx + 1, ly) || IS_MAUER(Feld[lx + 1][ly]))
1149 right_stopped = TRUE;
1151 if (left_stopped && right_stopped)
1153 else if (left_stopped)
1155 graphic = IMG_WALL_GROWING_ACTIVE_RIGHT;
1156 frame = graphic_info[graphic].anim_frames - 1;
1158 else if (right_stopped)
1160 graphic = IMG_WALL_GROWING_ACTIVE_LEFT;
1161 frame = graphic_info[graphic].anim_frames - 1;
1165 else if (IS_AMOEBOID(element) || element == EL_AMOEBA_DRIPPING)
1167 graphic = (element == EL_BD_AMOEBA ? IMG_BD_AMOEBA_PART1 :
1168 element == EL_AMOEBA_WET ? IMG_AMOEBA_WET_PART1 :
1169 element == EL_AMOEBA_DRY ? IMG_AMOEBA_DRY_PART1 :
1170 element == EL_AMOEBA_FULL ? IMG_AMOEBA_FULL_PART1 :
1171 IMG_AMOEBA_DEAD_PART1);
1173 graphic += (x + 2 * y + 4) % 4;
1178 if (IS_AMOEBOID(element) || element == EL_AMOEBA_DRIPPING)
1180 if (Feld[lx][ly] == EL_AMOEBA_DRIPPING)
1181 printf("---> %d -> %d / %d [%d]\n",
1182 element, graphic, frame, GfxRandom[lx][ly]);
1187 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, mask_mode);
1188 else if (mask_mode == USE_MASKING)
1189 DrawGraphicThruMask(x, y, graphic, frame);
1191 DrawGraphic(x, y, graphic, frame);
1194 void DrawLevelElementExt(int x, int y, int dx, int dy, int element,
1195 int cut_mode, int mask_mode)
1197 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1198 DrawScreenElementExt(SCREENX(x), SCREENY(y), dx, dy, element,
1199 cut_mode, mask_mode);
1202 void DrawScreenElementShifted(int x, int y, int dx, int dy, int element,
1205 DrawScreenElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1208 void DrawLevelElementShifted(int x, int y, int dx, int dy, int element,
1211 DrawLevelElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1215 void DrawOldScreenElementThruMask(int x, int y, int element)
1217 DrawOldScreenElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1220 void DrawScreenElementThruMask(int x, int y, int element)
1222 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1226 void DrawLevelElementThruMask(int x, int y, int element)
1228 DrawLevelElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1231 void DrawLevelFieldThruMask(int x, int y)
1233 DrawLevelElementExt(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
1236 void DrawCrumbledSand(int x, int y)
1240 int i, width, height, cx,cy;
1241 int lx = LEVELX(x), ly = LEVELY(y);
1242 int element, graphic;
1244 static int xy[4][2] =
1252 if (!IN_LEV_FIELD(lx, ly))
1255 element = Feld[lx][ly];
1257 if (element == EL_SAND ||
1258 element == EL_LANDMINE ||
1259 element == EL_TRAP ||
1260 element == EL_TRAP_ACTIVE)
1262 if (!IN_SCR_FIELD(x, y))
1265 graphic = IMG_SAND_CRUMBLED;
1267 src_bitmap = graphic_info[graphic].bitmap;
1268 src_x = graphic_info[graphic].src_x;
1269 src_y = graphic_info[graphic].src_y;
1275 lxx = lx + xy[i][0];
1276 lyy = ly + xy[i][1];
1277 if (!IN_LEV_FIELD(lxx, lyy))
1278 element = EL_STEELWALL;
1280 element = Feld[lxx][lyy];
1282 if (element == EL_SAND ||
1283 element == EL_LANDMINE ||
1284 element == EL_TRAP ||
1285 element == EL_TRAP_ACTIVE)
1288 if (i == 1 || i == 2)
1292 cx = (i == 2 ? TILEX - snip : 0);
1300 cy = (i == 3 ? TILEY - snip : 0);
1303 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1304 width, height, FX + x * TILEX + cx, FY + y * TILEY + cy);
1307 MarkTileDirty(x, y);
1311 graphic = IMG_SAND_CRUMBLED;
1313 src_bitmap = graphic_info[graphic].bitmap;
1314 src_x = graphic_info[graphic].src_x;
1315 src_y = graphic_info[graphic].src_y;
1319 int xx, yy, lxx, lyy;
1323 lxx = lx + xy[i][0];
1324 lyy = ly + xy[i][1];
1326 if (!IN_LEV_FIELD(lxx, lyy) ||
1327 (Feld[lxx][lyy] != EL_SAND &&
1328 Feld[lxx][lyy] != EL_LANDMINE &&
1329 Feld[lxx][lyy] != EL_TRAP &&
1330 Feld[lxx][lyy] != EL_TRAP_ACTIVE) ||
1331 !IN_SCR_FIELD(xx, yy))
1334 if (i == 1 || i == 2)
1338 cx = (i == 1 ? TILEX - snip : 0);
1346 cy = (i==0 ? TILEY-snip : 0);
1349 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1350 width, height, FX + xx * TILEX + cx, FY + yy * TILEY + cy);
1352 MarkTileDirty(xx, yy);
1357 static int getBorderElement(int x, int y)
1361 { EL_STEELWALL_TOPLEFT, EL_INVISIBLE_STEELWALL_TOPLEFT },
1362 { EL_STEELWALL_TOPRIGHT, EL_INVISIBLE_STEELWALL_TOPRIGHT },
1363 { EL_STEELWALL_BOTTOMLEFT, EL_INVISIBLE_STEELWALL_BOTTOMLEFT },
1364 { EL_STEELWALL_BOTTOMRIGHT, EL_INVISIBLE_STEELWALL_BOTTOMRIGHT },
1365 { EL_STEELWALL_VERTICAL, EL_INVISIBLE_STEELWALL_VERTICAL },
1366 { EL_STEELWALL_HORIZONTAL, EL_INVISIBLE_STEELWALL_HORIZONTAL },
1367 { EL_STEELWALL, EL_INVISIBLE_STEELWALL }
1369 int steel_type = (BorderElement == EL_STEELWALL ? 0 : 1);
1370 int steel_position = (x == -1 && y == -1 ? 0 :
1371 x == lev_fieldx && y == -1 ? 1 :
1372 x == -1 && y == lev_fieldy ? 2 :
1373 x == lev_fieldx && y == lev_fieldy ? 3 :
1374 x == -1 || x == lev_fieldx ? 4 :
1375 y == -1 || y == lev_fieldy ? 5 : 6);
1377 return border[steel_position][steel_type];
1380 void DrawScreenElement(int x, int y, int element)
1382 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
1383 DrawCrumbledSand(x, y);
1386 void DrawLevelElement(int x, int y, int element)
1388 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1389 DrawScreenElement(SCREENX(x), SCREENY(y), element);
1392 void DrawScreenField(int x, int y)
1394 int lx = LEVELX(x), ly = LEVELY(y);
1395 int element, content;
1397 if (!IN_LEV_FIELD(lx, ly))
1399 if (lx < -1 || lx > lev_fieldx || ly < -1 || ly > lev_fieldy)
1402 element = getBorderElement(lx, ly);
1404 DrawScreenElement(x, y, element);
1408 element = Feld[lx][ly];
1409 content = Store[lx][ly];
1411 if (IS_MOVING(lx, ly))
1413 int horiz_move = (MovDir[lx][ly] == MV_LEFT || MovDir[lx][ly] == MV_RIGHT);
1414 boolean cut_mode = NO_CUTTING;
1416 if (element == EL_QUICKSAND_EMPTYING ||
1417 element == EL_MAGIC_WALL_EMPTYING ||
1418 element == EL_BD_MAGIC_WALL_EMPTYING ||
1419 element == EL_AMOEBA_DRIPPING)
1420 cut_mode = CUT_ABOVE;
1421 else if (element == EL_QUICKSAND_FILLING ||
1422 element == EL_MAGIC_WALL_FILLING ||
1423 element == EL_BD_MAGIC_WALL_FILLING)
1424 cut_mode = CUT_BELOW;
1426 if (cut_mode == CUT_ABOVE)
1427 DrawScreenElementShifted(x, y, 0, 0, element, NO_CUTTING);
1429 DrawScreenElement(x, y, EL_EMPTY);
1432 DrawScreenElementShifted(x, y, MovPos[lx][ly], 0, element, NO_CUTTING);
1433 else if (cut_mode == NO_CUTTING)
1434 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], element, cut_mode);
1436 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], content, cut_mode);
1438 if (content == EL_ACID)
1439 DrawLevelElementThruMask(lx, ly + 1, EL_ACID);
1441 else if (IS_BLOCKED(lx, ly))
1446 boolean cut_mode = NO_CUTTING;
1447 int element_old, content_old;
1449 Blocked2Moving(lx, ly, &oldx, &oldy);
1452 horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
1453 MovDir[oldx][oldy] == MV_RIGHT);
1455 element_old = Feld[oldx][oldy];
1456 content_old = Store[oldx][oldy];
1458 if (element_old == EL_QUICKSAND_EMPTYING ||
1459 element_old == EL_MAGIC_WALL_EMPTYING ||
1460 element_old == EL_BD_MAGIC_WALL_EMPTYING ||
1461 element_old == EL_AMOEBA_DRIPPING)
1462 cut_mode = CUT_ABOVE;
1464 DrawScreenElement(x, y, EL_EMPTY);
1467 DrawScreenElementShifted(sx, sy, MovPos[oldx][oldy], 0, element_old,
1469 else if (cut_mode == NO_CUTTING)
1470 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], element_old,
1473 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], content_old,
1476 else if (IS_DRAWABLE(element))
1477 DrawScreenElement(x, y, element);
1479 DrawScreenElement(x, y, EL_EMPTY);
1482 void DrawLevelField(int x, int y)
1484 if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1485 DrawScreenField(SCREENX(x), SCREENY(y));
1486 else if (IS_MOVING(x, y))
1490 Moving2Blocked(x, y, &newx, &newy);
1491 if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
1492 DrawScreenField(SCREENX(newx), SCREENY(newy));
1494 else if (IS_BLOCKED(x, y))
1498 Blocked2Moving(x, y, &oldx, &oldy);
1499 if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
1500 DrawScreenField(SCREENX(oldx), SCREENY(oldy));
1504 void DrawMiniElement(int x, int y, int element)
1508 graphic = el2edimg(element);
1509 DrawMiniGraphic(x, y, graphic);
1512 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
1514 int x = sx + scroll_x, y = sy + scroll_y;
1516 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
1517 DrawMiniElement(sx, sy, EL_EMPTY);
1518 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
1519 DrawMiniElement(sx, sy, Feld[x][y]);
1521 DrawMiniGraphic(sx, sy, el2edimg(getBorderElement(x, y)));
1524 void getMicroGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
1526 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
1527 int mini_startx = src_bitmap->width * 3 / 4;
1528 int mini_starty = src_bitmap->height * 2 / 3;
1529 int src_x = mini_startx + graphic_info[graphic].src_x / 8;
1530 int src_y = mini_starty + graphic_info[graphic].src_y / 8;
1532 if (src_x + MICRO_TILEX > src_bitmap->width ||
1533 src_y + MICRO_TILEY > src_bitmap->height)
1535 /* graphic of desired size seems not to be contained in this image;
1536 dirty workaround: get it from the middle of the normal sized image */
1538 getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
1539 src_x += (TILEX / 2 - MICRO_TILEX / 2);
1540 src_y += (TILEY / 2 - MICRO_TILEY / 2);
1543 *bitmap = src_bitmap;
1548 void DrawMicroElement(int xpos, int ypos, int element)
1552 int graphic = el2preimg(element);
1554 getMicroGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
1555 BlitBitmap(src_bitmap, drawto, src_x, src_y, MICRO_TILEX, MICRO_TILEY,
1563 SetDrawBackgroundMask(REDRAW_NONE);
1566 for(x=BX1; x<=BX2; x++)
1567 for(y=BY1; y<=BY2; y++)
1568 DrawScreenField(x, y);
1570 redraw_mask |= REDRAW_FIELD;
1573 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
1577 for(x=0; x<size_x; x++)
1578 for(y=0; y<size_y; y++)
1579 DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
1581 redraw_mask |= REDRAW_FIELD;
1584 static void DrawMicroLevelExt(int xpos, int ypos, int from_x, int from_y)
1588 DrawBackground(xpos, ypos, MICROLEV_XSIZE, MICROLEV_YSIZE);
1590 if (lev_fieldx < STD_LEV_FIELDX)
1591 xpos += (STD_LEV_FIELDX - lev_fieldx) / 2 * MICRO_TILEX;
1592 if (lev_fieldy < STD_LEV_FIELDY)
1593 ypos += (STD_LEV_FIELDY - lev_fieldy) / 2 * MICRO_TILEY;
1595 xpos += MICRO_TILEX;
1596 ypos += MICRO_TILEY;
1598 for(x=-1; x<=STD_LEV_FIELDX; x++)
1600 for(y=-1; y<=STD_LEV_FIELDY; y++)
1602 int lx = from_x + x, ly = from_y + y;
1604 if (lx >= 0 && lx < lev_fieldx && ly >= 0 && ly < lev_fieldy)
1605 DrawMicroElement(xpos + x * MICRO_TILEX, ypos + y * MICRO_TILEY,
1607 else if (lx >= -1 && lx < lev_fieldx+1 && ly >= -1 && ly < lev_fieldy+1
1608 && BorderElement != EL_EMPTY)
1609 DrawMicroElement(xpos + x * MICRO_TILEX, ypos + y * MICRO_TILEY,
1610 getBorderElement(lx, ly));
1614 redraw_mask |= REDRAW_MICROLEVEL;
1617 #define MICROLABEL_EMPTY 0
1618 #define MICROLABEL_LEVEL_NAME 1
1619 #define MICROLABEL_CREATED_BY 2
1620 #define MICROLABEL_LEVEL_AUTHOR 3
1621 #define MICROLABEL_IMPORTED_FROM 4
1622 #define MICROLABEL_LEVEL_IMPORT_INFO 5
1624 #define MAX_MICROLABEL_SIZE (SXSIZE / FONT4_XSIZE)
1626 static void DrawMicroLevelLabelExt(int mode)
1628 char label_text[MAX_MICROLABEL_SIZE + 1];
1630 DrawBackground(SX, MICROLABEL_YPOS, SXSIZE, FONT4_YSIZE);
1632 strncpy(label_text, (mode == MICROLABEL_LEVEL_NAME ? level.name :
1633 mode == MICROLABEL_CREATED_BY ? "created by" :
1634 mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
1635 mode == MICROLABEL_IMPORTED_FROM ? "imported from" :
1636 mode == MICROLABEL_LEVEL_IMPORT_INFO ?
1637 leveldir_current->imported_from : ""),
1638 MAX_MICROLABEL_SIZE);
1639 label_text[MAX_MICROLABEL_SIZE] = '\0';
1641 if (strlen(label_text) > 0)
1643 int lxpos = SX + (SXSIZE - strlen(label_text) * FONT4_XSIZE) / 2;
1644 int lypos = MICROLABEL_YPOS;
1646 DrawText(lxpos, lypos, label_text, FS_SMALL, FC_SPECIAL2);
1649 redraw_mask |= REDRAW_MICROLEVEL;
1652 void DrawMicroLevel(int xpos, int ypos, boolean restart)
1654 static unsigned long scroll_delay = 0;
1655 static unsigned long label_delay = 0;
1656 static int from_x, from_y, scroll_direction;
1657 static int label_state, label_counter;
1661 from_x = from_y = 0;
1662 scroll_direction = MV_RIGHT;
1666 DrawMicroLevelExt(xpos, ypos, from_x, from_y);
1667 DrawMicroLevelLabelExt(label_state);
1669 /* initialize delay counters */
1670 DelayReached(&scroll_delay, 0);
1671 DelayReached(&label_delay, 0);
1676 /* scroll micro level, if needed */
1677 if ((lev_fieldx > STD_LEV_FIELDX || lev_fieldy > STD_LEV_FIELDY) &&
1678 DelayReached(&scroll_delay, MICROLEVEL_SCROLL_DELAY))
1680 switch (scroll_direction)
1686 scroll_direction = MV_UP;
1690 if (from_x < lev_fieldx - STD_LEV_FIELDX)
1693 scroll_direction = MV_DOWN;
1700 scroll_direction = MV_RIGHT;
1704 if (from_y < lev_fieldy - STD_LEV_FIELDY)
1707 scroll_direction = MV_LEFT;
1714 DrawMicroLevelExt(xpos, ypos, from_x, from_y);
1717 /* redraw micro level label, if needed */
1718 if (strcmp(level.name, NAMELESS_LEVEL_NAME) != 0 &&
1719 strcmp(level.author, ANONYMOUS_NAME) != 0 &&
1720 strcmp(level.author, leveldir_current->name) != 0 &&
1721 DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
1723 int max_label_counter = 23;
1725 if (leveldir_current->imported_from != NULL)
1726 max_label_counter += 14;
1728 label_counter = (label_counter + 1) % max_label_counter;
1729 label_state = (label_counter >= 0 && label_counter <= 7 ?
1730 MICROLABEL_LEVEL_NAME :
1731 label_counter >= 9 && label_counter <= 12 ?
1732 MICROLABEL_CREATED_BY :
1733 label_counter >= 14 && label_counter <= 21 ?
1734 MICROLABEL_LEVEL_AUTHOR :
1735 label_counter >= 23 && label_counter <= 26 ?
1736 MICROLABEL_IMPORTED_FROM :
1737 label_counter >= 28 && label_counter <= 35 ?
1738 MICROLABEL_LEVEL_IMPORT_INFO : MICROLABEL_EMPTY);
1739 DrawMicroLevelLabelExt(label_state);
1743 int REQ_in_range(int x, int y)
1745 if (y > DY+249 && y < DY+278)
1747 if (x > DX+1 && x < DX+48)
1749 else if (x > DX+51 && x < DX+98)
1755 #define MAX_REQUEST_LINES 13
1756 #define MAX_REQUEST_LINE_LEN 7
1758 boolean Request(char *text, unsigned int req_state)
1760 int mx, my, ty, result = -1;
1761 unsigned int old_door_state;
1763 #if defined(PLATFORM_UNIX)
1764 /* pause network game while waiting for request to answer */
1765 if (options.network &&
1766 game_status == PLAYING &&
1767 req_state & REQUEST_WAIT_FOR)
1768 SendToServer_PausePlaying();
1771 old_door_state = GetDoorState();
1775 CloseDoor(DOOR_CLOSE_1);
1777 /* save old door content */
1778 BlitBitmap(bitmap_db_door, bitmap_db_door,
1779 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
1780 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
1782 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
1784 /* clear door drawing field */
1785 DrawBackground(DX, DY, DXSIZE, DYSIZE);
1787 /* write text for request */
1788 for(ty=0; ty < MAX_REQUEST_LINES; ty++)
1790 char text_line[MAX_REQUEST_LINE_LEN + 1];
1796 for(tl=0,tx=0; tx < MAX_REQUEST_LINE_LEN; tl++,tx++)
1799 if (!tc || tc == ' ')
1810 strncpy(text_line, text, tl);
1813 DrawText(DX + 50 - (tl * 14)/2, DY + 8 + ty * 16,
1814 text_line, FS_SMALL, FC_YELLOW);
1816 text += tl + (tc == ' ' ? 1 : 0);
1819 if (req_state & REQ_ASK)
1821 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
1822 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
1824 else if (req_state & REQ_CONFIRM)
1826 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
1828 else if (req_state & REQ_PLAYER)
1830 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
1831 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
1832 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
1833 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
1836 /* copy request gadgets to door backbuffer */
1837 BlitBitmap(drawto, bitmap_db_door,
1838 DX, DY, DXSIZE, DYSIZE,
1839 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
1841 OpenDoor(DOOR_OPEN_1);
1847 if (!(req_state & REQUEST_WAIT_FOR))
1849 SetDrawBackgroundMask(REDRAW_FIELD);
1854 if (game_status != MAINMENU)
1857 button_status = MB_RELEASED;
1859 request_gadget_id = -1;
1861 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
1873 case EVENT_BUTTONPRESS:
1874 case EVENT_BUTTONRELEASE:
1875 case EVENT_MOTIONNOTIFY:
1877 if (event.type == EVENT_MOTIONNOTIFY)
1879 if (!PointerInWindow(window))
1880 continue; /* window and pointer are on different screens */
1885 motion_status = TRUE;
1886 mx = ((MotionEvent *) &event)->x;
1887 my = ((MotionEvent *) &event)->y;
1891 motion_status = FALSE;
1892 mx = ((ButtonEvent *) &event)->x;
1893 my = ((ButtonEvent *) &event)->y;
1894 if (event.type == EVENT_BUTTONPRESS)
1895 button_status = ((ButtonEvent *) &event)->button;
1897 button_status = MB_RELEASED;
1900 /* this sets 'request_gadget_id' */
1901 HandleGadgets(mx, my, button_status);
1903 switch(request_gadget_id)
1905 case TOOL_CTRL_ID_YES:
1908 case TOOL_CTRL_ID_NO:
1911 case TOOL_CTRL_ID_CONFIRM:
1912 result = TRUE | FALSE;
1915 case TOOL_CTRL_ID_PLAYER_1:
1918 case TOOL_CTRL_ID_PLAYER_2:
1921 case TOOL_CTRL_ID_PLAYER_3:
1924 case TOOL_CTRL_ID_PLAYER_4:
1935 case EVENT_KEYPRESS:
1936 switch(GetEventKey((KeyEvent *)&event, TRUE))
1949 if (req_state & REQ_PLAYER)
1953 case EVENT_KEYRELEASE:
1954 ClearPlayerAction();
1958 HandleOtherEvents(&event);
1962 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
1964 int joy = AnyJoystick();
1966 if (joy & JOY_BUTTON_1)
1968 else if (joy & JOY_BUTTON_2)
1974 /* don't eat all CPU time */
1978 if (game_status != MAINMENU)
1983 if (!(req_state & REQ_STAY_OPEN))
1985 CloseDoor(DOOR_CLOSE_1);
1987 if (!(req_state & REQ_STAY_CLOSED) && (old_door_state & DOOR_OPEN_1))
1989 BlitBitmap(bitmap_db_door, bitmap_db_door,
1990 DOOR_GFX_PAGEX2,DOOR_GFX_PAGEY1, DXSIZE,DYSIZE,
1991 DOOR_GFX_PAGEX1,DOOR_GFX_PAGEY1);
1992 OpenDoor(DOOR_OPEN_1);
1998 SetDrawBackgroundMask(REDRAW_FIELD);
2000 #if defined(PLATFORM_UNIX)
2001 /* continue network game after request */
2002 if (options.network &&
2003 game_status == PLAYING &&
2004 req_state & REQUEST_WAIT_FOR)
2005 SendToServer_ContinuePlaying();
2011 unsigned int OpenDoor(unsigned int door_state)
2013 unsigned int new_door_state;
2015 if (door_state & DOOR_COPY_BACK)
2017 BlitBitmap(bitmap_db_door, bitmap_db_door,
2018 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE + VYSIZE,
2019 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2020 door_state &= ~DOOR_COPY_BACK;
2023 new_door_state = MoveDoor(door_state);
2025 return(new_door_state);
2028 unsigned int CloseDoor(unsigned int door_state)
2030 unsigned int new_door_state;
2032 BlitBitmap(backbuffer, bitmap_db_door,
2033 DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2034 BlitBitmap(backbuffer, bitmap_db_door,
2035 VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
2037 new_door_state = MoveDoor(door_state);
2039 return(new_door_state);
2042 unsigned int GetDoorState()
2044 return MoveDoor(DOOR_GET_STATE);
2047 unsigned int SetDoorState(unsigned int door_state)
2049 return MoveDoor(door_state | DOOR_SET_STATE);
2052 unsigned int MoveDoor(unsigned int door_state)
2054 static int door1 = DOOR_OPEN_1;
2055 static int door2 = DOOR_CLOSE_2;
2056 static unsigned long door_delay = 0;
2057 int x, start, stepsize = 2;
2058 unsigned long door_delay_value = stepsize * 5;
2060 if (door_state == DOOR_GET_STATE)
2061 return(door1 | door2);
2063 if (door_state & DOOR_SET_STATE)
2065 if (door_state & DOOR_ACTION_1)
2066 door1 = door_state & DOOR_ACTION_1;
2067 if (door_state & DOOR_ACTION_2)
2068 door2 = door_state & DOOR_ACTION_2;
2070 return(door1 | door2);
2073 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
2074 door_state &= ~DOOR_OPEN_1;
2075 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
2076 door_state &= ~DOOR_CLOSE_1;
2077 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
2078 door_state &= ~DOOR_OPEN_2;
2079 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
2080 door_state &= ~DOOR_CLOSE_2;
2082 if (setup.quick_doors)
2085 door_delay_value = 0;
2087 StopSound(SND_MENU_DOOR_OPENING);
2088 StopSound(SND_MENU_DOOR_CLOSING);
2091 if (global.autoplay_leveldir)
2093 door_state |= DOOR_NO_DELAY;
2094 door_state &= ~DOOR_CLOSE_ALL;
2097 if (door_state & DOOR_ACTION)
2099 if (!(door_state & DOOR_NO_DELAY))
2101 /* opening door sound has priority over simultaneously closing door */
2102 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
2103 PlaySoundStereo(SND_MENU_DOOR_OPENING, SOUND_MAX_RIGHT);
2104 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
2105 PlaySoundStereo(SND_MENU_DOOR_CLOSING, SOUND_MAX_RIGHT);
2108 start = ((door_state & DOOR_NO_DELAY) ? DXSIZE : 0);
2110 for(x=start; x<=DXSIZE; x+=stepsize)
2112 Bitmap *bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
2113 GC gc = bitmap->stored_clip_gc;
2115 if (!(door_state & DOOR_NO_DELAY))
2116 WaitUntilDelayReached(&door_delay, door_delay_value);
2118 if (door_state & DOOR_ACTION_1)
2120 int i = (door_state & DOOR_OPEN_1 ? DXSIZE-x : x);
2121 int j = (DXSIZE - i) / 3;
2123 BlitBitmap(bitmap_db_door, drawto,
2124 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + i/2,
2125 DXSIZE,DYSIZE - i/2, DX, DY);
2127 ClearRectangle(drawto, DX, DY + DYSIZE - i/2, DXSIZE,i/2);
2129 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2130 BlitBitmapMasked(bitmap, drawto,
2131 DXSIZE, DOOR_GFX_PAGEY1, i, 77,
2132 DX + DXSIZE - i, DY + j);
2133 BlitBitmapMasked(bitmap, drawto,
2134 DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63,
2135 DX + DXSIZE - i, DY + 140 + j);
2136 SetClipOrigin(bitmap, gc, DX - DXSIZE + i, DY - (DOOR_GFX_PAGEY1 + j));
2137 BlitBitmapMasked(bitmap, drawto,
2138 DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j,
2140 BlitBitmapMasked(bitmap, drawto,
2141 DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63,
2144 BlitBitmapMasked(bitmap, drawto,
2145 DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
2147 BlitBitmapMasked(bitmap, drawto,
2148 DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
2150 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2151 BlitBitmapMasked(bitmap, drawto,
2152 DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
2153 DX + DXSIZE - i, DY + 77 + j);
2154 BlitBitmapMasked(bitmap, drawto,
2155 DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
2156 DX + DXSIZE - i, DY + 203 + j);
2158 redraw_mask |= REDRAW_DOOR_1;
2161 if (door_state & DOOR_ACTION_2)
2163 int i = (door_state & DOOR_OPEN_2 ? VXSIZE - x : x);
2164 int j = (VXSIZE - i) / 3;
2166 BlitBitmap(bitmap_db_door, drawto,
2167 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + i/2,
2168 VXSIZE, VYSIZE - i/2, VX, VY);
2170 ClearRectangle(drawto, VX, VY + VYSIZE-i/2, VXSIZE, i/2);
2172 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2173 BlitBitmapMasked(bitmap, drawto,
2174 VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2,
2175 VX + VXSIZE-i, VY+j);
2176 SetClipOrigin(bitmap, gc,
2177 VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
2178 BlitBitmapMasked(bitmap, drawto,
2179 VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j,
2182 BlitBitmapMasked(bitmap, drawto,
2183 VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2,
2184 i, VYSIZE / 2, VX, VY + VYSIZE / 2 - j);
2185 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2186 BlitBitmapMasked(bitmap, drawto,
2187 VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2,
2189 VX + VXSIZE - i, VY + VYSIZE / 2 + j);
2191 redraw_mask |= REDRAW_DOOR_2;
2196 if (game_status == MAINMENU)
2201 if (setup.quick_doors)
2203 StopSound(SND_MENU_DOOR_OPENING);
2204 StopSound(SND_MENU_DOOR_CLOSING);
2207 if (door_state & DOOR_ACTION_1)
2208 door1 = door_state & DOOR_ACTION_1;
2209 if (door_state & DOOR_ACTION_2)
2210 door2 = door_state & DOOR_ACTION_2;
2212 return (door1 | door2);
2215 void DrawSpecialEditorDoor()
2217 /* draw bigger toolbox window */
2218 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
2219 DOOR_GFX_PAGEX7, 0, EXSIZE + 8, 8,
2221 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
2222 EX - 4, VY - 4, EXSIZE + 8, EYSIZE - VYSIZE + 4,
2225 redraw_mask |= REDRAW_ALL;
2228 void UndrawSpecialEditorDoor()
2230 /* draw normal tape recorder window */
2231 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
2232 EX - 4, EY - 12, EXSIZE + 8, EYSIZE - VYSIZE + 12,
2235 redraw_mask |= REDRAW_ALL;
2239 int ReadPixel(DrawBuffer *bitmap, int x, int y)
2241 XImage *pixel_image;
2242 unsigned long pixel_value;
2244 pixel_image = XGetImage(display, bitmap->drawable,
2245 x, y, 1, 1, AllPlanes, ZPixmap);
2246 pixel_value = XGetPixel(pixel_image, 0, 0);
2248 XDestroyImage(pixel_image);
2254 /* ---------- new tool button stuff ---------------------------------------- */
2256 /* graphic position values for tool buttons */
2257 #define TOOL_BUTTON_YES_XPOS 2
2258 #define TOOL_BUTTON_YES_YPOS 250
2259 #define TOOL_BUTTON_YES_GFX_YPOS 0
2260 #define TOOL_BUTTON_YES_XSIZE 46
2261 #define TOOL_BUTTON_YES_YSIZE 28
2262 #define TOOL_BUTTON_NO_XPOS 52
2263 #define TOOL_BUTTON_NO_YPOS TOOL_BUTTON_YES_YPOS
2264 #define TOOL_BUTTON_NO_GFX_YPOS TOOL_BUTTON_YES_GFX_YPOS
2265 #define TOOL_BUTTON_NO_XSIZE TOOL_BUTTON_YES_XSIZE
2266 #define TOOL_BUTTON_NO_YSIZE TOOL_BUTTON_YES_YSIZE
2267 #define TOOL_BUTTON_CONFIRM_XPOS TOOL_BUTTON_YES_XPOS
2268 #define TOOL_BUTTON_CONFIRM_YPOS TOOL_BUTTON_YES_YPOS
2269 #define TOOL_BUTTON_CONFIRM_GFX_YPOS 30
2270 #define TOOL_BUTTON_CONFIRM_XSIZE 96
2271 #define TOOL_BUTTON_CONFIRM_YSIZE TOOL_BUTTON_YES_YSIZE
2272 #define TOOL_BUTTON_PLAYER_XSIZE 30
2273 #define TOOL_BUTTON_PLAYER_YSIZE 30
2274 #define TOOL_BUTTON_PLAYER_GFX_XPOS 5
2275 #define TOOL_BUTTON_PLAYER_GFX_YPOS 185
2276 #define TOOL_BUTTON_PLAYER_XPOS (5 + TOOL_BUTTON_PLAYER_XSIZE / 2)
2277 #define TOOL_BUTTON_PLAYER_YPOS (215 - TOOL_BUTTON_PLAYER_YSIZE / 2)
2278 #define TOOL_BUTTON_PLAYER1_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2279 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2280 #define TOOL_BUTTON_PLAYER2_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2281 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2282 #define TOOL_BUTTON_PLAYER3_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2283 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2284 #define TOOL_BUTTON_PLAYER4_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2285 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2286 #define TOOL_BUTTON_PLAYER1_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2287 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2288 #define TOOL_BUTTON_PLAYER2_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2289 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2290 #define TOOL_BUTTON_PLAYER3_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2291 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2292 #define TOOL_BUTTON_PLAYER4_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2293 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2302 } toolbutton_info[NUM_TOOL_BUTTONS] =
2305 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_GFX_YPOS,
2306 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_YPOS,
2307 TOOL_BUTTON_YES_XSIZE, TOOL_BUTTON_YES_YSIZE,
2312 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_GFX_YPOS,
2313 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_YPOS,
2314 TOOL_BUTTON_NO_XSIZE, TOOL_BUTTON_NO_YSIZE,
2319 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_GFX_YPOS,
2320 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_YPOS,
2321 TOOL_BUTTON_CONFIRM_XSIZE, TOOL_BUTTON_CONFIRM_YSIZE,
2322 TOOL_CTRL_ID_CONFIRM,
2326 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2327 TOOL_BUTTON_PLAYER1_XPOS, TOOL_BUTTON_PLAYER1_YPOS,
2328 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2329 TOOL_CTRL_ID_PLAYER_1,
2333 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2334 TOOL_BUTTON_PLAYER2_XPOS, TOOL_BUTTON_PLAYER2_YPOS,
2335 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2336 TOOL_CTRL_ID_PLAYER_2,
2340 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2341 TOOL_BUTTON_PLAYER3_XPOS, TOOL_BUTTON_PLAYER3_YPOS,
2342 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2343 TOOL_CTRL_ID_PLAYER_3,
2347 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2348 TOOL_BUTTON_PLAYER4_XPOS, TOOL_BUTTON_PLAYER4_YPOS,
2349 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2350 TOOL_CTRL_ID_PLAYER_4,
2355 void CreateToolButtons()
2359 for (i=0; i<NUM_TOOL_BUTTONS; i++)
2361 Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
2362 Bitmap *deco_bitmap = None;
2363 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
2364 struct GadgetInfo *gi;
2365 unsigned long event_mask;
2366 int gd_xoffset, gd_yoffset;
2367 int gd_x1, gd_x2, gd_y;
2370 event_mask = GD_EVENT_RELEASED;
2372 gd_xoffset = toolbutton_info[i].xpos;
2373 gd_yoffset = toolbutton_info[i].ypos;
2374 gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
2375 gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
2376 gd_y = DOOR_GFX_PAGEY1 + gd_yoffset;
2378 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
2380 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
2382 getMiniGraphicSource(PLAYER_NR_GFX(IMG_PLAYER1, player_nr),
2383 &deco_bitmap, &deco_x, &deco_y);
2384 deco_xpos = (toolbutton_info[i].width - MINI_TILEX) / 2;
2385 deco_ypos = (toolbutton_info[i].height - MINI_TILEY) / 2;
2388 gi = CreateGadget(GDI_CUSTOM_ID, id,
2389 GDI_INFO_TEXT, toolbutton_info[i].infotext,
2390 GDI_X, DX + toolbutton_info[i].x,
2391 GDI_Y, DY + toolbutton_info[i].y,
2392 GDI_WIDTH, toolbutton_info[i].width,
2393 GDI_HEIGHT, toolbutton_info[i].height,
2394 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
2395 GDI_STATE, GD_BUTTON_UNPRESSED,
2396 GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
2397 GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
2398 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
2399 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
2400 GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
2401 GDI_DECORATION_SHIFTING, 1, 1,
2402 GDI_EVENT_MASK, event_mask,
2403 GDI_CALLBACK_ACTION, HandleToolButtons,
2407 Error(ERR_EXIT, "cannot create gadget");
2409 tool_gadget[id] = gi;
2413 void FreeToolButtons()
2417 for (i=0; i<NUM_TOOL_BUTTONS; i++)
2418 FreeGadget(tool_gadget[i]);
2421 static void UnmapToolButtons()
2425 for (i=0; i<NUM_TOOL_BUTTONS; i++)
2426 UnmapGadget(tool_gadget[i]);
2429 static void HandleToolButtons(struct GadgetInfo *gi)
2431 request_gadget_id = gi->custom_id;
2434 int get_next_element(int element)
2438 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
2439 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
2440 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
2441 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
2442 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
2443 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
2444 case EL_AMOEBA_DRIPPING: return EL_AMOEBA_WET;
2446 default: return element;
2450 int el_act_dir2img(int element, int action, int direction)
2452 direction = MV_DIR_BIT(direction);
2454 return element_info[element].direction_graphic[action][direction];
2457 int el_act2img(int element, int action)
2459 return element_info[element].graphic[action];
2462 int el_dir2img(int element, int direction)
2464 return el_act_dir2img(element, ACTION_DEFAULT, direction);
2467 int el2img(int element)
2469 return element_info[element].graphic[ACTION_DEFAULT];
2472 int el2edimg(int element)
2474 return element_info[element].editor_graphic;
2477 int el2preimg(int element)
2479 return element_info[element].preview_graphic;