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;
962 if (src_x + MINI_TILEX > src_bitmap->width ||
963 src_y + MINI_TILEY > src_bitmap->height)
965 /* graphic of desired size seems not to be contained in this image;
966 dirty workaround: get it from the middle of the normal sized image */
968 getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
969 src_x += (TILEX / 2 - MINI_TILEX / 2);
970 src_y += (TILEY / 2 - MINI_TILEY / 2);
973 *bitmap = src_bitmap;
978 void DrawMiniGraphicExt(DrawBuffer *d, int x, int y, int graphic)
983 getMiniGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
984 BlitBitmap(src_bitmap, d, src_x, src_y, MINI_TILEX, MINI_TILEY, x, y);
987 void DrawGraphicShifted(int x,int y, int dx,int dy, int graphic, int frame,
988 int cut_mode, int mask_mode)
997 int width = TILEX, height = TILEY;
1003 DrawGraphic(x, y, graphic, frame);
1007 if (dx || dy) /* shifted graphic */
1009 if (x < BX1) /* object enters playfield from the left */
1016 else if (x > BX2) /* object enters playfield from the right */
1022 else if (x==BX1 && dx < 0) /* object leaves playfield to the left */
1028 else if (x==BX2 && dx > 0) /* object leaves playfield to the right */
1030 else if (dx) /* general horizontal movement */
1031 MarkTileDirty(x + SIGN(dx), y);
1033 if (y < BY1) /* object enters playfield from the top */
1035 if (cut_mode==CUT_BELOW) /* object completely above top border */
1043 else if (y > BY2) /* object enters playfield from the bottom */
1049 else if (y==BY1 && dy < 0) /* object leaves playfield to the top */
1055 else if (dy > 0 && cut_mode == CUT_ABOVE)
1057 if (y == BY2) /* object completely above bottom border */
1063 MarkTileDirty(x, y + 1);
1064 } /* object leaves playfield to the bottom */
1065 else if (dy > 0 && (y == BY2 || cut_mode == CUT_BELOW))
1067 else if (dy) /* general vertical movement */
1068 MarkTileDirty(x, y + SIGN(dy));
1071 src_bitmap = graphic_info[graphic].bitmap;
1072 src_x = graphic_info[graphic].src_x;
1073 src_y = graphic_info[graphic].src_y;
1074 offset_x = graphic_info[graphic].offset_x;
1075 offset_y = graphic_info[graphic].offset_y;
1077 drawing_gc = src_bitmap->stored_clip_gc;
1079 src_x += frame * offset_x;
1080 src_y += frame * offset_y;
1085 dest_x = FX + x * TILEX + dx;
1086 dest_y = FY + y * TILEY + dy;
1089 if (!IN_SCR_FIELD(x,y))
1091 printf("DrawGraphicShifted(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
1092 printf("DrawGraphicShifted(): This should never happen!\n");
1097 if (mask_mode == USE_MASKING)
1099 SetClipOrigin(src_bitmap, drawing_gc, dest_x - src_x, dest_y - src_y);
1100 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1104 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1110 void DrawGraphicShiftedThruMask(int x, int y, int dx, int dy, int graphic,
1111 int frame, int cut_mode)
1113 DrawGraphicShifted(x,y, dx,dy, graphic, frame, cut_mode, USE_MASKING);
1116 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
1117 int cut_mode, int mask_mode)
1119 int lx = LEVELX(x), ly = LEVELY(y);
1123 if (IN_LEV_FIELD(lx, ly))
1125 SetRandomAnimationValue(lx, ly);
1127 graphic = el_act_dir2img(element, GfxAction[lx][ly], MovDir[lx][ly]);
1128 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1130 else /* border element */
1132 graphic = el2img(element);
1133 frame = getGraphicAnimationFrame(graphic, -1);
1136 if (element == EL_WALL_GROWING)
1138 boolean left_stopped = FALSE, right_stopped = FALSE;
1140 if (!IN_LEV_FIELD(lx - 1, ly) || IS_MAUER(Feld[lx - 1][ly]))
1141 left_stopped = TRUE;
1142 if (!IN_LEV_FIELD(lx + 1, ly) || IS_MAUER(Feld[lx + 1][ly]))
1143 right_stopped = TRUE;
1145 if (left_stopped && right_stopped)
1147 else if (left_stopped)
1149 graphic = IMG_WALL_GROWING_ACTIVE_RIGHT;
1150 frame = graphic_info[graphic].anim_frames - 1;
1152 else if (right_stopped)
1154 graphic = IMG_WALL_GROWING_ACTIVE_LEFT;
1155 frame = graphic_info[graphic].anim_frames - 1;
1159 else if (IS_AMOEBOID(element) || element == EL_AMOEBA_DRIPPING)
1161 graphic = (element == EL_BD_AMOEBA ? IMG_BD_AMOEBA_PART1 :
1162 element == EL_AMOEBA_WET ? IMG_AMOEBA_WET_PART1 :
1163 element == EL_AMOEBA_DRY ? IMG_AMOEBA_DRY_PART1 :
1164 element == EL_AMOEBA_FULL ? IMG_AMOEBA_FULL_PART1 :
1165 IMG_AMOEBA_DEAD_PART1);
1167 graphic += (x + 2 * y + 4) % 4;
1172 if (IS_AMOEBOID(element) || element == EL_AMOEBA_DRIPPING)
1174 if (Feld[lx][ly] == EL_AMOEBA_DRIPPING)
1175 printf("---> %d -> %d / %d [%d]\n",
1176 element, graphic, frame, GfxRandom[lx][ly]);
1181 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, mask_mode);
1182 else if (mask_mode == USE_MASKING)
1183 DrawGraphicThruMask(x, y, graphic, frame);
1185 DrawGraphic(x, y, graphic, frame);
1188 void DrawLevelElementExt(int x, int y, int dx, int dy, int element,
1189 int cut_mode, int mask_mode)
1191 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1192 DrawScreenElementExt(SCREENX(x), SCREENY(y), dx, dy, element,
1193 cut_mode, mask_mode);
1196 void DrawScreenElementShifted(int x, int y, int dx, int dy, int element,
1199 DrawScreenElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1202 void DrawLevelElementShifted(int x, int y, int dx, int dy, int element,
1205 DrawLevelElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1209 void DrawOldScreenElementThruMask(int x, int y, int element)
1211 DrawOldScreenElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1214 void DrawScreenElementThruMask(int x, int y, int element)
1216 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1220 void DrawLevelElementThruMask(int x, int y, int element)
1222 DrawLevelElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1225 void DrawLevelFieldThruMask(int x, int y)
1227 DrawLevelElementExt(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
1230 void DrawCrumbledSand(int x, int y)
1234 int i, width, height, cx,cy;
1235 int lx = LEVELX(x), ly = LEVELY(y);
1236 int element, graphic;
1238 static int xy[4][2] =
1246 if (!IN_LEV_FIELD(lx, ly))
1249 element = Feld[lx][ly];
1251 if (element == EL_SAND ||
1252 element == EL_LANDMINE ||
1253 element == EL_TRAP ||
1254 element == EL_TRAP_ACTIVE)
1256 if (!IN_SCR_FIELD(x, y))
1259 graphic = IMG_SAND_CRUMBLED;
1261 src_bitmap = graphic_info[graphic].bitmap;
1262 src_x = graphic_info[graphic].src_x;
1263 src_y = graphic_info[graphic].src_y;
1269 lxx = lx + xy[i][0];
1270 lyy = ly + xy[i][1];
1271 if (!IN_LEV_FIELD(lxx, lyy))
1272 element = EL_STEELWALL;
1274 element = Feld[lxx][lyy];
1276 if (element == EL_SAND ||
1277 element == EL_LANDMINE ||
1278 element == EL_TRAP ||
1279 element == EL_TRAP_ACTIVE)
1282 if (i == 1 || i == 2)
1286 cx = (i == 2 ? TILEX - snip : 0);
1294 cy = (i == 3 ? TILEY - snip : 0);
1297 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1298 width, height, FX + x * TILEX + cx, FY + y * TILEY + cy);
1301 MarkTileDirty(x, y);
1305 graphic = IMG_SAND_CRUMBLED;
1307 src_bitmap = graphic_info[graphic].bitmap;
1308 src_x = graphic_info[graphic].src_x;
1309 src_y = graphic_info[graphic].src_y;
1313 int xx, yy, lxx, lyy;
1317 lxx = lx + xy[i][0];
1318 lyy = ly + xy[i][1];
1320 if (!IN_LEV_FIELD(lxx, lyy) ||
1321 (Feld[lxx][lyy] != EL_SAND &&
1322 Feld[lxx][lyy] != EL_LANDMINE &&
1323 Feld[lxx][lyy] != EL_TRAP &&
1324 Feld[lxx][lyy] != EL_TRAP_ACTIVE) ||
1325 !IN_SCR_FIELD(xx, yy))
1328 if (i == 1 || i == 2)
1332 cx = (i == 1 ? TILEX - snip : 0);
1340 cy = (i==0 ? TILEY-snip : 0);
1343 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1344 width, height, FX + xx * TILEX + cx, FY + yy * TILEY + cy);
1346 MarkTileDirty(xx, yy);
1351 static int getBorderElement(int x, int y)
1355 { EL_STEELWALL_TOPLEFT, EL_INVISIBLE_STEELWALL_TOPLEFT },
1356 { EL_STEELWALL_TOPRIGHT, EL_INVISIBLE_STEELWALL_TOPRIGHT },
1357 { EL_STEELWALL_BOTTOMLEFT, EL_INVISIBLE_STEELWALL_BOTTOMLEFT },
1358 { EL_STEELWALL_BOTTOMRIGHT, EL_INVISIBLE_STEELWALL_BOTTOMRIGHT },
1359 { EL_STEELWALL_VERTICAL, EL_INVISIBLE_STEELWALL_VERTICAL },
1360 { EL_STEELWALL_HORIZONTAL, EL_INVISIBLE_STEELWALL_HORIZONTAL },
1361 { EL_STEELWALL, EL_INVISIBLE_STEELWALL }
1363 int steel_type = (BorderElement == EL_STEELWALL ? 0 : 1);
1364 int steel_position = (x == -1 && y == -1 ? 0 :
1365 x == lev_fieldx && y == -1 ? 1 :
1366 x == -1 && y == lev_fieldy ? 2 :
1367 x == lev_fieldx && y == lev_fieldy ? 3 :
1368 x == -1 || x == lev_fieldx ? 4 :
1369 y == -1 || y == lev_fieldy ? 5 : 6);
1371 return border[steel_position][steel_type];
1374 void DrawScreenElement(int x, int y, int element)
1376 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
1377 DrawCrumbledSand(x, y);
1380 void DrawLevelElement(int x, int y, int element)
1382 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1383 DrawScreenElement(SCREENX(x), SCREENY(y), element);
1386 void DrawScreenField(int x, int y)
1388 int lx = LEVELX(x), ly = LEVELY(y);
1389 int element, content;
1391 if (!IN_LEV_FIELD(lx, ly))
1393 if (lx < -1 || lx > lev_fieldx || ly < -1 || ly > lev_fieldy)
1396 element = getBorderElement(lx, ly);
1398 DrawScreenElement(x, y, element);
1402 element = Feld[lx][ly];
1403 content = Store[lx][ly];
1405 if (IS_MOVING(lx, ly))
1407 int horiz_move = (MovDir[lx][ly] == MV_LEFT || MovDir[lx][ly] == MV_RIGHT);
1408 boolean cut_mode = NO_CUTTING;
1410 if (element == EL_QUICKSAND_EMPTYING ||
1411 element == EL_MAGIC_WALL_EMPTYING ||
1412 element == EL_BD_MAGIC_WALL_EMPTYING ||
1413 element == EL_AMOEBA_DRIPPING)
1414 cut_mode = CUT_ABOVE;
1415 else if (element == EL_QUICKSAND_FILLING ||
1416 element == EL_MAGIC_WALL_FILLING ||
1417 element == EL_BD_MAGIC_WALL_FILLING)
1418 cut_mode = CUT_BELOW;
1420 if (cut_mode == CUT_ABOVE)
1421 DrawScreenElementShifted(x, y, 0, 0, element, NO_CUTTING);
1423 DrawScreenElement(x, y, EL_EMPTY);
1426 DrawScreenElementShifted(x, y, MovPos[lx][ly], 0, element, NO_CUTTING);
1427 else if (cut_mode == NO_CUTTING)
1428 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], element, cut_mode);
1430 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], content, cut_mode);
1432 if (content == EL_ACID)
1433 DrawLevelElementThruMask(lx, ly + 1, EL_ACID);
1435 else if (IS_BLOCKED(lx, ly))
1440 boolean cut_mode = NO_CUTTING;
1441 int element_old, content_old;
1443 Blocked2Moving(lx, ly, &oldx, &oldy);
1446 horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
1447 MovDir[oldx][oldy] == MV_RIGHT);
1449 element_old = Feld[oldx][oldy];
1450 content_old = Store[oldx][oldy];
1452 if (element_old == EL_QUICKSAND_EMPTYING ||
1453 element_old == EL_MAGIC_WALL_EMPTYING ||
1454 element_old == EL_BD_MAGIC_WALL_EMPTYING ||
1455 element_old == EL_AMOEBA_DRIPPING)
1456 cut_mode = CUT_ABOVE;
1458 DrawScreenElement(x, y, EL_EMPTY);
1461 DrawScreenElementShifted(sx, sy, MovPos[oldx][oldy], 0, element_old,
1463 else if (cut_mode == NO_CUTTING)
1464 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], element_old,
1467 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], content_old,
1470 else if (IS_DRAWABLE(element))
1471 DrawScreenElement(x, y, element);
1473 DrawScreenElement(x, y, EL_EMPTY);
1476 void DrawLevelField(int x, int y)
1478 if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1479 DrawScreenField(SCREENX(x), SCREENY(y));
1480 else if (IS_MOVING(x, y))
1484 Moving2Blocked(x, y, &newx, &newy);
1485 if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
1486 DrawScreenField(SCREENX(newx), SCREENY(newy));
1488 else if (IS_BLOCKED(x, y))
1492 Blocked2Moving(x, y, &oldx, &oldy);
1493 if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
1494 DrawScreenField(SCREENX(oldx), SCREENY(oldy));
1498 void DrawMiniElement(int x, int y, int element)
1502 graphic = el2edimg(element);
1503 DrawMiniGraphic(x, y, graphic);
1506 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
1508 int x = sx + scroll_x, y = sy + scroll_y;
1510 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
1511 DrawMiniElement(sx, sy, EL_EMPTY);
1512 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
1513 DrawMiniElement(sx, sy, Feld[x][y]);
1515 DrawMiniGraphic(sx, sy, el2edimg(getBorderElement(x, y)));
1518 void getMicroGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
1520 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
1521 int mini_startx = src_bitmap->width * 3 / 4;
1522 int mini_starty = src_bitmap->height * 2 / 3;
1523 int src_x = mini_startx + graphic_info[graphic].src_x / 8;
1524 int src_y = mini_starty + graphic_info[graphic].src_y / 8;
1526 if (src_x + MICRO_TILEX > src_bitmap->width ||
1527 src_y + MICRO_TILEY > src_bitmap->height)
1529 /* graphic of desired size seems not to be contained in this image;
1530 dirty workaround: get it from the middle of the normal sized image */
1532 getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
1533 src_x += (TILEX / 2 - MICRO_TILEX / 2);
1534 src_y += (TILEY / 2 - MICRO_TILEY / 2);
1537 *bitmap = src_bitmap;
1542 void DrawMicroElement(int xpos, int ypos, int element)
1546 int graphic = el2preimg(element);
1548 getMicroGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
1549 BlitBitmap(src_bitmap, drawto, src_x, src_y, MICRO_TILEX, MICRO_TILEY,
1557 SetDrawBackgroundMask(REDRAW_NONE);
1560 for(x=BX1; x<=BX2; x++)
1561 for(y=BY1; y<=BY2; y++)
1562 DrawScreenField(x, y);
1564 redraw_mask |= REDRAW_FIELD;
1567 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
1571 for(x=0; x<size_x; x++)
1572 for(y=0; y<size_y; y++)
1573 DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
1575 redraw_mask |= REDRAW_FIELD;
1578 static void DrawMicroLevelExt(int xpos, int ypos, int from_x, int from_y)
1582 DrawBackground(xpos, ypos, MICROLEV_XSIZE, MICROLEV_YSIZE);
1584 if (lev_fieldx < STD_LEV_FIELDX)
1585 xpos += (STD_LEV_FIELDX - lev_fieldx) / 2 * MICRO_TILEX;
1586 if (lev_fieldy < STD_LEV_FIELDY)
1587 ypos += (STD_LEV_FIELDY - lev_fieldy) / 2 * MICRO_TILEY;
1589 xpos += MICRO_TILEX;
1590 ypos += MICRO_TILEY;
1592 for(x=-1; x<=STD_LEV_FIELDX; x++)
1594 for(y=-1; y<=STD_LEV_FIELDY; y++)
1596 int lx = from_x + x, ly = from_y + y;
1598 if (lx >= 0 && lx < lev_fieldx && ly >= 0 && ly < lev_fieldy)
1599 DrawMicroElement(xpos + x * MICRO_TILEX, ypos + y * MICRO_TILEY,
1601 else if (lx >= -1 && lx < lev_fieldx+1 && ly >= -1 && ly < lev_fieldy+1
1602 && BorderElement != EL_EMPTY)
1603 DrawMicroElement(xpos + x * MICRO_TILEX, ypos + y * MICRO_TILEY,
1604 getBorderElement(lx, ly));
1608 redraw_mask |= REDRAW_MICROLEVEL;
1611 #define MICROLABEL_EMPTY 0
1612 #define MICROLABEL_LEVEL_NAME 1
1613 #define MICROLABEL_CREATED_BY 2
1614 #define MICROLABEL_LEVEL_AUTHOR 3
1615 #define MICROLABEL_IMPORTED_FROM 4
1616 #define MICROLABEL_LEVEL_IMPORT_INFO 5
1618 #define MAX_MICROLABEL_SIZE (SXSIZE / FONT4_XSIZE)
1620 static void DrawMicroLevelLabelExt(int mode)
1622 char label_text[MAX_MICROLABEL_SIZE + 1];
1624 DrawBackground(SX, MICROLABEL_YPOS, SXSIZE, FONT4_YSIZE);
1626 strncpy(label_text, (mode == MICROLABEL_LEVEL_NAME ? level.name :
1627 mode == MICROLABEL_CREATED_BY ? "created by" :
1628 mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
1629 mode == MICROLABEL_IMPORTED_FROM ? "imported from" :
1630 mode == MICROLABEL_LEVEL_IMPORT_INFO ?
1631 leveldir_current->imported_from : ""),
1632 MAX_MICROLABEL_SIZE);
1633 label_text[MAX_MICROLABEL_SIZE] = '\0';
1635 if (strlen(label_text) > 0)
1637 int lxpos = SX + (SXSIZE - strlen(label_text) * FONT4_XSIZE) / 2;
1638 int lypos = MICROLABEL_YPOS;
1640 DrawText(lxpos, lypos, label_text, FS_SMALL, FC_SPECIAL2);
1643 redraw_mask |= REDRAW_MICROLEVEL;
1646 void DrawMicroLevel(int xpos, int ypos, boolean restart)
1648 static unsigned long scroll_delay = 0;
1649 static unsigned long label_delay = 0;
1650 static int from_x, from_y, scroll_direction;
1651 static int label_state, label_counter;
1655 from_x = from_y = 0;
1656 scroll_direction = MV_RIGHT;
1660 DrawMicroLevelExt(xpos, ypos, from_x, from_y);
1661 DrawMicroLevelLabelExt(label_state);
1663 /* initialize delay counters */
1664 DelayReached(&scroll_delay, 0);
1665 DelayReached(&label_delay, 0);
1670 /* scroll micro level, if needed */
1671 if ((lev_fieldx > STD_LEV_FIELDX || lev_fieldy > STD_LEV_FIELDY) &&
1672 DelayReached(&scroll_delay, MICROLEVEL_SCROLL_DELAY))
1674 switch (scroll_direction)
1680 scroll_direction = MV_UP;
1684 if (from_x < lev_fieldx - STD_LEV_FIELDX)
1687 scroll_direction = MV_DOWN;
1694 scroll_direction = MV_RIGHT;
1698 if (from_y < lev_fieldy - STD_LEV_FIELDY)
1701 scroll_direction = MV_LEFT;
1708 DrawMicroLevelExt(xpos, ypos, from_x, from_y);
1711 /* redraw micro level label, if needed */
1712 if (strcmp(level.name, NAMELESS_LEVEL_NAME) != 0 &&
1713 strcmp(level.author, ANONYMOUS_NAME) != 0 &&
1714 strcmp(level.author, leveldir_current->name) != 0 &&
1715 DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
1717 int max_label_counter = 23;
1719 if (leveldir_current->imported_from != NULL)
1720 max_label_counter += 14;
1722 label_counter = (label_counter + 1) % max_label_counter;
1723 label_state = (label_counter >= 0 && label_counter <= 7 ?
1724 MICROLABEL_LEVEL_NAME :
1725 label_counter >= 9 && label_counter <= 12 ?
1726 MICROLABEL_CREATED_BY :
1727 label_counter >= 14 && label_counter <= 21 ?
1728 MICROLABEL_LEVEL_AUTHOR :
1729 label_counter >= 23 && label_counter <= 26 ?
1730 MICROLABEL_IMPORTED_FROM :
1731 label_counter >= 28 && label_counter <= 35 ?
1732 MICROLABEL_LEVEL_IMPORT_INFO : MICROLABEL_EMPTY);
1733 DrawMicroLevelLabelExt(label_state);
1737 int REQ_in_range(int x, int y)
1739 if (y > DY+249 && y < DY+278)
1741 if (x > DX+1 && x < DX+48)
1743 else if (x > DX+51 && x < DX+98)
1749 #define MAX_REQUEST_LINES 13
1750 #define MAX_REQUEST_LINE_LEN 7
1752 boolean Request(char *text, unsigned int req_state)
1754 int mx, my, ty, result = -1;
1755 unsigned int old_door_state;
1757 #if defined(PLATFORM_UNIX)
1758 /* pause network game while waiting for request to answer */
1759 if (options.network &&
1760 game_status == PLAYING &&
1761 req_state & REQUEST_WAIT_FOR)
1762 SendToServer_PausePlaying();
1765 old_door_state = GetDoorState();
1769 CloseDoor(DOOR_CLOSE_1);
1771 /* save old door content */
1772 BlitBitmap(bitmap_db_door, bitmap_db_door,
1773 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
1774 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
1776 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
1778 /* clear door drawing field */
1779 DrawBackground(DX, DY, DXSIZE, DYSIZE);
1781 /* write text for request */
1782 for(ty=0; ty < MAX_REQUEST_LINES; ty++)
1784 char text_line[MAX_REQUEST_LINE_LEN + 1];
1790 for(tl=0,tx=0; tx < MAX_REQUEST_LINE_LEN; tl++,tx++)
1793 if (!tc || tc == ' ')
1804 strncpy(text_line, text, tl);
1807 DrawText(DX + 50 - (tl * 14)/2, DY + 8 + ty * 16,
1808 text_line, FS_SMALL, FC_YELLOW);
1810 text += tl + (tc == ' ' ? 1 : 0);
1813 if (req_state & REQ_ASK)
1815 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
1816 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
1818 else if (req_state & REQ_CONFIRM)
1820 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
1822 else if (req_state & REQ_PLAYER)
1824 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
1825 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
1826 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
1827 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
1830 /* copy request gadgets to door backbuffer */
1831 BlitBitmap(drawto, bitmap_db_door,
1832 DX, DY, DXSIZE, DYSIZE,
1833 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
1835 OpenDoor(DOOR_OPEN_1);
1841 if (!(req_state & REQUEST_WAIT_FOR))
1843 SetDrawBackgroundMask(REDRAW_FIELD);
1848 if (game_status != MAINMENU)
1851 button_status = MB_RELEASED;
1853 request_gadget_id = -1;
1855 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
1867 case EVENT_BUTTONPRESS:
1868 case EVENT_BUTTONRELEASE:
1869 case EVENT_MOTIONNOTIFY:
1871 if (event.type == EVENT_MOTIONNOTIFY)
1873 if (!PointerInWindow(window))
1874 continue; /* window and pointer are on different screens */
1879 motion_status = TRUE;
1880 mx = ((MotionEvent *) &event)->x;
1881 my = ((MotionEvent *) &event)->y;
1885 motion_status = FALSE;
1886 mx = ((ButtonEvent *) &event)->x;
1887 my = ((ButtonEvent *) &event)->y;
1888 if (event.type == EVENT_BUTTONPRESS)
1889 button_status = ((ButtonEvent *) &event)->button;
1891 button_status = MB_RELEASED;
1894 /* this sets 'request_gadget_id' */
1895 HandleGadgets(mx, my, button_status);
1897 switch(request_gadget_id)
1899 case TOOL_CTRL_ID_YES:
1902 case TOOL_CTRL_ID_NO:
1905 case TOOL_CTRL_ID_CONFIRM:
1906 result = TRUE | FALSE;
1909 case TOOL_CTRL_ID_PLAYER_1:
1912 case TOOL_CTRL_ID_PLAYER_2:
1915 case TOOL_CTRL_ID_PLAYER_3:
1918 case TOOL_CTRL_ID_PLAYER_4:
1929 case EVENT_KEYPRESS:
1930 switch(GetEventKey((KeyEvent *)&event, TRUE))
1943 if (req_state & REQ_PLAYER)
1947 case EVENT_KEYRELEASE:
1948 ClearPlayerAction();
1952 HandleOtherEvents(&event);
1956 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
1958 int joy = AnyJoystick();
1960 if (joy & JOY_BUTTON_1)
1962 else if (joy & JOY_BUTTON_2)
1968 /* don't eat all CPU time */
1972 if (game_status != MAINMENU)
1977 if (!(req_state & REQ_STAY_OPEN))
1979 CloseDoor(DOOR_CLOSE_1);
1981 if (!(req_state & REQ_STAY_CLOSED) && (old_door_state & DOOR_OPEN_1))
1983 BlitBitmap(bitmap_db_door, bitmap_db_door,
1984 DOOR_GFX_PAGEX2,DOOR_GFX_PAGEY1, DXSIZE,DYSIZE,
1985 DOOR_GFX_PAGEX1,DOOR_GFX_PAGEY1);
1986 OpenDoor(DOOR_OPEN_1);
1992 SetDrawBackgroundMask(REDRAW_FIELD);
1994 #if defined(PLATFORM_UNIX)
1995 /* continue network game after request */
1996 if (options.network &&
1997 game_status == PLAYING &&
1998 req_state & REQUEST_WAIT_FOR)
1999 SendToServer_ContinuePlaying();
2005 unsigned int OpenDoor(unsigned int door_state)
2007 unsigned int new_door_state;
2009 if (door_state & DOOR_COPY_BACK)
2011 BlitBitmap(bitmap_db_door, bitmap_db_door,
2012 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE + VYSIZE,
2013 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2014 door_state &= ~DOOR_COPY_BACK;
2017 new_door_state = MoveDoor(door_state);
2019 return(new_door_state);
2022 unsigned int CloseDoor(unsigned int door_state)
2024 unsigned int new_door_state;
2026 BlitBitmap(backbuffer, bitmap_db_door,
2027 DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2028 BlitBitmap(backbuffer, bitmap_db_door,
2029 VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
2031 new_door_state = MoveDoor(door_state);
2033 return(new_door_state);
2036 unsigned int GetDoorState()
2038 return MoveDoor(DOOR_GET_STATE);
2041 unsigned int SetDoorState(unsigned int door_state)
2043 return MoveDoor(door_state | DOOR_SET_STATE);
2046 unsigned int MoveDoor(unsigned int door_state)
2048 static int door1 = DOOR_OPEN_1;
2049 static int door2 = DOOR_CLOSE_2;
2050 static unsigned long door_delay = 0;
2051 int x, start, stepsize = 2;
2052 unsigned long door_delay_value = stepsize * 5;
2054 if (door_state == DOOR_GET_STATE)
2055 return(door1 | door2);
2057 if (door_state & DOOR_SET_STATE)
2059 if (door_state & DOOR_ACTION_1)
2060 door1 = door_state & DOOR_ACTION_1;
2061 if (door_state & DOOR_ACTION_2)
2062 door2 = door_state & DOOR_ACTION_2;
2064 return(door1 | door2);
2067 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
2068 door_state &= ~DOOR_OPEN_1;
2069 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
2070 door_state &= ~DOOR_CLOSE_1;
2071 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
2072 door_state &= ~DOOR_OPEN_2;
2073 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
2074 door_state &= ~DOOR_CLOSE_2;
2076 if (setup.quick_doors)
2079 door_delay_value = 0;
2081 StopSound(SND_MENU_DOOR_OPENING);
2082 StopSound(SND_MENU_DOOR_CLOSING);
2085 if (global.autoplay_leveldir)
2087 door_state |= DOOR_NO_DELAY;
2088 door_state &= ~DOOR_CLOSE_ALL;
2091 if (door_state & DOOR_ACTION)
2093 if (!(door_state & DOOR_NO_DELAY))
2095 /* opening door sound has priority over simultaneously closing door */
2096 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
2097 PlaySoundStereo(SND_MENU_DOOR_OPENING, SOUND_MAX_RIGHT);
2098 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
2099 PlaySoundStereo(SND_MENU_DOOR_CLOSING, SOUND_MAX_RIGHT);
2102 start = ((door_state & DOOR_NO_DELAY) ? DXSIZE : 0);
2104 for(x=start; x<=DXSIZE; x+=stepsize)
2106 Bitmap *bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
2107 GC gc = bitmap->stored_clip_gc;
2109 if (!(door_state & DOOR_NO_DELAY))
2110 WaitUntilDelayReached(&door_delay, door_delay_value);
2112 if (door_state & DOOR_ACTION_1)
2114 int i = (door_state & DOOR_OPEN_1 ? DXSIZE-x : x);
2115 int j = (DXSIZE - i) / 3;
2117 BlitBitmap(bitmap_db_door, drawto,
2118 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + i/2,
2119 DXSIZE,DYSIZE - i/2, DX, DY);
2121 ClearRectangle(drawto, DX, DY + DYSIZE - i/2, DXSIZE,i/2);
2123 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2124 BlitBitmapMasked(bitmap, drawto,
2125 DXSIZE, DOOR_GFX_PAGEY1, i, 77,
2126 DX + DXSIZE - i, DY + j);
2127 BlitBitmapMasked(bitmap, drawto,
2128 DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63,
2129 DX + DXSIZE - i, DY + 140 + j);
2130 SetClipOrigin(bitmap, gc, DX - DXSIZE + i, DY - (DOOR_GFX_PAGEY1 + j));
2131 BlitBitmapMasked(bitmap, drawto,
2132 DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j,
2134 BlitBitmapMasked(bitmap, drawto,
2135 DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63,
2138 BlitBitmapMasked(bitmap, drawto,
2139 DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
2141 BlitBitmapMasked(bitmap, drawto,
2142 DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
2144 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2145 BlitBitmapMasked(bitmap, drawto,
2146 DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
2147 DX + DXSIZE - i, DY + 77 + j);
2148 BlitBitmapMasked(bitmap, drawto,
2149 DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
2150 DX + DXSIZE - i, DY + 203 + j);
2152 redraw_mask |= REDRAW_DOOR_1;
2155 if (door_state & DOOR_ACTION_2)
2157 int i = (door_state & DOOR_OPEN_2 ? VXSIZE - x : x);
2158 int j = (VXSIZE - i) / 3;
2160 BlitBitmap(bitmap_db_door, drawto,
2161 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + i/2,
2162 VXSIZE, VYSIZE - i/2, VX, VY);
2164 ClearRectangle(drawto, VX, VY + VYSIZE-i/2, VXSIZE, i/2);
2166 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2167 BlitBitmapMasked(bitmap, drawto,
2168 VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2,
2169 VX + VXSIZE-i, VY+j);
2170 SetClipOrigin(bitmap, gc,
2171 VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
2172 BlitBitmapMasked(bitmap, drawto,
2173 VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j,
2176 BlitBitmapMasked(bitmap, drawto,
2177 VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2,
2178 i, VYSIZE / 2, VX, VY + VYSIZE / 2 - j);
2179 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2180 BlitBitmapMasked(bitmap, drawto,
2181 VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2,
2183 VX + VXSIZE - i, VY + VYSIZE / 2 + j);
2185 redraw_mask |= REDRAW_DOOR_2;
2190 if (game_status == MAINMENU)
2195 if (setup.quick_doors)
2197 StopSound(SND_MENU_DOOR_OPENING);
2198 StopSound(SND_MENU_DOOR_CLOSING);
2201 if (door_state & DOOR_ACTION_1)
2202 door1 = door_state & DOOR_ACTION_1;
2203 if (door_state & DOOR_ACTION_2)
2204 door2 = door_state & DOOR_ACTION_2;
2206 return (door1 | door2);
2209 void DrawSpecialEditorDoor()
2211 /* draw bigger toolbox window */
2212 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
2213 DOOR_GFX_PAGEX7, 0, EXSIZE + 8, 8,
2215 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
2216 EX - 4, VY - 4, EXSIZE + 8, EYSIZE - VYSIZE + 4,
2219 redraw_mask |= REDRAW_ALL;
2222 void UndrawSpecialEditorDoor()
2224 /* draw normal tape recorder window */
2225 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
2226 EX - 4, EY - 12, EXSIZE + 8, EYSIZE - VYSIZE + 12,
2229 redraw_mask |= REDRAW_ALL;
2233 int ReadPixel(DrawBuffer *bitmap, int x, int y)
2235 XImage *pixel_image;
2236 unsigned long pixel_value;
2238 pixel_image = XGetImage(display, bitmap->drawable,
2239 x, y, 1, 1, AllPlanes, ZPixmap);
2240 pixel_value = XGetPixel(pixel_image, 0, 0);
2242 XDestroyImage(pixel_image);
2248 /* ---------- new tool button stuff ---------------------------------------- */
2250 /* graphic position values for tool buttons */
2251 #define TOOL_BUTTON_YES_XPOS 2
2252 #define TOOL_BUTTON_YES_YPOS 250
2253 #define TOOL_BUTTON_YES_GFX_YPOS 0
2254 #define TOOL_BUTTON_YES_XSIZE 46
2255 #define TOOL_BUTTON_YES_YSIZE 28
2256 #define TOOL_BUTTON_NO_XPOS 52
2257 #define TOOL_BUTTON_NO_YPOS TOOL_BUTTON_YES_YPOS
2258 #define TOOL_BUTTON_NO_GFX_YPOS TOOL_BUTTON_YES_GFX_YPOS
2259 #define TOOL_BUTTON_NO_XSIZE TOOL_BUTTON_YES_XSIZE
2260 #define TOOL_BUTTON_NO_YSIZE TOOL_BUTTON_YES_YSIZE
2261 #define TOOL_BUTTON_CONFIRM_XPOS TOOL_BUTTON_YES_XPOS
2262 #define TOOL_BUTTON_CONFIRM_YPOS TOOL_BUTTON_YES_YPOS
2263 #define TOOL_BUTTON_CONFIRM_GFX_YPOS 30
2264 #define TOOL_BUTTON_CONFIRM_XSIZE 96
2265 #define TOOL_BUTTON_CONFIRM_YSIZE TOOL_BUTTON_YES_YSIZE
2266 #define TOOL_BUTTON_PLAYER_XSIZE 30
2267 #define TOOL_BUTTON_PLAYER_YSIZE 30
2268 #define TOOL_BUTTON_PLAYER_GFX_XPOS 5
2269 #define TOOL_BUTTON_PLAYER_GFX_YPOS 185
2270 #define TOOL_BUTTON_PLAYER_XPOS (5 + TOOL_BUTTON_PLAYER_XSIZE / 2)
2271 #define TOOL_BUTTON_PLAYER_YPOS (215 - TOOL_BUTTON_PLAYER_YSIZE / 2)
2272 #define TOOL_BUTTON_PLAYER1_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2273 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2274 #define TOOL_BUTTON_PLAYER2_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2275 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2276 #define TOOL_BUTTON_PLAYER3_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2277 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2278 #define TOOL_BUTTON_PLAYER4_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2279 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2280 #define TOOL_BUTTON_PLAYER1_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2281 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2282 #define TOOL_BUTTON_PLAYER2_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2283 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2284 #define TOOL_BUTTON_PLAYER3_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2285 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2286 #define TOOL_BUTTON_PLAYER4_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2287 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2296 } toolbutton_info[NUM_TOOL_BUTTONS] =
2299 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_GFX_YPOS,
2300 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_YPOS,
2301 TOOL_BUTTON_YES_XSIZE, TOOL_BUTTON_YES_YSIZE,
2306 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_GFX_YPOS,
2307 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_YPOS,
2308 TOOL_BUTTON_NO_XSIZE, TOOL_BUTTON_NO_YSIZE,
2313 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_GFX_YPOS,
2314 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_YPOS,
2315 TOOL_BUTTON_CONFIRM_XSIZE, TOOL_BUTTON_CONFIRM_YSIZE,
2316 TOOL_CTRL_ID_CONFIRM,
2320 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2321 TOOL_BUTTON_PLAYER1_XPOS, TOOL_BUTTON_PLAYER1_YPOS,
2322 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2323 TOOL_CTRL_ID_PLAYER_1,
2327 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2328 TOOL_BUTTON_PLAYER2_XPOS, TOOL_BUTTON_PLAYER2_YPOS,
2329 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2330 TOOL_CTRL_ID_PLAYER_2,
2334 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2335 TOOL_BUTTON_PLAYER3_XPOS, TOOL_BUTTON_PLAYER3_YPOS,
2336 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2337 TOOL_CTRL_ID_PLAYER_3,
2341 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2342 TOOL_BUTTON_PLAYER4_XPOS, TOOL_BUTTON_PLAYER4_YPOS,
2343 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2344 TOOL_CTRL_ID_PLAYER_4,
2349 void CreateToolButtons()
2353 for (i=0; i<NUM_TOOL_BUTTONS; i++)
2355 Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
2356 Bitmap *deco_bitmap = None;
2357 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
2358 struct GadgetInfo *gi;
2359 unsigned long event_mask;
2360 int gd_xoffset, gd_yoffset;
2361 int gd_x1, gd_x2, gd_y;
2364 event_mask = GD_EVENT_RELEASED;
2366 gd_xoffset = toolbutton_info[i].xpos;
2367 gd_yoffset = toolbutton_info[i].ypos;
2368 gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
2369 gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
2370 gd_y = DOOR_GFX_PAGEY1 + gd_yoffset;
2372 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
2374 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
2376 getMiniGraphicSource(PLAYER_NR_GFX(IMG_PLAYER1, player_nr),
2377 &deco_bitmap, &deco_x, &deco_y);
2378 deco_xpos = (toolbutton_info[i].width - MINI_TILEX) / 2;
2379 deco_ypos = (toolbutton_info[i].height - MINI_TILEY) / 2;
2382 gi = CreateGadget(GDI_CUSTOM_ID, id,
2383 GDI_INFO_TEXT, toolbutton_info[i].infotext,
2384 GDI_X, DX + toolbutton_info[i].x,
2385 GDI_Y, DY + toolbutton_info[i].y,
2386 GDI_WIDTH, toolbutton_info[i].width,
2387 GDI_HEIGHT, toolbutton_info[i].height,
2388 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
2389 GDI_STATE, GD_BUTTON_UNPRESSED,
2390 GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
2391 GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
2392 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
2393 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
2394 GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
2395 GDI_DECORATION_SHIFTING, 1, 1,
2396 GDI_EVENT_MASK, event_mask,
2397 GDI_CALLBACK_ACTION, HandleToolButtons,
2401 Error(ERR_EXIT, "cannot create gadget");
2403 tool_gadget[id] = gi;
2407 void FreeToolButtons()
2411 for (i=0; i<NUM_TOOL_BUTTONS; i++)
2412 FreeGadget(tool_gadget[i]);
2415 static void UnmapToolButtons()
2419 for (i=0; i<NUM_TOOL_BUTTONS; i++)
2420 UnmapGadget(tool_gadget[i]);
2423 static void HandleToolButtons(struct GadgetInfo *gi)
2425 request_gadget_id = gi->custom_id;
2428 int get_next_element(int element)
2432 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
2433 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
2434 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
2435 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
2436 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
2437 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
2438 case EL_AMOEBA_DRIPPING: return EL_AMOEBA_WET;
2440 default: return element;
2444 int el_act_dir2img(int element, int action, int direction)
2446 direction = MV_DIR_BIT(direction);
2448 return element_info[element].direction_graphic[action][direction];
2451 int el_act2img(int element, int action)
2453 return element_info[element].graphic[action];
2456 int el_dir2img(int element, int direction)
2458 return el_act_dir2img(element, ACTION_DEFAULT, direction);
2461 int el2img(int element)
2463 return element_info[element].graphic[ACTION_DEFAULT];
2466 int el2edimg(int element)
2468 return element_info[element].editor_graphic;
2471 int el2preimg(int element)
2473 return element_info[element].preview_graphic;