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 == GAME_MODE_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 == GAME_MODE_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 == GAME_MODE_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 != GAME_MODE_PLAYING ||
179 redraw_mask & REDRAW_FROM_BACKBUFFER)
181 BlitBitmap(backbuffer, window,
182 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE, REAL_SX, REAL_SY);
186 int fx = FX, fy = FY;
188 if (setup.soft_scrolling)
190 fx += (ScreenMovDir & (MV_LEFT | MV_RIGHT) ? ScreenGfxPos : 0);
191 fy += (ScreenMovDir & (MV_UP | MV_DOWN) ? ScreenGfxPos : 0);
194 if (setup.soft_scrolling ||
195 ABS(ScreenMovPos) + ScrollStepSize == TILEX ||
196 ABS(ScreenMovPos) == ScrollStepSize ||
197 redraw_tiles > REDRAWTILES_THRESHOLD)
199 BlitBitmap(buffer, window, fx, fy, SXSIZE, SYSIZE, SX, SY);
203 printf("redrawing all (ScreenGfxPos == %d) because %s\n",
205 (setup.soft_scrolling ?
206 "setup.soft_scrolling" :
207 ABS(ScreenGfxPos) + ScrollStepSize == TILEX ?
208 "ABS(ScreenGfxPos) + ScrollStepSize == TILEX" :
209 ABS(ScreenGfxPos) == ScrollStepSize ?
210 "ABS(ScreenGfxPos) == ScrollStepSize" :
211 "redraw_tiles > REDRAWTILES_THRESHOLD"));
217 redraw_mask &= ~REDRAW_MAIN;
220 if (redraw_mask & REDRAW_DOORS)
222 if (redraw_mask & REDRAW_DOOR_1)
223 BlitBitmap(backbuffer, window, DX, DY, DXSIZE, DYSIZE, DX, DY);
224 if (redraw_mask & REDRAW_DOOR_2)
226 if ((redraw_mask & REDRAW_DOOR_2) == REDRAW_DOOR_2)
227 BlitBitmap(backbuffer, window, VX,VY, VXSIZE,VYSIZE, VX,VY);
230 if (redraw_mask & REDRAW_VIDEO_1)
231 BlitBitmap(backbuffer, window,
232 VX+VIDEO_DISPLAY1_XPOS,VY+VIDEO_DISPLAY1_YPOS,
233 VIDEO_DISPLAY_XSIZE,VIDEO_DISPLAY_YSIZE,
234 VX+VIDEO_DISPLAY1_XPOS,VY+VIDEO_DISPLAY1_YPOS);
235 if (redraw_mask & REDRAW_VIDEO_2)
236 BlitBitmap(backbuffer, window,
237 VX+VIDEO_DISPLAY2_XPOS,VY+VIDEO_DISPLAY2_YPOS,
238 VIDEO_DISPLAY_XSIZE,VIDEO_DISPLAY_YSIZE,
239 VX+VIDEO_DISPLAY2_XPOS,VY+VIDEO_DISPLAY2_YPOS);
240 if (redraw_mask & REDRAW_VIDEO_3)
241 BlitBitmap(backbuffer, window,
242 VX+VIDEO_CONTROL_XPOS,VY+VIDEO_CONTROL_YPOS,
243 VIDEO_CONTROL_XSIZE,VIDEO_CONTROL_YSIZE,
244 VX+VIDEO_CONTROL_XPOS,VY+VIDEO_CONTROL_YPOS);
248 if (redraw_mask & REDRAW_DOOR_3)
249 BlitBitmap(backbuffer, window, EX, EY, EXSIZE, EYSIZE, EX, EY);
251 redraw_mask &= ~REDRAW_DOORS;
254 if (redraw_mask & REDRAW_MICROLEVEL)
256 BlitBitmap(backbuffer, window, SX, SY + 10 * TILEY, SXSIZE, 7 * TILEY,
257 SX, SY + 10 * TILEY);
259 redraw_mask &= ~REDRAW_MICROLEVEL;
262 if (redraw_mask & REDRAW_TILES)
264 for(x=0; x<SCR_FIELDX; x++)
265 for(y=0; y<SCR_FIELDY; y++)
266 if (redraw[redraw_x1 + x][redraw_y1 + y])
267 BlitBitmap(buffer, window,
268 FX + x * TILEX, FX + y * TILEY, TILEX, TILEY,
269 SX + x * TILEX, SY + y * TILEY);
272 if (redraw_mask & REDRAW_FPS) /* display frames per second */
277 sprintf(info1, " (only every %d. frame)", global.fps_slowdown_factor);
278 if (!global.fps_slowdown)
281 sprintf(text, "%.1f fps%s", global.frames_per_second, info1);
282 DrawTextExt(window, SX, SY, text, FONT_TEXT_2, BLIT_OPAQUE);
287 for(x=0; x<MAX_BUF_XSIZE; x++)
288 for(y=0; y<MAX_BUF_YSIZE; y++)
291 redraw_mask = REDRAW_NONE;
297 long fading_delay = 300;
299 if (setup.fading && (redraw_mask & REDRAW_FIELD))
306 ClearRectangle(window, REAL_SX,REAL_SY,FULL_SXSIZE,FULL_SYSIZE);
309 for(i=0;i<2*FULL_SYSIZE;i++)
311 for(y=0;y<FULL_SYSIZE;y++)
313 BlitBitmap(backbuffer, window,
314 REAL_SX,REAL_SY+i, FULL_SXSIZE,1, REAL_SX,REAL_SY+i);
322 for(i=1;i<FULL_SYSIZE;i+=2)
323 BlitBitmap(backbuffer, window,
324 REAL_SX,REAL_SY+i, FULL_SXSIZE,1, REAL_SX,REAL_SY+i);
330 SetClipOrigin(clip_gc[PIX_FADEMASK], 0, 0);
331 BlitBitmapMasked(backbuffer, window,
332 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
337 SetClipOrigin(clip_gc[PIX_FADEMASK], -1, -1);
338 BlitBitmapMasked(backbuffer, window,
339 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
344 SetClipOrigin(clip_gc[PIX_FADEMASK], 0, -1);
345 BlitBitmapMasked(backbuffer, window,
346 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
351 SetClipOrigin(clip_gc[PIX_FADEMASK], -1, 0);
352 BlitBitmapMasked(backbuffer, window,
353 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
358 redraw_mask &= ~REDRAW_MAIN;
365 void SetMainBackgroundImage(int graphic)
367 SetMainBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
368 graphic_info[graphic].bitmap ?
369 graphic_info[graphic].bitmap :
370 graphic_info[IMG_BACKGROUND].bitmap);
373 void SetDoorBackgroundImage(int graphic)
375 SetDoorBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
376 graphic_info[graphic].bitmap ?
377 graphic_info[graphic].bitmap :
378 graphic_info[IMG_BACKGROUND].bitmap);
381 void DrawBackground(int dest_x, int dest_y, int width, int height)
383 ClearRectangleOnBackground(backbuffer, dest_x, dest_y, width, height);
385 redraw_mask |= REDRAW_FIELD;
390 DrawBackground(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
392 if (setup.soft_scrolling && game_status == GAME_MODE_PLAYING)
394 ClearRectangle(fieldbuffer, 0, 0, FXSIZE, FYSIZE);
395 SetDrawtoField(DRAW_BUFFERED);
398 SetDrawtoField(DRAW_BACKBUFFER);
400 if (setup.direct_draw && game_status == GAME_MODE_PLAYING)
402 ClearRectangle(window, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
403 SetDrawtoField(DRAW_DIRECT);
407 void MarkTileDirty(int x, int y)
409 int xx = redraw_x1 + x;
410 int yy = redraw_y1 + y;
415 redraw[xx][yy] = TRUE;
416 redraw_mask |= REDRAW_TILES;
419 void SetBorderElement()
423 BorderElement = EL_EMPTY;
425 for(y=0; y<lev_fieldy && BorderElement == EL_EMPTY; y++)
427 for(x=0; x<lev_fieldx; x++)
429 if (!IS_INDESTRUCTIBLE(Feld[x][y]))
430 BorderElement = EL_STEELWALL;
432 if (y != 0 && y != lev_fieldy - 1 && x != lev_fieldx - 1)
438 void SetRandomAnimationValue(int x, int y)
440 gfx.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)
487 int graphic = el_act_dir2img(element, GfxAction[x][y], MovDir[x][y]);
489 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
491 DrawGraphicAnimation(SCREENX(x), SCREENY(y), el2img(element));
495 inline void DrawLevelGraphicAnimationIfNeeded(int x, int y, int graphic)
497 int sx = SCREENX(x), sy = SCREENY(y);
499 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
502 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
505 DrawGraphicAnimation(sx, sy, graphic);
508 void DrawLevelElementAnimationIfNeeded(int x, int y, int element)
510 int sx = SCREENX(x), sy = SCREENY(y);
513 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
516 graphic = el_act_dir2img(element, GfxAction[x][y], MovDir[x][y]);
518 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
521 DrawGraphicAnimation(sx, sy, graphic);
524 void DrawAllPlayers()
528 for(i=0; i<MAX_PLAYERS; i++)
529 if (stored_player[i].active)
530 DrawPlayer(&stored_player[i]);
533 void DrawPlayerField(int x, int y)
535 if (!IS_PLAYER(x, y))
538 DrawPlayer(PLAYERINFO(x, y));
541 void DrawPlayer(struct PlayerInfo *player)
543 int jx = player->jx, jy = player->jy;
544 int last_jx = player->last_jx, last_jy = player->last_jy;
545 int next_jx = jx + (jx - last_jx), next_jy = jy + (jy - last_jy);
546 int sx = SCREENX(jx), sy = SCREENY(jy);
547 int sxx = 0, syy = 0;
548 int element = Feld[jx][jy], last_element = Feld[last_jx][last_jy];
551 boolean player_is_moving = (last_jx != jx || last_jy != jy ? TRUE : FALSE);
552 int move_dir = player->MovDir;
553 int action = ACTION_DEFAULT;
555 if (!player->active || !IN_SCR_FIELD(SCREENX(last_jx), SCREENY(last_jy)))
559 if (!IN_LEV_FIELD(jx,jy))
561 printf("DrawPlayerField(): x = %d, y = %d\n",jx,jy);
562 printf("DrawPlayerField(): sx = %d, sy = %d\n",sx,sy);
563 printf("DrawPlayerField(): This should never happen!\n");
568 if (element == EL_EXPLOSION)
571 action = (player->Pushing ? ACTION_PUSHING :
572 player->is_digging ? ACTION_DIGGING :
573 player->is_collecting ? ACTION_COLLECTING :
574 player->is_moving ? ACTION_MOVING :
575 player->snapped ? ACTION_SNAPPING : ACTION_DEFAULT);
577 InitPlayerGfxAnimation(player, action, move_dir);
579 /* ----------------------------------------------------------------------- */
580 /* draw things in the field the player is leaving, if needed */
581 /* ----------------------------------------------------------------------- */
583 if (player_is_moving)
585 if (Back[last_jx][last_jy] && IS_DRAWABLE(last_element))
587 DrawLevelElement(last_jx, last_jy, Back[last_jx][last_jy]);
589 if (last_element == EL_DYNAMITE_ACTIVE ||
590 last_element == EL_SP_DISK_RED_ACTIVE)
591 DrawDynamite(last_jx, last_jy);
593 DrawLevelFieldThruMask(last_jx, last_jy);
595 else if (last_element == EL_DYNAMITE_ACTIVE ||
596 last_element == EL_SP_DISK_RED_ACTIVE)
597 DrawDynamite(last_jx, last_jy);
599 DrawLevelField(last_jx, last_jy);
601 if (player->Pushing && IN_SCR_FIELD(SCREENX(next_jx), SCREENY(next_jy)))
605 if (Feld[next_jx][next_jy] == EL_SOKOBAN_FIELD_FULL)
606 DrawLevelElement(next_jx, next_jy, EL_SOKOBAN_FIELD_EMPTY);
608 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
611 DrawLevelField(next_jx, next_jy);
615 if (!IN_SCR_FIELD(sx, sy))
618 if (setup.direct_draw)
619 SetDrawtoField(DRAW_BUFFERED);
621 /* ----------------------------------------------------------------------- */
622 /* draw things behind the player, if needed */
623 /* ----------------------------------------------------------------------- */
626 DrawLevelElement(jx, jy, Back[jx][jy]);
627 else if (IS_ACTIVE_BOMB(element))
628 DrawLevelElement(jx, jy, EL_EMPTY);
631 if (player_is_moving && GfxElement[jx][jy] != EL_UNDEFINED)
633 if (GfxElement[jx][jy] == EL_SAND)
634 DrawLevelFieldCrumbledSandDigging(jx, jy, move_dir, player->StepFrame);
637 int old_element = GfxElement[jx][jy];
638 int old_graphic = el_act_dir2img(old_element, action, move_dir);
639 int frame = getGraphicAnimationFrame(old_graphic, player->StepFrame);
641 DrawGraphic(sx, sy, old_graphic, frame);
646 GfxElement[jx][jy] = EL_UNDEFINED;
648 DrawLevelField(jx, jy);
652 /* ----------------------------------------------------------------------- */
653 /* draw player himself */
654 /* ----------------------------------------------------------------------- */
656 if (player->use_murphy_graphic)
658 static int last_horizontal_dir = MV_LEFT;
661 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
662 last_horizontal_dir = move_dir;
664 direction = (player->snapped ? move_dir : last_horizontal_dir);
666 graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, direction);
669 graphic = el_act_dir2img(player->element_nr, player->GfxAction, move_dir);
671 frame = getGraphicAnimationFrame(graphic, player->Frame);
675 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
676 sxx = player->GfxPos;
678 syy = player->GfxPos;
681 if (!setup.soft_scrolling && ScreenMovPos)
684 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
686 if (SHIELD_ON(player))
688 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
689 IMG_SHIELD_NORMAL_ACTIVE);
690 int frame = getGraphicAnimationFrame(graphic, -1);
692 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
695 /* ----------------------------------------------------------------------- */
696 /* draw things the player is pushing, if needed */
697 /* ----------------------------------------------------------------------- */
699 if (player->Pushing && player_is_moving)
701 int px = SCREENX(next_jx), py = SCREENY(next_jy);
704 (element == EL_SOKOBAN_FIELD_EMPTY ||
705 Feld[next_jx][next_jy] == EL_SOKOBAN_FIELD_FULL))
706 DrawGraphicShiftedThruMask(px, py, sxx, syy, IMG_SOKOBAN_OBJECT, 0,
710 int element = Feld[next_jx][next_jy];
711 int graphic = el2img(element);
714 if ((sxx || syy) && IS_PUSHABLE(element))
716 graphic = el_act_dir2img(element, ACTION_MOVING, move_dir);
717 frame = getGraphicAnimationFrame(graphic, player->Frame);
720 DrawGraphicShifted(px, py, sxx, syy, graphic, frame,
721 NO_CUTTING, NO_MASKING);
725 /* ----------------------------------------------------------------------- */
726 /* draw things in front of player (active dynamite or dynabombs) */
727 /* ----------------------------------------------------------------------- */
729 if (IS_ACTIVE_BOMB(element))
731 graphic = el2img(element);
732 frame = getGraphicAnimationFrame(graphic, GfxFrame[jx][jy]);
734 if (game.emulation == EMU_SUPAPLEX)
735 DrawGraphic(sx, sy, IMG_SP_DISK_RED, frame);
737 DrawGraphicThruMask(sx, sy, graphic, frame);
740 if (player_is_moving && last_element == EL_EXPLOSION)
742 int stored = Store[last_jx][last_jy];
743 int graphic = (game.emulation != EMU_SUPAPLEX ? IMG_EXPLOSION :
744 stored == EL_SP_INFOTRON ? IMG_SP_EXPLOSION_INFOTRON :
746 int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
747 int phase = ExplodePhase[last_jx][last_jy] - 1;
748 int frame = getGraphicAnimationFrame(graphic, phase - delay);
751 DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy), graphic, frame);
754 /* ----------------------------------------------------------------------- */
755 /* draw elements the player is just walking/passing through/under */
756 /* ----------------------------------------------------------------------- */
758 /* handle the field the player is leaving ... */
759 if (player_is_moving && IS_ACCESSIBLE_INSIDE(last_element))
760 DrawLevelField(last_jx, last_jy);
761 else if (player_is_moving && IS_ACCESSIBLE_UNDER(last_element))
762 DrawLevelFieldThruMask(last_jx, last_jy);
764 /* ... and the field the player is entering */
765 if (IS_ACCESSIBLE_INSIDE(element))
766 DrawLevelField(jx, jy);
767 else if (IS_ACCESSIBLE_UNDER(element))
768 DrawLevelFieldThruMask(jx, jy);
770 if (setup.direct_draw)
772 int dest_x = SX + SCREENX(MIN(jx, last_jx)) * TILEX;
773 int dest_y = SY + SCREENY(MIN(jy, last_jy)) * TILEY;
774 int x_size = TILEX * (1 + ABS(jx - last_jx));
775 int y_size = TILEY * (1 + ABS(jy - last_jy));
777 BlitBitmap(drawto_field, window,
778 dest_x, dest_y, x_size, y_size, dest_x, dest_y);
779 SetDrawtoField(DRAW_DIRECT);
782 MarkTileDirty(sx,sy);
785 void getGraphicSource(int graphic, int frame, Bitmap **bitmap, int *x, int *y)
787 struct GraphicInfo *g = &graphic_info[graphic];
791 if (g->offset_y == 0) /* frames are ordered horizontally */
793 int max_width = g->anim_frames_per_line * g->width;
795 *x = (g->src_x + frame * g->offset_x) % max_width;
796 *y = g->src_y + (g->src_x + frame * g->offset_x) / max_width * g->height;
798 else if (g->offset_x == 0) /* frames are ordered vertically */
800 int max_height = g->anim_frames_per_line * g->height;
802 *x = g->src_x + (g->src_y + frame * g->offset_y) / max_height * g->width;
803 *y = (g->src_y + frame * g->offset_y) % max_height;
805 else /* frames are ordered diagonally */
807 *x = g->src_x + frame * g->offset_x;
808 *y = g->src_y + frame * g->offset_y;
812 void DrawGraphic(int x, int y, int graphic, int frame)
815 if (!IN_SCR_FIELD(x, y))
817 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
818 printf("DrawGraphic(): This should never happen!\n");
823 DrawGraphicExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic, frame);
828 void DrawOldGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic)
833 getOldGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
834 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
838 void DrawGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
845 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
847 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
848 int src_x = graphic_info[graphic].src_x;
849 int src_y = graphic_info[graphic].src_y;
850 int offset_x = graphic_info[graphic].offset_x;
851 int offset_y = graphic_info[graphic].offset_y;
853 src_x += frame * offset_x;
854 src_y += frame * offset_y;
857 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
860 void DrawGraphicThruMask(int x, int y, int graphic, int frame)
863 if (!IN_SCR_FIELD(x, y))
865 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
866 printf("DrawGraphicThruMask(): This should never happen!\n");
871 DrawGraphicThruMaskExt(drawto_field, FX + x * TILEX, FY + y *TILEY, graphic,
876 void DrawGraphicThruMaskExt(DrawBuffer *d, int dest_x, int dest_y, int graphic,
884 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
885 drawing_gc = src_bitmap->stored_clip_gc;
887 GC drawing_gc = src_bitmap->stored_clip_gc;
888 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
889 int src_x = graphic_info[graphic].src_x;
890 int src_y = graphic_info[graphic].src_y;
891 int offset_x = graphic_info[graphic].offset_x;
892 int offset_y = graphic_info[graphic].offset_y;
894 src_x += frame * offset_x;
895 src_y += frame * offset_y;
899 SetClipOrigin(src_bitmap, drawing_gc, dest_x - src_x, dest_y - src_y);
900 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX, TILEY, dest_x, dest_y);
903 void DrawMiniGraphic(int x, int y, int graphic)
905 DrawMiniGraphicExt(drawto, SX + x * MINI_TILEX,SY + y * MINI_TILEY, graphic);
906 MarkTileDirty(x / 2, y / 2);
909 void getMiniGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
911 struct GraphicInfo *g = &graphic_info[graphic];
913 int mini_starty = g->bitmap->height * 2 / 3;
916 *x = mini_startx + g->src_x / 2;
917 *y = mini_starty + g->src_y / 2;
920 void DrawMiniGraphicExt(DrawBuffer *d, int x, int y, int graphic)
925 getMiniGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
926 BlitBitmap(src_bitmap, d, src_x, src_y, MINI_TILEX, MINI_TILEY, x, y);
929 void DrawGraphicShifted(int x,int y, int dx,int dy, int graphic, int frame,
930 int cut_mode, int mask_mode)
935 int width = TILEX, height = TILEY;
941 DrawGraphic(x, y, graphic, frame);
945 if (dx || dy) /* shifted graphic */
947 if (x < BX1) /* object enters playfield from the left */
954 else if (x > BX2) /* object enters playfield from the right */
960 else if (x==BX1 && dx < 0) /* object leaves playfield to the left */
966 else if (x==BX2 && dx > 0) /* object leaves playfield to the right */
968 else if (dx) /* general horizontal movement */
969 MarkTileDirty(x + SIGN(dx), y);
971 if (y < BY1) /* object enters playfield from the top */
973 if (cut_mode==CUT_BELOW) /* object completely above top border */
981 else if (y > BY2) /* object enters playfield from the bottom */
987 else if (y==BY1 && dy < 0) /* object leaves playfield to the top */
993 else if (dy > 0 && cut_mode == CUT_ABOVE)
995 if (y == BY2) /* object completely above bottom border */
1001 MarkTileDirty(x, y + 1);
1002 } /* object leaves playfield to the bottom */
1003 else if (dy > 0 && (y == BY2 || cut_mode == CUT_BELOW))
1005 else if (dy) /* general vertical movement */
1006 MarkTileDirty(x, y + SIGN(dy));
1010 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1012 src_bitmap = graphic_info[graphic].bitmap;
1013 src_x = graphic_info[graphic].src_x;
1014 src_y = graphic_info[graphic].src_y;
1015 offset_x = graphic_info[graphic].offset_x;
1016 offset_y = graphic_info[graphic].offset_y;
1018 src_x += frame * offset_x;
1019 src_y += frame * offset_y;
1022 drawing_gc = src_bitmap->stored_clip_gc;
1027 dest_x = FX + x * TILEX + dx;
1028 dest_y = FY + y * TILEY + dy;
1031 if (!IN_SCR_FIELD(x,y))
1033 printf("DrawGraphicShifted(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
1034 printf("DrawGraphicShifted(): This should never happen!\n");
1039 if (mask_mode == USE_MASKING)
1041 SetClipOrigin(src_bitmap, drawing_gc, dest_x - src_x, dest_y - src_y);
1042 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1046 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1052 void DrawGraphicShiftedThruMask(int x, int y, int dx, int dy, int graphic,
1053 int frame, int cut_mode)
1055 DrawGraphicShifted(x,y, dx,dy, graphic, frame, cut_mode, USE_MASKING);
1058 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
1059 int cut_mode, int mask_mode)
1061 int lx = LEVELX(x), ly = LEVELY(y);
1065 if (IN_LEV_FIELD(lx, ly))
1067 SetRandomAnimationValue(lx, ly);
1069 graphic = el_act_dir2img(element, GfxAction[lx][ly], MovDir[lx][ly]);
1070 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1072 else /* border element */
1074 graphic = el2img(element);
1075 frame = getGraphicAnimationFrame(graphic, -1);
1078 if (element == EL_EXPANDABLE_WALL)
1080 boolean left_stopped = FALSE, right_stopped = FALSE;
1082 if (!IN_LEV_FIELD(lx - 1, ly) || IS_WALL(Feld[lx - 1][ly]))
1083 left_stopped = TRUE;
1084 if (!IN_LEV_FIELD(lx + 1, ly) || IS_WALL(Feld[lx + 1][ly]))
1085 right_stopped = TRUE;
1087 if (left_stopped && right_stopped)
1089 else if (left_stopped)
1091 graphic = IMG_EXPANDABLE_WALL_GROWING_RIGHT;
1092 frame = graphic_info[graphic].anim_frames - 1;
1094 else if (right_stopped)
1096 graphic = IMG_EXPANDABLE_WALL_GROWING_LEFT;
1097 frame = graphic_info[graphic].anim_frames - 1;
1101 else if (IS_AMOEBOID(element) || element == EL_AMOEBA_DROPPING)
1103 graphic = (element == EL_BD_AMOEBA ? IMG_BD_AMOEBA_PART1 :
1104 element == EL_AMOEBA_WET ? IMG_AMOEBA_WET_PART1 :
1105 element == EL_AMOEBA_DRY ? IMG_AMOEBA_DRY_PART1 :
1106 element == EL_AMOEBA_FULL ? IMG_AMOEBA_FULL_PART1 :
1107 IMG_AMOEBA_DEAD_PART1);
1109 graphic += (x + 2 * y + 4) % 4;
1114 if (IS_AMOEBOID(element) || element == EL_AMOEBA_DROPPING)
1116 if (Feld[lx][ly] == EL_AMOEBA_DROPPING)
1117 printf("---> %d -> %d / %d [%d]\n",
1118 element, graphic, frame, GfxRandom[lx][ly]);
1123 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, mask_mode);
1124 else if (mask_mode == USE_MASKING)
1125 DrawGraphicThruMask(x, y, graphic, frame);
1127 DrawGraphic(x, y, graphic, frame);
1130 void DrawLevelElementExt(int x, int y, int dx, int dy, int element,
1131 int cut_mode, int mask_mode)
1133 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1134 DrawScreenElementExt(SCREENX(x), SCREENY(y), dx, dy, element,
1135 cut_mode, mask_mode);
1138 void DrawScreenElementShifted(int x, int y, int dx, int dy, int element,
1141 DrawScreenElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1144 void DrawLevelElementShifted(int x, int y, int dx, int dy, int element,
1147 DrawLevelElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1151 void DrawOldScreenElementThruMask(int x, int y, int element)
1153 DrawOldScreenElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1156 void DrawScreenElementThruMask(int x, int y, int element)
1158 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1162 void DrawLevelElementThruMask(int x, int y, int element)
1164 DrawLevelElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1167 void DrawLevelFieldThruMask(int x, int y)
1169 DrawLevelElementExt(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
1172 static void DrawLevelFieldCrumbledSandExt(int x, int y, int graphic, int frame)
1176 int sx = SCREENX(x), sy = SCREENY(y);
1178 int width, height, cx, cy, i;
1179 int snip = TILEX / 8; /* number of border pixels from "crumbled graphic" */
1180 static int xy[4][2] =
1188 if (!IN_LEV_FIELD(x, y))
1191 element = (GfxElement[x][y] != EL_UNDEFINED ? GfxElement[x][y] : Feld[x][y]);
1193 /* crumble field itself */
1194 if (CAN_BE_CRUMBLED(element))
1196 if (!IN_SCR_FIELD(sx, sy))
1199 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1203 int xx = x + xy[i][0];
1204 int yy = y + xy[i][1];
1206 element = (IN_LEV_FIELD(xx, yy) ? Feld[xx][yy] : EL_STEELWALL);
1208 /* check if neighbour field is of same type */
1209 if (CAN_BE_CRUMBLED(element))
1212 if (i == 1 || i == 2)
1216 cx = (i == 2 ? TILEX - snip : 0);
1224 cy = (i == 3 ? TILEY - snip : 0);
1227 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1228 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
1231 MarkTileDirty(sx, sy);
1233 else /* crumble neighbour fields */
1235 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1239 int xx = x + xy[i][0];
1240 int yy = y + xy[i][1];
1241 int sxx = sx + xy[i][0];
1242 int syy = sy + xy[i][1];
1244 if (!IN_LEV_FIELD(xx, yy) ||
1245 !IN_SCR_FIELD(sxx, syy) ||
1246 !CAN_BE_CRUMBLED(Feld[xx][yy]))
1249 if (i == 1 || i == 2)
1253 cx = (i == 1 ? TILEX - snip : 0);
1261 cy = (i==0 ? TILEY-snip : 0);
1264 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1265 width, height, FX + sxx * TILEX + cx, FY + syy * TILEY + cy);
1267 MarkTileDirty(sxx, syy);
1272 void DrawLevelFieldCrumbledSand(int x, int y)
1274 DrawLevelFieldCrumbledSandExt(x, y, IMG_SAND_CRUMBLED, 0);
1277 void DrawLevelFieldCrumbledSandDigging(int x, int y, int direction,
1280 int graphic1 = el_act_dir2img(EL_SAND, ACTION_DIGGING, direction);
1281 int graphic2 = el_act_dir2img(EL_SAND_CRUMBLED, ACTION_DIGGING, direction);
1282 int frame1 = getGraphicAnimationFrame(graphic1, step_frame);
1283 int frame2 = getGraphicAnimationFrame(graphic2, step_frame);
1284 int sx = SCREENX(x), sy = SCREENY(y);
1286 DrawGraphic(sx, sy, graphic1, frame1);
1287 DrawLevelFieldCrumbledSandExt(x, y, graphic2, frame2);
1290 static int getBorderElement(int x, int y)
1294 { EL_STEELWALL_TOPLEFT, EL_INVISIBLE_STEELWALL_TOPLEFT },
1295 { EL_STEELWALL_TOPRIGHT, EL_INVISIBLE_STEELWALL_TOPRIGHT },
1296 { EL_STEELWALL_BOTTOMLEFT, EL_INVISIBLE_STEELWALL_BOTTOMLEFT },
1297 { EL_STEELWALL_BOTTOMRIGHT, EL_INVISIBLE_STEELWALL_BOTTOMRIGHT },
1298 { EL_STEELWALL_VERTICAL, EL_INVISIBLE_STEELWALL_VERTICAL },
1299 { EL_STEELWALL_HORIZONTAL, EL_INVISIBLE_STEELWALL_HORIZONTAL },
1300 { EL_STEELWALL, EL_INVISIBLE_STEELWALL }
1302 int steel_type = (BorderElement == EL_STEELWALL ? 0 : 1);
1303 int steel_position = (x == -1 && y == -1 ? 0 :
1304 x == lev_fieldx && y == -1 ? 1 :
1305 x == -1 && y == lev_fieldy ? 2 :
1306 x == lev_fieldx && y == lev_fieldy ? 3 :
1307 x == -1 || x == lev_fieldx ? 4 :
1308 y == -1 || y == lev_fieldy ? 5 : 6);
1310 return border[steel_position][steel_type];
1313 void DrawScreenElement(int x, int y, int element)
1315 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
1316 DrawLevelFieldCrumbledSand(LEVELX(x), LEVELY(y));
1319 void DrawLevelElement(int x, int y, int element)
1321 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1322 DrawScreenElement(SCREENX(x), SCREENY(y), element);
1325 void DrawScreenField(int x, int y)
1327 int lx = LEVELX(x), ly = LEVELY(y);
1328 int element, content;
1330 if (!IN_LEV_FIELD(lx, ly))
1332 if (lx < -1 || lx > lev_fieldx || ly < -1 || ly > lev_fieldy)
1335 element = getBorderElement(lx, ly);
1337 DrawScreenElement(x, y, element);
1341 element = Feld[lx][ly];
1342 content = Store[lx][ly];
1344 if (IS_MOVING(lx, ly))
1346 int horiz_move = (MovDir[lx][ly] == MV_LEFT || MovDir[lx][ly] == MV_RIGHT);
1347 boolean cut_mode = NO_CUTTING;
1349 if (element == EL_QUICKSAND_EMPTYING ||
1350 element == EL_MAGIC_WALL_EMPTYING ||
1351 element == EL_BD_MAGIC_WALL_EMPTYING ||
1352 element == EL_AMOEBA_DROPPING)
1353 cut_mode = CUT_ABOVE;
1354 else if (element == EL_QUICKSAND_FILLING ||
1355 element == EL_MAGIC_WALL_FILLING ||
1356 element == EL_BD_MAGIC_WALL_FILLING)
1357 cut_mode = CUT_BELOW;
1359 if (cut_mode == CUT_ABOVE)
1360 DrawScreenElementShifted(x, y, 0, 0, element, NO_CUTTING);
1362 DrawScreenElement(x, y, EL_EMPTY);
1365 DrawScreenElementShifted(x, y, MovPos[lx][ly], 0, element, NO_CUTTING);
1366 else if (cut_mode == NO_CUTTING)
1367 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], element, cut_mode);
1369 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], content, cut_mode);
1371 if (content == EL_ACID)
1372 DrawLevelElementThruMask(lx, ly + 1, EL_ACID);
1374 else if (IS_BLOCKED(lx, ly))
1379 boolean cut_mode = NO_CUTTING;
1380 int element_old, content_old;
1382 Blocked2Moving(lx, ly, &oldx, &oldy);
1385 horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
1386 MovDir[oldx][oldy] == MV_RIGHT);
1388 element_old = Feld[oldx][oldy];
1389 content_old = Store[oldx][oldy];
1391 if (element_old == EL_QUICKSAND_EMPTYING ||
1392 element_old == EL_MAGIC_WALL_EMPTYING ||
1393 element_old == EL_BD_MAGIC_WALL_EMPTYING ||
1394 element_old == EL_AMOEBA_DROPPING)
1395 cut_mode = CUT_ABOVE;
1397 DrawScreenElement(x, y, EL_EMPTY);
1400 DrawScreenElementShifted(sx, sy, MovPos[oldx][oldy], 0, element_old,
1402 else if (cut_mode == NO_CUTTING)
1403 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], element_old,
1406 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], content_old,
1409 else if (IS_DRAWABLE(element))
1410 DrawScreenElement(x, y, element);
1412 DrawScreenElement(x, y, EL_EMPTY);
1415 void DrawLevelField(int x, int y)
1417 if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1418 DrawScreenField(SCREENX(x), SCREENY(y));
1419 else if (IS_MOVING(x, y))
1423 Moving2Blocked(x, y, &newx, &newy);
1424 if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
1425 DrawScreenField(SCREENX(newx), SCREENY(newy));
1427 else if (IS_BLOCKED(x, y))
1431 Blocked2Moving(x, y, &oldx, &oldy);
1432 if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
1433 DrawScreenField(SCREENX(oldx), SCREENY(oldy));
1437 void DrawMiniElement(int x, int y, int element)
1441 graphic = el2edimg(element);
1442 DrawMiniGraphic(x, y, graphic);
1445 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
1447 int x = sx + scroll_x, y = sy + scroll_y;
1449 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
1450 DrawMiniElement(sx, sy, EL_EMPTY);
1451 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
1452 DrawMiniElement(sx, sy, Feld[x][y]);
1454 DrawMiniGraphic(sx, sy, el2edimg(getBorderElement(x, y)));
1457 void getMicroGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
1459 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
1460 int mini_startx = src_bitmap->width * 3 / 4;
1461 int mini_starty = src_bitmap->height * 2 / 3;
1462 int src_x = mini_startx + graphic_info[graphic].src_x / 8;
1463 int src_y = mini_starty + graphic_info[graphic].src_y / 8;
1466 if (src_x + MICRO_TILEX > src_bitmap->width ||
1467 src_y + MICRO_TILEY > src_bitmap->height)
1469 /* graphic of desired size seems not to be contained in this image;
1470 dirty workaround: get it from the middle of the normal sized image */
1472 getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
1473 src_x += (TILEX / 2 - MICRO_TILEX / 2);
1474 src_y += (TILEY / 2 - MICRO_TILEY / 2);
1478 *bitmap = src_bitmap;
1483 void DrawMicroElement(int xpos, int ypos, int element)
1487 int graphic = el2preimg(element);
1489 getMicroGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
1490 BlitBitmap(src_bitmap, drawto, src_x, src_y, MICRO_TILEX, MICRO_TILEY,
1498 SetDrawBackgroundMask(REDRAW_NONE);
1501 for(x=BX1; x<=BX2; x++)
1502 for(y=BY1; y<=BY2; y++)
1503 DrawScreenField(x, y);
1505 redraw_mask |= REDRAW_FIELD;
1508 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
1512 for(x=0; x<size_x; x++)
1513 for(y=0; y<size_y; y++)
1514 DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
1516 redraw_mask |= REDRAW_FIELD;
1519 static void DrawMicroLevelExt(int xpos, int ypos, int from_x, int from_y)
1523 DrawBackground(xpos, ypos, MICROLEV_XSIZE, MICROLEV_YSIZE);
1525 if (lev_fieldx < STD_LEV_FIELDX)
1526 xpos += (STD_LEV_FIELDX - lev_fieldx) / 2 * MICRO_TILEX;
1527 if (lev_fieldy < STD_LEV_FIELDY)
1528 ypos += (STD_LEV_FIELDY - lev_fieldy) / 2 * MICRO_TILEY;
1530 xpos += MICRO_TILEX;
1531 ypos += MICRO_TILEY;
1533 for(x=-1; x<=STD_LEV_FIELDX; x++)
1535 for(y=-1; y<=STD_LEV_FIELDY; y++)
1537 int lx = from_x + x, ly = from_y + y;
1539 if (lx >= 0 && lx < lev_fieldx && ly >= 0 && ly < lev_fieldy)
1540 DrawMicroElement(xpos + x * MICRO_TILEX, ypos + y * MICRO_TILEY,
1542 else if (lx >= -1 && lx < lev_fieldx+1 && ly >= -1 && ly < lev_fieldy+1
1543 && BorderElement != EL_EMPTY)
1544 DrawMicroElement(xpos + x * MICRO_TILEX, ypos + y * MICRO_TILEY,
1545 getBorderElement(lx, ly));
1549 redraw_mask |= REDRAW_MICROLEVEL;
1552 #define MICROLABEL_EMPTY 0
1553 #define MICROLABEL_LEVEL_NAME 1
1554 #define MICROLABEL_CREATED_BY 2
1555 #define MICROLABEL_LEVEL_AUTHOR 3
1556 #define MICROLABEL_IMPORTED_FROM 4
1557 #define MICROLABEL_LEVEL_IMPORT_INFO 5
1559 static void DrawMicroLevelLabelExt(int mode)
1561 char label_text[MAX_OUTPUT_LINESIZE + 1];
1562 int max_len_label_text;
1563 int font_nr = FONT_TEXT_2;
1565 if (mode == MICROLABEL_CREATED_BY || mode == MICROLABEL_IMPORTED_FROM)
1566 font_nr = FONT_TEXT_3;
1568 max_len_label_text = SXSIZE / getFontWidth(font_nr);
1570 DrawBackground(SX, MICROLABEL_YPOS, SXSIZE, getFontHeight(font_nr));
1572 strncpy(label_text, (mode == MICROLABEL_LEVEL_NAME ? level.name :
1573 mode == MICROLABEL_CREATED_BY ? "created by" :
1574 mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
1575 mode == MICROLABEL_IMPORTED_FROM ? "imported from" :
1576 mode == MICROLABEL_LEVEL_IMPORT_INFO ?
1577 leveldir_current->imported_from : ""),
1578 max_len_label_text);
1579 label_text[max_len_label_text] = '\0';
1581 if (strlen(label_text) > 0)
1583 int text_width = strlen(label_text) * getFontWidth(font_nr);
1584 int lxpos = SX + (SXSIZE - text_width) / 2;
1585 int lypos = MICROLABEL_YPOS;
1587 DrawText(lxpos, lypos, label_text, font_nr);
1590 redraw_mask |= REDRAW_MICROLEVEL;
1593 void DrawMicroLevel(int xpos, int ypos, boolean restart)
1595 static unsigned long scroll_delay = 0;
1596 static unsigned long label_delay = 0;
1597 static int from_x, from_y, scroll_direction;
1598 static int label_state, label_counter;
1599 int last_game_status = game_status; /* save current game status */
1601 /* force PREVIEW font on preview level */
1602 game_status = GAME_MODE_PSEUDO_PREVIEW;
1606 from_x = from_y = 0;
1607 scroll_direction = MV_RIGHT;
1611 DrawMicroLevelExt(xpos, ypos, from_x, from_y);
1612 DrawMicroLevelLabelExt(label_state);
1614 /* initialize delay counters */
1615 DelayReached(&scroll_delay, 0);
1616 DelayReached(&label_delay, 0);
1618 if (leveldir_current->name)
1620 int len = strlen(leveldir_current->name);
1621 int lxpos = SX + (SXSIZE - len * getFontWidth(FONT_TEXT_1)) / 2;
1622 int lypos = SY + 352;
1624 DrawText(lxpos, lypos, leveldir_current->name, FONT_TEXT_1);
1627 game_status = last_game_status; /* restore current game status */
1632 /* scroll micro level, if needed */
1633 if ((lev_fieldx > STD_LEV_FIELDX || lev_fieldy > STD_LEV_FIELDY) &&
1634 DelayReached(&scroll_delay, MICROLEVEL_SCROLL_DELAY))
1636 switch (scroll_direction)
1642 scroll_direction = MV_UP;
1646 if (from_x < lev_fieldx - STD_LEV_FIELDX)
1649 scroll_direction = MV_DOWN;
1656 scroll_direction = MV_RIGHT;
1660 if (from_y < lev_fieldy - STD_LEV_FIELDY)
1663 scroll_direction = MV_LEFT;
1670 DrawMicroLevelExt(xpos, ypos, from_x, from_y);
1673 /* redraw micro level label, if needed */
1674 if (strcmp(level.name, NAMELESS_LEVEL_NAME) != 0 &&
1675 strcmp(level.author, ANONYMOUS_NAME) != 0 &&
1676 strcmp(level.author, leveldir_current->name) != 0 &&
1677 DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
1679 int max_label_counter = 23;
1681 if (leveldir_current->imported_from != NULL)
1682 max_label_counter += 14;
1684 label_counter = (label_counter + 1) % max_label_counter;
1685 label_state = (label_counter >= 0 && label_counter <= 7 ?
1686 MICROLABEL_LEVEL_NAME :
1687 label_counter >= 9 && label_counter <= 12 ?
1688 MICROLABEL_CREATED_BY :
1689 label_counter >= 14 && label_counter <= 21 ?
1690 MICROLABEL_LEVEL_AUTHOR :
1691 label_counter >= 23 && label_counter <= 26 ?
1692 MICROLABEL_IMPORTED_FROM :
1693 label_counter >= 28 && label_counter <= 35 ?
1694 MICROLABEL_LEVEL_IMPORT_INFO : MICROLABEL_EMPTY);
1695 DrawMicroLevelLabelExt(label_state);
1698 game_status = last_game_status; /* restore current game status */
1701 int REQ_in_range(int x, int y)
1703 if (y > DY+249 && y < DY+278)
1705 if (x > DX+1 && x < DX+48)
1707 else if (x > DX+51 && x < DX+98)
1713 #define MAX_REQUEST_LINES 13
1714 #define MAX_REQUEST_LINE_LEN 7
1716 boolean Request(char *text, unsigned int req_state)
1718 int mx, my, ty, result = -1;
1719 unsigned int old_door_state;
1720 int last_game_status = game_status; /* save current game status */
1722 #if defined(PLATFORM_UNIX)
1723 /* pause network game while waiting for request to answer */
1724 if (options.network &&
1725 game_status == GAME_MODE_PLAYING &&
1726 req_state & REQUEST_WAIT_FOR)
1727 SendToServer_PausePlaying();
1730 old_door_state = GetDoorState();
1734 CloseDoor(DOOR_CLOSE_1);
1736 /* save old door content */
1737 BlitBitmap(bitmap_db_door, bitmap_db_door,
1738 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
1739 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
1741 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
1743 /* clear door drawing field */
1744 DrawBackground(DX, DY, DXSIZE, DYSIZE);
1746 /* force DOOR font on preview level */
1747 game_status = GAME_MODE_PSEUDO_DOOR;
1749 /* write text for request */
1750 for(ty=0; ty < MAX_REQUEST_LINES; ty++)
1752 char text_line[MAX_REQUEST_LINE_LEN + 1];
1758 for(tl=0,tx=0; tx < MAX_REQUEST_LINE_LEN; tl++,tx++)
1761 if (!tc || tc == ' ')
1772 strncpy(text_line, text, tl);
1775 DrawText(DX + (DXSIZE - tl * getFontWidth(FONT_TEXT_2)) / 2,
1776 DY + 8 + ty * (getFontHeight(FONT_TEXT_2) + 2),
1777 text_line, FONT_TEXT_2);
1779 text += tl + (tc == ' ' ? 1 : 0);
1782 game_status = last_game_status; /* restore current game status */
1784 if (req_state & REQ_ASK)
1786 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
1787 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
1789 else if (req_state & REQ_CONFIRM)
1791 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
1793 else if (req_state & REQ_PLAYER)
1795 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
1796 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
1797 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
1798 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
1801 /* copy request gadgets to door backbuffer */
1802 BlitBitmap(drawto, bitmap_db_door,
1803 DX, DY, DXSIZE, DYSIZE,
1804 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
1806 OpenDoor(DOOR_OPEN_1);
1812 if (!(req_state & REQUEST_WAIT_FOR))
1814 SetDrawBackgroundMask(REDRAW_FIELD);
1819 if (game_status != GAME_MODE_MAIN)
1822 button_status = MB_RELEASED;
1824 request_gadget_id = -1;
1826 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
1838 case EVENT_BUTTONPRESS:
1839 case EVENT_BUTTONRELEASE:
1840 case EVENT_MOTIONNOTIFY:
1842 if (event.type == EVENT_MOTIONNOTIFY)
1844 if (!PointerInWindow(window))
1845 continue; /* window and pointer are on different screens */
1850 motion_status = TRUE;
1851 mx = ((MotionEvent *) &event)->x;
1852 my = ((MotionEvent *) &event)->y;
1856 motion_status = FALSE;
1857 mx = ((ButtonEvent *) &event)->x;
1858 my = ((ButtonEvent *) &event)->y;
1859 if (event.type == EVENT_BUTTONPRESS)
1860 button_status = ((ButtonEvent *) &event)->button;
1862 button_status = MB_RELEASED;
1865 /* this sets 'request_gadget_id' */
1866 HandleGadgets(mx, my, button_status);
1868 switch(request_gadget_id)
1870 case TOOL_CTRL_ID_YES:
1873 case TOOL_CTRL_ID_NO:
1876 case TOOL_CTRL_ID_CONFIRM:
1877 result = TRUE | FALSE;
1880 case TOOL_CTRL_ID_PLAYER_1:
1883 case TOOL_CTRL_ID_PLAYER_2:
1886 case TOOL_CTRL_ID_PLAYER_3:
1889 case TOOL_CTRL_ID_PLAYER_4:
1900 case EVENT_KEYPRESS:
1901 switch(GetEventKey((KeyEvent *)&event, TRUE))
1914 if (req_state & REQ_PLAYER)
1918 case EVENT_KEYRELEASE:
1919 ClearPlayerAction();
1923 HandleOtherEvents(&event);
1927 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
1929 int joy = AnyJoystick();
1931 if (joy & JOY_BUTTON_1)
1933 else if (joy & JOY_BUTTON_2)
1939 /* don't eat all CPU time */
1943 if (game_status != GAME_MODE_MAIN)
1948 if (!(req_state & REQ_STAY_OPEN))
1950 CloseDoor(DOOR_CLOSE_1);
1952 if (!(req_state & REQ_STAY_CLOSED) && (old_door_state & DOOR_OPEN_1))
1954 BlitBitmap(bitmap_db_door, bitmap_db_door,
1955 DOOR_GFX_PAGEX2,DOOR_GFX_PAGEY1, DXSIZE,DYSIZE,
1956 DOOR_GFX_PAGEX1,DOOR_GFX_PAGEY1);
1957 OpenDoor(DOOR_OPEN_1);
1963 SetDrawBackgroundMask(REDRAW_FIELD);
1965 #if defined(PLATFORM_UNIX)
1966 /* continue network game after request */
1967 if (options.network &&
1968 game_status == GAME_MODE_PLAYING &&
1969 req_state & REQUEST_WAIT_FOR)
1970 SendToServer_ContinuePlaying();
1976 unsigned int OpenDoor(unsigned int door_state)
1978 unsigned int new_door_state;
1980 if (door_state & DOOR_COPY_BACK)
1982 BlitBitmap(bitmap_db_door, bitmap_db_door,
1983 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE + VYSIZE,
1984 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
1985 door_state &= ~DOOR_COPY_BACK;
1988 new_door_state = MoveDoor(door_state);
1990 return(new_door_state);
1993 unsigned int CloseDoor(unsigned int door_state)
1995 unsigned int new_door_state;
1997 BlitBitmap(backbuffer, bitmap_db_door,
1998 DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
1999 BlitBitmap(backbuffer, bitmap_db_door,
2000 VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
2002 new_door_state = MoveDoor(door_state);
2004 return(new_door_state);
2007 unsigned int GetDoorState()
2009 return MoveDoor(DOOR_GET_STATE);
2012 unsigned int SetDoorState(unsigned int door_state)
2014 return MoveDoor(door_state | DOOR_SET_STATE);
2017 unsigned int MoveDoor(unsigned int door_state)
2019 static int door1 = DOOR_OPEN_1;
2020 static int door2 = DOOR_CLOSE_2;
2021 static unsigned long door_delay = 0;
2022 int x, start, stepsize = door.step_offset;
2023 unsigned long door_delay_value = door.step_delay;
2025 if (door_state == DOOR_GET_STATE)
2026 return(door1 | door2);
2028 if (door_state & DOOR_SET_STATE)
2030 if (door_state & DOOR_ACTION_1)
2031 door1 = door_state & DOOR_ACTION_1;
2032 if (door_state & DOOR_ACTION_2)
2033 door2 = door_state & DOOR_ACTION_2;
2035 return(door1 | door2);
2038 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
2039 door_state &= ~DOOR_OPEN_1;
2040 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
2041 door_state &= ~DOOR_CLOSE_1;
2042 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
2043 door_state &= ~DOOR_OPEN_2;
2044 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
2045 door_state &= ~DOOR_CLOSE_2;
2047 if (setup.quick_doors)
2050 door_delay_value = 0;
2052 StopSound(SND_DOOR_OPENING);
2053 StopSound(SND_DOOR_CLOSING);
2056 if (global.autoplay_leveldir)
2058 door_state |= DOOR_NO_DELAY;
2059 door_state &= ~DOOR_CLOSE_ALL;
2062 if (door_state & DOOR_ACTION)
2064 if (!(door_state & DOOR_NO_DELAY))
2066 /* opening door sound has priority over simultaneously closing door */
2067 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
2068 PlaySoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
2069 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
2070 PlaySoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
2073 start = ((door_state & DOOR_NO_DELAY) ? DXSIZE : 0);
2075 for(x=start; x<=DXSIZE; x+=stepsize)
2077 Bitmap *bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
2078 GC gc = bitmap->stored_clip_gc;
2080 if (!(door_state & DOOR_NO_DELAY))
2081 WaitUntilDelayReached(&door_delay, door_delay_value);
2083 if (door_state & DOOR_ACTION_1)
2085 int i = (door_state & DOOR_OPEN_1 ? DXSIZE-x : x);
2086 int j = (DXSIZE - i) / 3;
2088 BlitBitmap(bitmap_db_door, drawto,
2089 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + i/2,
2090 DXSIZE,DYSIZE - i/2, DX, DY);
2092 ClearRectangle(drawto, DX, DY + DYSIZE - i/2, DXSIZE,i/2);
2094 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2095 BlitBitmapMasked(bitmap, drawto,
2096 DXSIZE, DOOR_GFX_PAGEY1, i, 77,
2097 DX + DXSIZE - i, DY + j);
2098 BlitBitmapMasked(bitmap, drawto,
2099 DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63,
2100 DX + DXSIZE - i, DY + 140 + j);
2101 SetClipOrigin(bitmap, gc, DX - DXSIZE + i, DY - (DOOR_GFX_PAGEY1 + j));
2102 BlitBitmapMasked(bitmap, drawto,
2103 DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j,
2105 BlitBitmapMasked(bitmap, drawto,
2106 DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63,
2109 BlitBitmapMasked(bitmap, drawto,
2110 DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
2112 BlitBitmapMasked(bitmap, drawto,
2113 DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
2115 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2116 BlitBitmapMasked(bitmap, drawto,
2117 DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
2118 DX + DXSIZE - i, DY + 77 + j);
2119 BlitBitmapMasked(bitmap, drawto,
2120 DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
2121 DX + DXSIZE - i, DY + 203 + j);
2123 redraw_mask |= REDRAW_DOOR_1;
2126 if (door_state & DOOR_ACTION_2)
2128 int i = (door_state & DOOR_OPEN_2 ? VXSIZE - x : x);
2129 int j = (VXSIZE - i) / 3;
2131 BlitBitmap(bitmap_db_door, drawto,
2132 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + i/2,
2133 VXSIZE, VYSIZE - i/2, VX, VY);
2135 ClearRectangle(drawto, VX, VY + VYSIZE-i/2, VXSIZE, i/2);
2137 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2138 BlitBitmapMasked(bitmap, drawto,
2139 VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2,
2140 VX + VXSIZE-i, VY+j);
2141 SetClipOrigin(bitmap, gc,
2142 VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
2143 BlitBitmapMasked(bitmap, drawto,
2144 VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j,
2147 BlitBitmapMasked(bitmap, drawto,
2148 VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2,
2149 i, VYSIZE / 2, VX, VY + VYSIZE / 2 - j);
2150 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2151 BlitBitmapMasked(bitmap, drawto,
2152 VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2,
2154 VX + VXSIZE - i, VY + VYSIZE / 2 + j);
2156 redraw_mask |= REDRAW_DOOR_2;
2161 if (game_status == GAME_MODE_MAIN)
2166 if (setup.quick_doors)
2168 StopSound(SND_DOOR_OPENING);
2169 StopSound(SND_DOOR_CLOSING);
2172 if (door_state & DOOR_ACTION_1)
2173 door1 = door_state & DOOR_ACTION_1;
2174 if (door_state & DOOR_ACTION_2)
2175 door2 = door_state & DOOR_ACTION_2;
2177 return (door1 | door2);
2180 void DrawSpecialEditorDoor()
2182 /* draw bigger toolbox window */
2183 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
2184 DOOR_GFX_PAGEX7, 0, EXSIZE + 8, 8,
2186 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
2187 EX - 4, VY - 4, EXSIZE + 8, EYSIZE - VYSIZE + 4,
2190 redraw_mask |= REDRAW_ALL;
2193 void UndrawSpecialEditorDoor()
2195 /* draw normal tape recorder window */
2196 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
2197 EX - 4, EY - 12, EXSIZE + 8, EYSIZE - VYSIZE + 12,
2200 redraw_mask |= REDRAW_ALL;
2204 /* ---------- new tool button stuff ---------------------------------------- */
2206 /* graphic position values for tool buttons */
2207 #define TOOL_BUTTON_YES_XPOS 2
2208 #define TOOL_BUTTON_YES_YPOS 250
2209 #define TOOL_BUTTON_YES_GFX_YPOS 0
2210 #define TOOL_BUTTON_YES_XSIZE 46
2211 #define TOOL_BUTTON_YES_YSIZE 28
2212 #define TOOL_BUTTON_NO_XPOS 52
2213 #define TOOL_BUTTON_NO_YPOS TOOL_BUTTON_YES_YPOS
2214 #define TOOL_BUTTON_NO_GFX_YPOS TOOL_BUTTON_YES_GFX_YPOS
2215 #define TOOL_BUTTON_NO_XSIZE TOOL_BUTTON_YES_XSIZE
2216 #define TOOL_BUTTON_NO_YSIZE TOOL_BUTTON_YES_YSIZE
2217 #define TOOL_BUTTON_CONFIRM_XPOS TOOL_BUTTON_YES_XPOS
2218 #define TOOL_BUTTON_CONFIRM_YPOS TOOL_BUTTON_YES_YPOS
2219 #define TOOL_BUTTON_CONFIRM_GFX_YPOS 30
2220 #define TOOL_BUTTON_CONFIRM_XSIZE 96
2221 #define TOOL_BUTTON_CONFIRM_YSIZE TOOL_BUTTON_YES_YSIZE
2222 #define TOOL_BUTTON_PLAYER_XSIZE 30
2223 #define TOOL_BUTTON_PLAYER_YSIZE 30
2224 #define TOOL_BUTTON_PLAYER_GFX_XPOS 5
2225 #define TOOL_BUTTON_PLAYER_GFX_YPOS 185
2226 #define TOOL_BUTTON_PLAYER_XPOS (5 + TOOL_BUTTON_PLAYER_XSIZE / 2)
2227 #define TOOL_BUTTON_PLAYER_YPOS (215 - TOOL_BUTTON_PLAYER_YSIZE / 2)
2228 #define TOOL_BUTTON_PLAYER1_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2229 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2230 #define TOOL_BUTTON_PLAYER2_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2231 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2232 #define TOOL_BUTTON_PLAYER3_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2233 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2234 #define TOOL_BUTTON_PLAYER4_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2235 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2236 #define TOOL_BUTTON_PLAYER1_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2237 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2238 #define TOOL_BUTTON_PLAYER2_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2239 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2240 #define TOOL_BUTTON_PLAYER3_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2241 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2242 #define TOOL_BUTTON_PLAYER4_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2243 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2252 } toolbutton_info[NUM_TOOL_BUTTONS] =
2255 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_GFX_YPOS,
2256 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_YPOS,
2257 TOOL_BUTTON_YES_XSIZE, TOOL_BUTTON_YES_YSIZE,
2262 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_GFX_YPOS,
2263 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_YPOS,
2264 TOOL_BUTTON_NO_XSIZE, TOOL_BUTTON_NO_YSIZE,
2269 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_GFX_YPOS,
2270 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_YPOS,
2271 TOOL_BUTTON_CONFIRM_XSIZE, TOOL_BUTTON_CONFIRM_YSIZE,
2272 TOOL_CTRL_ID_CONFIRM,
2276 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2277 TOOL_BUTTON_PLAYER1_XPOS, TOOL_BUTTON_PLAYER1_YPOS,
2278 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2279 TOOL_CTRL_ID_PLAYER_1,
2283 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2284 TOOL_BUTTON_PLAYER2_XPOS, TOOL_BUTTON_PLAYER2_YPOS,
2285 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2286 TOOL_CTRL_ID_PLAYER_2,
2290 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2291 TOOL_BUTTON_PLAYER3_XPOS, TOOL_BUTTON_PLAYER3_YPOS,
2292 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2293 TOOL_CTRL_ID_PLAYER_3,
2297 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2298 TOOL_BUTTON_PLAYER4_XPOS, TOOL_BUTTON_PLAYER4_YPOS,
2299 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2300 TOOL_CTRL_ID_PLAYER_4,
2305 void CreateToolButtons()
2309 for (i=0; i<NUM_TOOL_BUTTONS; i++)
2311 Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
2312 Bitmap *deco_bitmap = None;
2313 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
2314 struct GadgetInfo *gi;
2315 unsigned long event_mask;
2316 int gd_xoffset, gd_yoffset;
2317 int gd_x1, gd_x2, gd_y;
2320 event_mask = GD_EVENT_RELEASED;
2322 gd_xoffset = toolbutton_info[i].xpos;
2323 gd_yoffset = toolbutton_info[i].ypos;
2324 gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
2325 gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
2326 gd_y = DOOR_GFX_PAGEY1 + gd_yoffset;
2328 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
2330 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
2332 getMiniGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr),
2333 &deco_bitmap, &deco_x, &deco_y);
2334 deco_xpos = (toolbutton_info[i].width - MINI_TILEX) / 2;
2335 deco_ypos = (toolbutton_info[i].height - MINI_TILEY) / 2;
2338 gi = CreateGadget(GDI_CUSTOM_ID, id,
2339 GDI_INFO_TEXT, toolbutton_info[i].infotext,
2340 GDI_X, DX + toolbutton_info[i].x,
2341 GDI_Y, DY + toolbutton_info[i].y,
2342 GDI_WIDTH, toolbutton_info[i].width,
2343 GDI_HEIGHT, toolbutton_info[i].height,
2344 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
2345 GDI_STATE, GD_BUTTON_UNPRESSED,
2346 GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
2347 GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
2348 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
2349 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
2350 GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
2351 GDI_DECORATION_SHIFTING, 1, 1,
2352 GDI_EVENT_MASK, event_mask,
2353 GDI_CALLBACK_ACTION, HandleToolButtons,
2357 Error(ERR_EXIT, "cannot create gadget");
2359 tool_gadget[id] = gi;
2363 void FreeToolButtons()
2367 for (i=0; i<NUM_TOOL_BUTTONS; i++)
2368 FreeGadget(tool_gadget[i]);
2371 static void UnmapToolButtons()
2375 for (i=0; i<NUM_TOOL_BUTTONS; i++)
2376 UnmapGadget(tool_gadget[i]);
2379 static void HandleToolButtons(struct GadgetInfo *gi)
2381 request_gadget_id = gi->custom_id;
2384 int get_next_element(int element)
2388 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
2389 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
2390 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
2391 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
2392 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
2393 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
2394 case EL_AMOEBA_DROPPING: return EL_AMOEBA_WET;
2396 default: return element;
2400 int el_act_dir2img(int element, int action, int direction)
2402 element = GFX_ELEMENT(element);
2403 direction = MV_DIR_BIT(direction);
2405 return element_info[element].direction_graphic[action][direction];
2408 int el_act2img(int element, int action)
2410 element = GFX_ELEMENT(element);
2412 return element_info[element].graphic[action];
2415 int el_dir2img(int element, int direction)
2417 element = GFX_ELEMENT(element);
2419 return el_act_dir2img(element, ACTION_DEFAULT, direction);
2422 int el2img(int element)
2424 element = GFX_ELEMENT(element);
2426 return element_info[element].graphic[ACTION_DEFAULT];
2429 int el2edimg(int element)
2431 element = GFX_ELEMENT(element);
2433 return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
2436 int el2preimg(int element)
2438 element = GFX_ELEMENT(element);
2440 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];