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;
1158 else if (IS_AMOEBOID(element) || element == EL_AMOEBA_DRIPPING)
1160 graphic = (element == EL_BD_AMOEBA ? IMG_BD_AMOEBA_PART1 :
1161 element == EL_AMOEBA_WET ? IMG_AMOEBA_WET_PART1 :
1162 element == EL_AMOEBA_DRY ? IMG_AMOEBA_DRY_PART1 :
1163 element == EL_AMOEBA_FULL ? IMG_AMOEBA_FULL_PART1 :
1164 IMG_AMOEBA_DEAD_PART1);
1166 graphic += (x + 2 * y + 4) % 4;
1170 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, mask_mode);
1171 else if (mask_mode == USE_MASKING)
1172 DrawGraphicThruMask(x, y, graphic, frame);
1174 DrawGraphic(x, y, graphic, frame);
1177 void DrawLevelElementExt(int x, int y, int dx, int dy, int element,
1178 int cut_mode, int mask_mode)
1180 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1181 DrawScreenElementExt(SCREENX(x), SCREENY(y), dx, dy, element,
1182 cut_mode, mask_mode);
1185 void DrawScreenElementShifted(int x, int y, int dx, int dy, int element,
1188 DrawScreenElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1191 void DrawLevelElementShifted(int x, int y, int dx, int dy, int element,
1194 DrawLevelElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1198 void DrawOldScreenElementThruMask(int x, int y, int element)
1200 DrawOldScreenElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1203 void DrawScreenElementThruMask(int x, int y, int element)
1205 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1209 void DrawLevelElementThruMask(int x, int y, int element)
1211 DrawLevelElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1214 void DrawLevelFieldThruMask(int x, int y)
1216 DrawLevelElementExt(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
1219 void DrawCrumbledSand(int x, int y)
1223 int i, width, height, cx,cy;
1224 int lx = LEVELX(x), ly = LEVELY(y);
1225 int element, graphic;
1227 static int xy[4][2] =
1235 if (!IN_LEV_FIELD(lx, ly))
1238 element = Feld[lx][ly];
1240 if (element == EL_SAND ||
1241 element == EL_LANDMINE ||
1242 element == EL_TRAP ||
1243 element == EL_TRAP_ACTIVE)
1245 if (!IN_SCR_FIELD(x, y))
1248 graphic = IMG_SAND_CRUMBLED;
1250 src_bitmap = graphic_info[graphic].bitmap;
1251 src_x = graphic_info[graphic].src_x;
1252 src_y = graphic_info[graphic].src_y;
1258 lxx = lx + xy[i][0];
1259 lyy = ly + xy[i][1];
1260 if (!IN_LEV_FIELD(lxx, lyy))
1261 element = EL_STEELWALL;
1263 element = Feld[lxx][lyy];
1265 if (element == EL_SAND ||
1266 element == EL_LANDMINE ||
1267 element == EL_TRAP ||
1268 element == EL_TRAP_ACTIVE)
1271 if (i == 1 || i == 2)
1275 cx = (i == 2 ? TILEX - snip : 0);
1283 cy = (i == 3 ? TILEY - snip : 0);
1286 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1287 width, height, FX + x * TILEX + cx, FY + y * TILEY + cy);
1290 MarkTileDirty(x, y);
1294 graphic = IMG_SAND_CRUMBLED;
1296 src_bitmap = graphic_info[graphic].bitmap;
1297 src_x = graphic_info[graphic].src_x;
1298 src_y = graphic_info[graphic].src_y;
1302 int xx, yy, lxx, lyy;
1306 lxx = lx + xy[i][0];
1307 lyy = ly + xy[i][1];
1309 if (!IN_LEV_FIELD(lxx, lyy) ||
1310 (Feld[lxx][lyy] != EL_SAND &&
1311 Feld[lxx][lyy] != EL_LANDMINE &&
1312 Feld[lxx][lyy] != EL_TRAP &&
1313 Feld[lxx][lyy] != EL_TRAP_ACTIVE) ||
1314 !IN_SCR_FIELD(xx, yy))
1317 if (i == 1 || i == 2)
1321 cx = (i == 1 ? TILEX - snip : 0);
1329 cy = (i==0 ? TILEY-snip : 0);
1332 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1333 width, height, FX + xx * TILEX + cx, FY + yy * TILEY + cy);
1335 MarkTileDirty(xx, yy);
1340 static int getBorderElement(int x, int y)
1344 { EL_STEELWALL_TOPLEFT, EL_INVISIBLE_STEELWALL_TOPLEFT },
1345 { EL_STEELWALL_TOPRIGHT, EL_INVISIBLE_STEELWALL_TOPRIGHT },
1346 { EL_STEELWALL_BOTTOMLEFT, EL_INVISIBLE_STEELWALL_BOTTOMLEFT },
1347 { EL_STEELWALL_BOTTOMRIGHT, EL_INVISIBLE_STEELWALL_BOTTOMRIGHT },
1348 { EL_STEELWALL_VERTICAL, EL_INVISIBLE_STEELWALL_VERTICAL },
1349 { EL_STEELWALL_HORIZONTAL, EL_INVISIBLE_STEELWALL_HORIZONTAL },
1350 { EL_STEELWALL, EL_INVISIBLE_STEELWALL }
1352 int steel_type = (BorderElement == EL_STEELWALL ? 0 : 1);
1353 int steel_position = (x == -1 && y == -1 ? 0 :
1354 x == lev_fieldx && y == -1 ? 1 :
1355 x == -1 && y == lev_fieldy ? 2 :
1356 x == lev_fieldx && y == lev_fieldy ? 3 :
1357 x == -1 || x == lev_fieldx ? 4 :
1358 y == -1 || y == lev_fieldy ? 5 : 6);
1360 return border[steel_position][steel_type];
1363 void DrawScreenElement(int x, int y, int element)
1365 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
1366 DrawCrumbledSand(x, y);
1369 void DrawLevelElement(int x, int y, int element)
1371 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1372 DrawScreenElement(SCREENX(x), SCREENY(y), element);
1375 void DrawScreenField(int x, int y)
1377 int lx = LEVELX(x), ly = LEVELY(y);
1378 int element, content;
1380 if (!IN_LEV_FIELD(lx, ly))
1382 if (lx < -1 || lx > lev_fieldx || ly < -1 || ly > lev_fieldy)
1385 element = getBorderElement(lx, ly);
1387 DrawScreenElement(x, y, element);
1391 element = Feld[lx][ly];
1392 content = Store[lx][ly];
1394 if (IS_MOVING(lx, ly))
1396 int horiz_move = (MovDir[lx][ly] == MV_LEFT || MovDir[lx][ly] == MV_RIGHT);
1397 boolean cut_mode = NO_CUTTING;
1399 if (element == EL_QUICKSAND_EMPTYING ||
1400 element == EL_MAGIC_WALL_EMPTYING ||
1401 element == EL_BD_MAGIC_WALL_EMPTYING ||
1402 element == EL_AMOEBA_DRIPPING)
1403 cut_mode = CUT_ABOVE;
1404 else if (element == EL_QUICKSAND_FILLING ||
1405 element == EL_MAGIC_WALL_FILLING ||
1406 element == EL_BD_MAGIC_WALL_FILLING)
1407 cut_mode = CUT_BELOW;
1409 if (cut_mode == CUT_ABOVE)
1410 DrawScreenElementShifted(x, y, 0, 0, element, NO_CUTTING);
1412 DrawScreenElement(x, y, EL_EMPTY);
1415 DrawScreenElementShifted(x, y, MovPos[lx][ly], 0, element, NO_CUTTING);
1416 else if (cut_mode == NO_CUTTING)
1417 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], element, cut_mode);
1419 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], content, cut_mode);
1421 if (content == EL_ACID)
1422 DrawLevelElementThruMask(lx, ly + 1, EL_ACID);
1424 else if (IS_BLOCKED(lx, ly))
1429 boolean cut_mode = NO_CUTTING;
1430 int element_old, content_old;
1432 Blocked2Moving(lx, ly, &oldx, &oldy);
1435 horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
1436 MovDir[oldx][oldy] == MV_RIGHT);
1438 element_old = Feld[oldx][oldy];
1439 content_old = Store[oldx][oldy];
1441 if (element_old == EL_QUICKSAND_EMPTYING ||
1442 element_old == EL_MAGIC_WALL_EMPTYING ||
1443 element_old == EL_BD_MAGIC_WALL_EMPTYING ||
1444 element_old == EL_AMOEBA_DRIPPING)
1445 cut_mode = CUT_ABOVE;
1447 DrawScreenElement(x, y, EL_EMPTY);
1450 DrawScreenElementShifted(sx, sy, MovPos[oldx][oldy], 0, element_old,
1452 else if (cut_mode == NO_CUTTING)
1453 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], element_old,
1456 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], content_old,
1459 else if (IS_DRAWABLE(element))
1460 DrawScreenElement(x, y, element);
1462 DrawScreenElement(x, y, EL_EMPTY);
1465 void DrawLevelField(int x, int y)
1467 if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1468 DrawScreenField(SCREENX(x), SCREENY(y));
1469 else if (IS_MOVING(x, y))
1473 Moving2Blocked(x, y, &newx, &newy);
1474 if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
1475 DrawScreenField(SCREENX(newx), SCREENY(newy));
1477 else if (IS_BLOCKED(x, y))
1481 Blocked2Moving(x, y, &oldx, &oldy);
1482 if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
1483 DrawScreenField(SCREENX(oldx), SCREENY(oldy));
1487 void DrawMiniElement(int x, int y, int element)
1491 graphic = el2edimg(element);
1492 DrawMiniGraphic(x, y, graphic);
1495 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
1497 int x = sx + scroll_x, y = sy + scroll_y;
1499 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
1500 DrawMiniElement(sx, sy, EL_EMPTY);
1501 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
1502 DrawMiniElement(sx, sy, Feld[x][y]);
1504 DrawMiniGraphic(sx, sy, el2edimg(getBorderElement(x, y)));
1507 void getMicroGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
1509 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
1510 int mini_startx = src_bitmap->width * 3 / 4;
1511 int mini_starty = src_bitmap->height * 2 / 3;
1512 int src_x = mini_startx + graphic_info[graphic].src_x / 8;
1513 int src_y = mini_starty + graphic_info[graphic].src_y / 8;
1515 if (src_x + MICRO_TILEX > src_bitmap->width ||
1516 src_y + MICRO_TILEY > src_bitmap->height)
1518 /* graphic of desired size seems not to be contained in this image;
1519 dirty workaround: get it from the middle of the normal sized image */
1521 getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
1522 src_x += (TILEX / 2 - MICRO_TILEX / 2);
1523 src_y += (TILEY / 2 - MICRO_TILEY / 2);
1526 *bitmap = src_bitmap;
1531 void DrawMicroElement(int xpos, int ypos, int element)
1535 int graphic = el2preimg(element);
1537 getMicroGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
1538 BlitBitmap(src_bitmap, drawto, src_x, src_y, MICRO_TILEX, MICRO_TILEY,
1546 SetDrawBackgroundMask(REDRAW_NONE);
1549 for(x=BX1; x<=BX2; x++)
1550 for(y=BY1; y<=BY2; y++)
1551 DrawScreenField(x, y);
1553 redraw_mask |= REDRAW_FIELD;
1556 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
1560 for(x=0; x<size_x; x++)
1561 for(y=0; y<size_y; y++)
1562 DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
1564 redraw_mask |= REDRAW_FIELD;
1567 static void DrawMicroLevelExt(int xpos, int ypos, int from_x, int from_y)
1571 DrawBackground(xpos, ypos, MICROLEV_XSIZE, MICROLEV_YSIZE);
1573 if (lev_fieldx < STD_LEV_FIELDX)
1574 xpos += (STD_LEV_FIELDX - lev_fieldx) / 2 * MICRO_TILEX;
1575 if (lev_fieldy < STD_LEV_FIELDY)
1576 ypos += (STD_LEV_FIELDY - lev_fieldy) / 2 * MICRO_TILEY;
1578 xpos += MICRO_TILEX;
1579 ypos += MICRO_TILEY;
1581 for(x=-1; x<=STD_LEV_FIELDX; x++)
1583 for(y=-1; y<=STD_LEV_FIELDY; y++)
1585 int lx = from_x + x, ly = from_y + y;
1587 if (lx >= 0 && lx < lev_fieldx && ly >= 0 && ly < lev_fieldy)
1588 DrawMicroElement(xpos + x * MICRO_TILEX, ypos + y * MICRO_TILEY,
1590 else if (lx >= -1 && lx < lev_fieldx+1 && ly >= -1 && ly < lev_fieldy+1
1591 && BorderElement != EL_EMPTY)
1592 DrawMicroElement(xpos + x * MICRO_TILEX, ypos + y * MICRO_TILEY,
1593 getBorderElement(lx, ly));
1597 redraw_mask |= REDRAW_MICROLEVEL;
1600 #define MICROLABEL_EMPTY 0
1601 #define MICROLABEL_LEVEL_NAME 1
1602 #define MICROLABEL_CREATED_BY 2
1603 #define MICROLABEL_LEVEL_AUTHOR 3
1604 #define MICROLABEL_IMPORTED_FROM 4
1605 #define MICROLABEL_LEVEL_IMPORT_INFO 5
1607 #define MAX_MICROLABEL_SIZE (SXSIZE / FONT4_XSIZE)
1609 static void DrawMicroLevelLabelExt(int mode)
1611 char label_text[MAX_MICROLABEL_SIZE + 1];
1613 DrawBackground(SX, MICROLABEL_YPOS, SXSIZE, FONT4_YSIZE);
1615 strncpy(label_text, (mode == MICROLABEL_LEVEL_NAME ? level.name :
1616 mode == MICROLABEL_CREATED_BY ? "created by" :
1617 mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
1618 mode == MICROLABEL_IMPORTED_FROM ? "imported from" :
1619 mode == MICROLABEL_LEVEL_IMPORT_INFO ?
1620 leveldir_current->imported_from : ""),
1621 MAX_MICROLABEL_SIZE);
1622 label_text[MAX_MICROLABEL_SIZE] = '\0';
1624 if (strlen(label_text) > 0)
1626 int lxpos = SX + (SXSIZE - strlen(label_text) * FONT4_XSIZE) / 2;
1627 int lypos = MICROLABEL_YPOS;
1629 DrawText(lxpos, lypos, label_text, FS_SMALL, FC_SPECIAL2);
1632 redraw_mask |= REDRAW_MICROLEVEL;
1635 void DrawMicroLevel(int xpos, int ypos, boolean restart)
1637 static unsigned long scroll_delay = 0;
1638 static unsigned long label_delay = 0;
1639 static int from_x, from_y, scroll_direction;
1640 static int label_state, label_counter;
1644 from_x = from_y = 0;
1645 scroll_direction = MV_RIGHT;
1649 DrawMicroLevelExt(xpos, ypos, from_x, from_y);
1650 DrawMicroLevelLabelExt(label_state);
1652 /* initialize delay counters */
1653 DelayReached(&scroll_delay, 0);
1654 DelayReached(&label_delay, 0);
1659 /* scroll micro level, if needed */
1660 if ((lev_fieldx > STD_LEV_FIELDX || lev_fieldy > STD_LEV_FIELDY) &&
1661 DelayReached(&scroll_delay, MICROLEVEL_SCROLL_DELAY))
1663 switch (scroll_direction)
1669 scroll_direction = MV_UP;
1673 if (from_x < lev_fieldx - STD_LEV_FIELDX)
1676 scroll_direction = MV_DOWN;
1683 scroll_direction = MV_RIGHT;
1687 if (from_y < lev_fieldy - STD_LEV_FIELDY)
1690 scroll_direction = MV_LEFT;
1697 DrawMicroLevelExt(xpos, ypos, from_x, from_y);
1700 /* redraw micro level label, if needed */
1701 if (strcmp(level.name, NAMELESS_LEVEL_NAME) != 0 &&
1702 strcmp(level.author, ANONYMOUS_NAME) != 0 &&
1703 strcmp(level.author, leveldir_current->name) != 0 &&
1704 DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
1706 int max_label_counter = 23;
1708 if (leveldir_current->imported_from != NULL)
1709 max_label_counter += 14;
1711 label_counter = (label_counter + 1) % max_label_counter;
1712 label_state = (label_counter >= 0 && label_counter <= 7 ?
1713 MICROLABEL_LEVEL_NAME :
1714 label_counter >= 9 && label_counter <= 12 ?
1715 MICROLABEL_CREATED_BY :
1716 label_counter >= 14 && label_counter <= 21 ?
1717 MICROLABEL_LEVEL_AUTHOR :
1718 label_counter >= 23 && label_counter <= 26 ?
1719 MICROLABEL_IMPORTED_FROM :
1720 label_counter >= 28 && label_counter <= 35 ?
1721 MICROLABEL_LEVEL_IMPORT_INFO : MICROLABEL_EMPTY);
1722 DrawMicroLevelLabelExt(label_state);
1726 int REQ_in_range(int x, int y)
1728 if (y > DY+249 && y < DY+278)
1730 if (x > DX+1 && x < DX+48)
1732 else if (x > DX+51 && x < DX+98)
1738 #define MAX_REQUEST_LINES 13
1739 #define MAX_REQUEST_LINE_LEN 7
1741 boolean Request(char *text, unsigned int req_state)
1743 int mx, my, ty, result = -1;
1744 unsigned int old_door_state;
1746 #if defined(PLATFORM_UNIX)
1747 /* pause network game while waiting for request to answer */
1748 if (options.network &&
1749 game_status == PLAYING &&
1750 req_state & REQUEST_WAIT_FOR)
1751 SendToServer_PausePlaying();
1754 old_door_state = GetDoorState();
1758 CloseDoor(DOOR_CLOSE_1);
1760 /* save old door content */
1761 BlitBitmap(bitmap_db_door, bitmap_db_door,
1762 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
1763 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
1765 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
1767 /* clear door drawing field */
1768 DrawBackground(DX, DY, DXSIZE, DYSIZE);
1770 /* write text for request */
1771 for(ty=0; ty < MAX_REQUEST_LINES; ty++)
1773 char text_line[MAX_REQUEST_LINE_LEN + 1];
1779 for(tl=0,tx=0; tx < MAX_REQUEST_LINE_LEN; tl++,tx++)
1782 if (!tc || tc == ' ')
1793 strncpy(text_line, text, tl);
1796 DrawText(DX + 50 - (tl * 14)/2, DY + 8 + ty * 16,
1797 text_line, FS_SMALL, FC_YELLOW);
1799 text += tl + (tc == ' ' ? 1 : 0);
1802 if (req_state & REQ_ASK)
1804 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
1805 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
1807 else if (req_state & REQ_CONFIRM)
1809 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
1811 else if (req_state & REQ_PLAYER)
1813 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
1814 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
1815 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
1816 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
1819 /* copy request gadgets to door backbuffer */
1820 BlitBitmap(drawto, bitmap_db_door,
1821 DX, DY, DXSIZE, DYSIZE,
1822 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
1824 OpenDoor(DOOR_OPEN_1);
1830 if (!(req_state & REQUEST_WAIT_FOR))
1832 SetDrawBackgroundMask(REDRAW_FIELD);
1837 if (game_status != MAINMENU)
1840 button_status = MB_RELEASED;
1842 request_gadget_id = -1;
1844 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
1856 case EVENT_BUTTONPRESS:
1857 case EVENT_BUTTONRELEASE:
1858 case EVENT_MOTIONNOTIFY:
1860 if (event.type == EVENT_MOTIONNOTIFY)
1862 if (!PointerInWindow(window))
1863 continue; /* window and pointer are on different screens */
1868 motion_status = TRUE;
1869 mx = ((MotionEvent *) &event)->x;
1870 my = ((MotionEvent *) &event)->y;
1874 motion_status = FALSE;
1875 mx = ((ButtonEvent *) &event)->x;
1876 my = ((ButtonEvent *) &event)->y;
1877 if (event.type == EVENT_BUTTONPRESS)
1878 button_status = ((ButtonEvent *) &event)->button;
1880 button_status = MB_RELEASED;
1883 /* this sets 'request_gadget_id' */
1884 HandleGadgets(mx, my, button_status);
1886 switch(request_gadget_id)
1888 case TOOL_CTRL_ID_YES:
1891 case TOOL_CTRL_ID_NO:
1894 case TOOL_CTRL_ID_CONFIRM:
1895 result = TRUE | FALSE;
1898 case TOOL_CTRL_ID_PLAYER_1:
1901 case TOOL_CTRL_ID_PLAYER_2:
1904 case TOOL_CTRL_ID_PLAYER_3:
1907 case TOOL_CTRL_ID_PLAYER_4:
1918 case EVENT_KEYPRESS:
1919 switch(GetEventKey((KeyEvent *)&event, TRUE))
1932 if (req_state & REQ_PLAYER)
1936 case EVENT_KEYRELEASE:
1937 ClearPlayerAction();
1941 HandleOtherEvents(&event);
1945 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
1947 int joy = AnyJoystick();
1949 if (joy & JOY_BUTTON_1)
1951 else if (joy & JOY_BUTTON_2)
1957 /* don't eat all CPU time */
1961 if (game_status != MAINMENU)
1966 if (!(req_state & REQ_STAY_OPEN))
1968 CloseDoor(DOOR_CLOSE_1);
1970 if (!(req_state & REQ_STAY_CLOSED) && (old_door_state & DOOR_OPEN_1))
1972 BlitBitmap(bitmap_db_door, bitmap_db_door,
1973 DOOR_GFX_PAGEX2,DOOR_GFX_PAGEY1, DXSIZE,DYSIZE,
1974 DOOR_GFX_PAGEX1,DOOR_GFX_PAGEY1);
1975 OpenDoor(DOOR_OPEN_1);
1981 SetDrawBackgroundMask(REDRAW_FIELD);
1983 #if defined(PLATFORM_UNIX)
1984 /* continue network game after request */
1985 if (options.network &&
1986 game_status == PLAYING &&
1987 req_state & REQUEST_WAIT_FOR)
1988 SendToServer_ContinuePlaying();
1994 unsigned int OpenDoor(unsigned int door_state)
1996 unsigned int new_door_state;
1998 if (door_state & DOOR_COPY_BACK)
2000 BlitBitmap(bitmap_db_door, bitmap_db_door,
2001 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE + VYSIZE,
2002 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2003 door_state &= ~DOOR_COPY_BACK;
2006 new_door_state = MoveDoor(door_state);
2008 return(new_door_state);
2011 unsigned int CloseDoor(unsigned int door_state)
2013 unsigned int new_door_state;
2015 BlitBitmap(backbuffer, bitmap_db_door,
2016 DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2017 BlitBitmap(backbuffer, bitmap_db_door,
2018 VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
2020 new_door_state = MoveDoor(door_state);
2022 return(new_door_state);
2025 unsigned int GetDoorState()
2027 return MoveDoor(DOOR_GET_STATE);
2030 unsigned int SetDoorState(unsigned int door_state)
2032 return MoveDoor(door_state | DOOR_SET_STATE);
2035 unsigned int MoveDoor(unsigned int door_state)
2037 static int door1 = DOOR_OPEN_1;
2038 static int door2 = DOOR_CLOSE_2;
2039 static unsigned long door_delay = 0;
2040 int x, start, stepsize = 2;
2041 unsigned long door_delay_value = stepsize * 5;
2043 if (door_state == DOOR_GET_STATE)
2044 return(door1 | door2);
2046 if (door_state & DOOR_SET_STATE)
2048 if (door_state & DOOR_ACTION_1)
2049 door1 = door_state & DOOR_ACTION_1;
2050 if (door_state & DOOR_ACTION_2)
2051 door2 = door_state & DOOR_ACTION_2;
2053 return(door1 | door2);
2056 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
2057 door_state &= ~DOOR_OPEN_1;
2058 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
2059 door_state &= ~DOOR_CLOSE_1;
2060 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
2061 door_state &= ~DOOR_OPEN_2;
2062 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
2063 door_state &= ~DOOR_CLOSE_2;
2065 if (setup.quick_doors)
2068 door_delay_value = 0;
2070 StopSound(SND_MENU_DOOR_OPENING);
2071 StopSound(SND_MENU_DOOR_CLOSING);
2074 if (global.autoplay_leveldir)
2076 door_state |= DOOR_NO_DELAY;
2077 door_state &= ~DOOR_CLOSE_ALL;
2080 if (door_state & DOOR_ACTION)
2082 if (!(door_state & DOOR_NO_DELAY))
2084 /* opening door sound has priority over simultaneously closing door */
2085 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
2086 PlaySoundStereo(SND_MENU_DOOR_OPENING, SOUND_MAX_RIGHT);
2087 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
2088 PlaySoundStereo(SND_MENU_DOOR_CLOSING, SOUND_MAX_RIGHT);
2091 start = ((door_state & DOOR_NO_DELAY) ? DXSIZE : 0);
2093 for(x=start; x<=DXSIZE; x+=stepsize)
2095 Bitmap *bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
2096 GC gc = bitmap->stored_clip_gc;
2098 if (!(door_state & DOOR_NO_DELAY))
2099 WaitUntilDelayReached(&door_delay, door_delay_value);
2101 if (door_state & DOOR_ACTION_1)
2103 int i = (door_state & DOOR_OPEN_1 ? DXSIZE-x : x);
2104 int j = (DXSIZE - i) / 3;
2106 BlitBitmap(bitmap_db_door, drawto,
2107 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + i/2,
2108 DXSIZE,DYSIZE - i/2, DX, DY);
2110 ClearRectangle(drawto, DX, DY + DYSIZE - i/2, DXSIZE,i/2);
2112 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2113 BlitBitmapMasked(bitmap, drawto,
2114 DXSIZE, DOOR_GFX_PAGEY1, i, 77,
2115 DX + DXSIZE - i, DY + j);
2116 BlitBitmapMasked(bitmap, drawto,
2117 DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63,
2118 DX + DXSIZE - i, DY + 140 + j);
2119 SetClipOrigin(bitmap, gc, DX - DXSIZE + i, DY - (DOOR_GFX_PAGEY1 + j));
2120 BlitBitmapMasked(bitmap, drawto,
2121 DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j,
2123 BlitBitmapMasked(bitmap, drawto,
2124 DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63,
2127 BlitBitmapMasked(bitmap, drawto,
2128 DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
2130 BlitBitmapMasked(bitmap, drawto,
2131 DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
2133 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2134 BlitBitmapMasked(bitmap, drawto,
2135 DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
2136 DX + DXSIZE - i, DY + 77 + j);
2137 BlitBitmapMasked(bitmap, drawto,
2138 DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
2139 DX + DXSIZE - i, DY + 203 + j);
2141 redraw_mask |= REDRAW_DOOR_1;
2144 if (door_state & DOOR_ACTION_2)
2146 int i = (door_state & DOOR_OPEN_2 ? VXSIZE - x : x);
2147 int j = (VXSIZE - i) / 3;
2149 BlitBitmap(bitmap_db_door, drawto,
2150 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + i/2,
2151 VXSIZE, VYSIZE - i/2, VX, VY);
2153 ClearRectangle(drawto, VX, VY + VYSIZE-i/2, VXSIZE, i/2);
2155 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2156 BlitBitmapMasked(bitmap, drawto,
2157 VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2,
2158 VX + VXSIZE-i, VY+j);
2159 SetClipOrigin(bitmap, gc,
2160 VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
2161 BlitBitmapMasked(bitmap, drawto,
2162 VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j,
2165 BlitBitmapMasked(bitmap, drawto,
2166 VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2,
2167 i, VYSIZE / 2, VX, VY + VYSIZE / 2 - j);
2168 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2169 BlitBitmapMasked(bitmap, drawto,
2170 VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2,
2172 VX + VXSIZE - i, VY + VYSIZE / 2 + j);
2174 redraw_mask |= REDRAW_DOOR_2;
2179 if (game_status == MAINMENU)
2184 if (setup.quick_doors)
2186 StopSound(SND_MENU_DOOR_OPENING);
2187 StopSound(SND_MENU_DOOR_CLOSING);
2190 if (door_state & DOOR_ACTION_1)
2191 door1 = door_state & DOOR_ACTION_1;
2192 if (door_state & DOOR_ACTION_2)
2193 door2 = door_state & DOOR_ACTION_2;
2195 return (door1 | door2);
2198 void DrawSpecialEditorDoor()
2200 /* draw bigger toolbox window */
2201 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
2202 DOOR_GFX_PAGEX7, 0, EXSIZE + 8, 8,
2204 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
2205 EX - 4, VY - 4, EXSIZE + 8, EYSIZE - VYSIZE + 4,
2208 redraw_mask |= REDRAW_ALL;
2211 void UndrawSpecialEditorDoor()
2213 /* draw normal tape recorder window */
2214 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
2215 EX - 4, EY - 12, EXSIZE + 8, EYSIZE - VYSIZE + 12,
2218 redraw_mask |= REDRAW_ALL;
2222 int ReadPixel(DrawBuffer *bitmap, int x, int y)
2224 XImage *pixel_image;
2225 unsigned long pixel_value;
2227 pixel_image = XGetImage(display, bitmap->drawable,
2228 x, y, 1, 1, AllPlanes, ZPixmap);
2229 pixel_value = XGetPixel(pixel_image, 0, 0);
2231 XDestroyImage(pixel_image);
2237 /* ---------- new tool button stuff ---------------------------------------- */
2239 /* graphic position values for tool buttons */
2240 #define TOOL_BUTTON_YES_XPOS 2
2241 #define TOOL_BUTTON_YES_YPOS 250
2242 #define TOOL_BUTTON_YES_GFX_YPOS 0
2243 #define TOOL_BUTTON_YES_XSIZE 46
2244 #define TOOL_BUTTON_YES_YSIZE 28
2245 #define TOOL_BUTTON_NO_XPOS 52
2246 #define TOOL_BUTTON_NO_YPOS TOOL_BUTTON_YES_YPOS
2247 #define TOOL_BUTTON_NO_GFX_YPOS TOOL_BUTTON_YES_GFX_YPOS
2248 #define TOOL_BUTTON_NO_XSIZE TOOL_BUTTON_YES_XSIZE
2249 #define TOOL_BUTTON_NO_YSIZE TOOL_BUTTON_YES_YSIZE
2250 #define TOOL_BUTTON_CONFIRM_XPOS TOOL_BUTTON_YES_XPOS
2251 #define TOOL_BUTTON_CONFIRM_YPOS TOOL_BUTTON_YES_YPOS
2252 #define TOOL_BUTTON_CONFIRM_GFX_YPOS 30
2253 #define TOOL_BUTTON_CONFIRM_XSIZE 96
2254 #define TOOL_BUTTON_CONFIRM_YSIZE TOOL_BUTTON_YES_YSIZE
2255 #define TOOL_BUTTON_PLAYER_XSIZE 30
2256 #define TOOL_BUTTON_PLAYER_YSIZE 30
2257 #define TOOL_BUTTON_PLAYER_GFX_XPOS 5
2258 #define TOOL_BUTTON_PLAYER_GFX_YPOS 185
2259 #define TOOL_BUTTON_PLAYER_XPOS (5 + TOOL_BUTTON_PLAYER_XSIZE / 2)
2260 #define TOOL_BUTTON_PLAYER_YPOS (215 - TOOL_BUTTON_PLAYER_YSIZE / 2)
2261 #define TOOL_BUTTON_PLAYER1_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2262 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2263 #define TOOL_BUTTON_PLAYER2_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2264 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2265 #define TOOL_BUTTON_PLAYER3_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2266 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2267 #define TOOL_BUTTON_PLAYER4_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2268 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2269 #define TOOL_BUTTON_PLAYER1_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2270 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2271 #define TOOL_BUTTON_PLAYER2_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2272 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2273 #define TOOL_BUTTON_PLAYER3_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2274 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2275 #define TOOL_BUTTON_PLAYER4_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2276 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2285 } toolbutton_info[NUM_TOOL_BUTTONS] =
2288 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_GFX_YPOS,
2289 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_YPOS,
2290 TOOL_BUTTON_YES_XSIZE, TOOL_BUTTON_YES_YSIZE,
2295 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_GFX_YPOS,
2296 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_YPOS,
2297 TOOL_BUTTON_NO_XSIZE, TOOL_BUTTON_NO_YSIZE,
2302 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_GFX_YPOS,
2303 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_YPOS,
2304 TOOL_BUTTON_CONFIRM_XSIZE, TOOL_BUTTON_CONFIRM_YSIZE,
2305 TOOL_CTRL_ID_CONFIRM,
2309 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2310 TOOL_BUTTON_PLAYER1_XPOS, TOOL_BUTTON_PLAYER1_YPOS,
2311 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2312 TOOL_CTRL_ID_PLAYER_1,
2316 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2317 TOOL_BUTTON_PLAYER2_XPOS, TOOL_BUTTON_PLAYER2_YPOS,
2318 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2319 TOOL_CTRL_ID_PLAYER_2,
2323 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2324 TOOL_BUTTON_PLAYER3_XPOS, TOOL_BUTTON_PLAYER3_YPOS,
2325 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2326 TOOL_CTRL_ID_PLAYER_3,
2330 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2331 TOOL_BUTTON_PLAYER4_XPOS, TOOL_BUTTON_PLAYER4_YPOS,
2332 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2333 TOOL_CTRL_ID_PLAYER_4,
2338 void CreateToolButtons()
2342 for (i=0; i<NUM_TOOL_BUTTONS; i++)
2344 Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
2345 Bitmap *deco_bitmap = None;
2346 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
2347 struct GadgetInfo *gi;
2348 unsigned long event_mask;
2349 int gd_xoffset, gd_yoffset;
2350 int gd_x1, gd_x2, gd_y;
2353 event_mask = GD_EVENT_RELEASED;
2355 gd_xoffset = toolbutton_info[i].xpos;
2356 gd_yoffset = toolbutton_info[i].ypos;
2357 gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
2358 gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
2359 gd_y = DOOR_GFX_PAGEY1 + gd_yoffset;
2361 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
2363 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
2365 getMiniGraphicSource(PLAYER_NR_GFX(IMG_PLAYER1, player_nr),
2366 &deco_bitmap, &deco_x, &deco_y);
2367 deco_xpos = (toolbutton_info[i].width - MINI_TILEX) / 2;
2368 deco_ypos = (toolbutton_info[i].height - MINI_TILEY) / 2;
2371 gi = CreateGadget(GDI_CUSTOM_ID, id,
2372 GDI_INFO_TEXT, toolbutton_info[i].infotext,
2373 GDI_X, DX + toolbutton_info[i].x,
2374 GDI_Y, DY + toolbutton_info[i].y,
2375 GDI_WIDTH, toolbutton_info[i].width,
2376 GDI_HEIGHT, toolbutton_info[i].height,
2377 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
2378 GDI_STATE, GD_BUTTON_UNPRESSED,
2379 GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
2380 GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
2381 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
2382 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
2383 GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
2384 GDI_DECORATION_SHIFTING, 1, 1,
2385 GDI_EVENT_MASK, event_mask,
2386 GDI_CALLBACK_ACTION, HandleToolButtons,
2390 Error(ERR_EXIT, "cannot create gadget");
2392 tool_gadget[id] = gi;
2396 void FreeToolButtons()
2400 for (i=0; i<NUM_TOOL_BUTTONS; i++)
2401 FreeGadget(tool_gadget[i]);
2404 static void UnmapToolButtons()
2408 for (i=0; i<NUM_TOOL_BUTTONS; i++)
2409 UnmapGadget(tool_gadget[i]);
2412 static void HandleToolButtons(struct GadgetInfo *gi)
2414 request_gadget_id = gi->custom_id;
2417 int get_next_element(int element)
2421 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
2422 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
2423 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
2424 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
2425 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
2426 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
2427 case EL_AMOEBA_DRIPPING: return EL_AMOEBA_WET;
2429 default: return element;
2433 int el_act_dir2img(int element, int action, int direction)
2435 direction = MV_DIR_BIT(direction);
2437 return element_info[element].direction_graphic[action][direction];
2440 int el_act2img(int element, int action)
2442 return element_info[element].graphic[action];
2445 int el_dir2img(int element, int direction)
2447 return el_act_dir2img(element, ACTION_DEFAULT, direction);
2450 int el2img(int element)
2452 return element_info[element].graphic[ACTION_DEFAULT];
2455 int el2edimg(int element)
2457 return element_info[element].editor_graphic;
2460 int el2preimg(int element)
2462 return element_info[element].preview_graphic;