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)
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);
546 int move_dir = player->MovDir;
547 int action = ACTION_DEFAULT;
549 if (!player->active || !IN_SCR_FIELD(SCREENX(last_jx), SCREENY(last_jy)))
553 if (!IN_LEV_FIELD(jx,jy))
555 printf("DrawPlayerField(): x = %d, y = %d\n",jx,jy);
556 printf("DrawPlayerField(): sx = %d, sy = %d\n",sx,sy);
557 printf("DrawPlayerField(): This should never happen!\n");
562 if (element == EL_EXPLOSION)
565 action = (player->Pushing ? ACTION_PUSHING :
566 player->is_digging ? ACTION_DIGGING :
567 player->is_collecting ? ACTION_COLLECTING :
568 player->is_moving ? ACTION_MOVING :
569 player->snapped ? ACTION_SNAPPING : ACTION_DEFAULT);
571 InitPlayerGfxAnimation(player, action, move_dir);
573 /* ----------------------------------------------------------------------- */
574 /* draw things in the field the player is leaving, if needed */
575 /* ----------------------------------------------------------------------- */
577 if (player_is_moving)
579 if (Back[last_jx][last_jy] && IS_DRAWABLE(last_element))
581 DrawLevelElement(last_jx, last_jy, Back[last_jx][last_jy]);
583 if (last_element == EL_DYNAMITE_ACTIVE ||
584 last_element == EL_SP_DISK_RED_ACTIVE)
585 DrawDynamite(last_jx, last_jy);
587 DrawLevelFieldThruMask(last_jx, last_jy);
589 else if (last_element == EL_DYNAMITE_ACTIVE ||
590 last_element == EL_SP_DISK_RED_ACTIVE)
591 DrawDynamite(last_jx, last_jy);
593 DrawLevelField(last_jx, last_jy);
595 if (player->Pushing && IN_SCR_FIELD(SCREENX(next_jx), SCREENY(next_jy)))
599 if (Feld[next_jx][next_jy] == EL_SOKOBAN_FIELD_FULL)
600 DrawLevelElement(next_jx, next_jy, EL_SOKOBAN_FIELD_EMPTY);
602 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
605 DrawLevelField(next_jx, next_jy);
609 if (!IN_SCR_FIELD(sx, sy))
612 if (setup.direct_draw)
613 SetDrawtoField(DRAW_BUFFERED);
615 /* ----------------------------------------------------------------------- */
616 /* draw things behind the player, if needed */
617 /* ----------------------------------------------------------------------- */
620 DrawLevelElement(jx, jy, Back[jx][jy]);
621 else if (IS_ACTIVE_BOMB(element))
622 DrawLevelElement(jx, jy, EL_EMPTY);
625 if (player_is_moving && GfxElement[jx][jy] != EL_UNDEFINED)
627 if (GfxElement[jx][jy] == EL_SAND)
628 DrawLevelFieldCrumbledSandDigging(jx, jy, move_dir, player->StepFrame);
631 int old_element = GfxElement[jx][jy];
632 int old_graphic = el_act_dir2img(old_element, action, move_dir);
633 int frame = getGraphicAnimationFrame(old_graphic, player->StepFrame);
635 DrawGraphic(sx, sy, old_graphic, frame);
640 GfxElement[jx][jy] = EL_UNDEFINED;
642 DrawLevelField(jx, jy);
646 /* ----------------------------------------------------------------------- */
647 /* draw player himself */
648 /* ----------------------------------------------------------------------- */
650 if (player->use_murphy_graphic)
652 static int last_horizontal_dir = MV_LEFT;
655 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
656 last_horizontal_dir = move_dir;
658 direction = (player->snapped ? move_dir : last_horizontal_dir);
660 graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, direction);
663 graphic = el_act_dir2img(player->element_nr, player->GfxAction, move_dir);
665 frame = getGraphicAnimationFrame(graphic, player->Frame);
669 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
670 sxx = player->GfxPos;
672 syy = player->GfxPos;
675 if (!setup.soft_scrolling && ScreenMovPos)
678 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
680 if (SHIELD_ON(player))
682 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
683 IMG_SHIELD_NORMAL_ACTIVE);
684 int frame = getGraphicAnimationFrame(graphic, -1);
686 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
689 /* ----------------------------------------------------------------------- */
690 /* draw things the player is pushing, if needed */
691 /* ----------------------------------------------------------------------- */
693 if (player->Pushing && player_is_moving)
695 int px = SCREENX(next_jx), py = SCREENY(next_jy);
698 (element == EL_SOKOBAN_FIELD_EMPTY ||
699 Feld[next_jx][next_jy] == EL_SOKOBAN_FIELD_FULL))
700 DrawGraphicShiftedThruMask(px, py, sxx, syy, IMG_SOKOBAN_OBJECT, 0,
704 int element = Feld[next_jx][next_jy];
705 int graphic = el2img(element);
708 if ((sxx || syy) && IS_PUSHABLE(element))
710 graphic = el_act_dir2img(element, ACTION_MOVING, move_dir);
711 frame = getGraphicAnimationFrame(graphic, player->Frame);
714 DrawGraphicShifted(px, py, sxx, syy, graphic, frame,
715 NO_CUTTING, NO_MASKING);
719 /* ----------------------------------------------------------------------- */
720 /* draw things in front of player (active dynamite or dynabombs) */
721 /* ----------------------------------------------------------------------- */
723 if (IS_ACTIVE_BOMB(element))
725 graphic = el2img(element);
726 frame = getGraphicAnimationFrame(graphic, GfxFrame[jx][jy]);
728 if (game.emulation == EMU_SUPAPLEX)
729 DrawGraphic(sx, sy, IMG_SP_DISK_RED, frame);
731 DrawGraphicThruMask(sx, sy, graphic, frame);
734 if (player_is_moving && last_element == EL_EXPLOSION)
736 int stored = Store[last_jx][last_jy];
737 int graphic = (game.emulation != EMU_SUPAPLEX ? IMG_EXPLOSION :
738 stored == EL_SP_INFOTRON ? IMG_SP_EXPLOSION_INFOTRON :
740 int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
741 int phase = ExplodePhase[last_jx][last_jy] - 1;
742 int frame = getGraphicAnimationFrame(graphic, phase - delay);
745 DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy), graphic, frame);
748 /* ----------------------------------------------------------------------- */
749 /* draw elements the player is just walking/passing through/under */
750 /* ----------------------------------------------------------------------- */
752 /* handle the field the player is leaving ... */
753 if (player_is_moving && IS_ACCESSIBLE_INSIDE(last_element))
754 DrawLevelField(last_jx, last_jy);
755 else if (player_is_moving && IS_ACCESSIBLE_UNDER(last_element))
756 DrawLevelFieldThruMask(last_jx, last_jy);
758 /* ... and the field the player is entering */
759 if (IS_ACCESSIBLE_INSIDE(element))
760 DrawLevelField(jx, jy);
761 else if (IS_ACCESSIBLE_UNDER(element))
762 DrawLevelFieldThruMask(jx, jy);
764 if (setup.direct_draw)
766 int dest_x = SX + SCREENX(MIN(jx, last_jx)) * TILEX;
767 int dest_y = SY + SCREENY(MIN(jy, last_jy)) * TILEY;
768 int x_size = TILEX * (1 + ABS(jx - last_jx));
769 int y_size = TILEY * (1 + ABS(jy - last_jy));
771 BlitBitmap(drawto_field, window,
772 dest_x, dest_y, x_size, y_size, dest_x, dest_y);
773 SetDrawtoField(DRAW_DIRECT);
776 MarkTileDirty(sx,sy);
779 void getGraphicSource(int graphic, int frame, Bitmap **bitmap, int *x, int *y)
781 struct GraphicInfo *g = &graphic_info[graphic];
785 if (g->offset_y == 0) /* frames are ordered horizontally */
787 int max_width = g->anim_frames_per_line * g->width;
789 *x = (g->src_x + frame * g->offset_x) % max_width;
790 *y = g->src_y + (g->src_x + frame * g->offset_x) / max_width * g->height;
792 else if (g->offset_x == 0) /* frames are ordered vertically */
794 int max_height = g->anim_frames_per_line * g->height;
796 *x = g->src_x + (g->src_y + frame * g->offset_y) / max_height * g->width;
797 *y = (g->src_y + frame * g->offset_y) % max_height;
799 else /* frames are ordered diagonally */
801 *x = g->src_x + frame * g->offset_x;
802 *y = g->src_y + frame * g->offset_y;
806 void DrawGraphic(int x, int y, int graphic, int frame)
809 if (!IN_SCR_FIELD(x, y))
811 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
812 printf("DrawGraphic(): This should never happen!\n");
817 DrawGraphicExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic, frame);
822 void DrawOldGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic)
827 getOldGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
828 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
832 void DrawGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
839 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
841 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
842 int src_x = graphic_info[graphic].src_x;
843 int src_y = graphic_info[graphic].src_y;
844 int offset_x = graphic_info[graphic].offset_x;
845 int offset_y = graphic_info[graphic].offset_y;
847 src_x += frame * offset_x;
848 src_y += frame * offset_y;
851 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
854 void DrawGraphicThruMask(int x, int y, int graphic, int frame)
857 if (!IN_SCR_FIELD(x, y))
859 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
860 printf("DrawGraphicThruMask(): This should never happen!\n");
865 DrawGraphicThruMaskExt(drawto_field, FX + x * TILEX, FY + y *TILEY, graphic,
870 void DrawGraphicThruMaskExt(DrawBuffer *d, int dest_x, int dest_y, int graphic,
878 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
879 drawing_gc = src_bitmap->stored_clip_gc;
881 GC drawing_gc = src_bitmap->stored_clip_gc;
882 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
883 int src_x = graphic_info[graphic].src_x;
884 int src_y = graphic_info[graphic].src_y;
885 int offset_x = graphic_info[graphic].offset_x;
886 int offset_y = graphic_info[graphic].offset_y;
888 src_x += frame * offset_x;
889 src_y += frame * offset_y;
893 SetClipOrigin(src_bitmap, drawing_gc, dest_x - src_x, dest_y - src_y);
894 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX, TILEY, dest_x, dest_y);
897 void DrawMiniGraphic(int x, int y, int graphic)
899 DrawMiniGraphicExt(drawto, SX + x * MINI_TILEX,SY + y * MINI_TILEY, graphic);
900 MarkTileDirty(x / 2, y / 2);
903 void getMiniGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
905 struct GraphicInfo *g = &graphic_info[graphic];
907 int mini_starty = g->bitmap->height * 2 / 3;
910 *x = mini_startx + g->src_x / 2;
911 *y = mini_starty + g->src_y / 2;
914 void DrawMiniGraphicExt(DrawBuffer *d, int x, int y, int graphic)
919 getMiniGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
920 BlitBitmap(src_bitmap, d, src_x, src_y, MINI_TILEX, MINI_TILEY, x, y);
923 void DrawGraphicShifted(int x,int y, int dx,int dy, int graphic, int frame,
924 int cut_mode, int mask_mode)
933 int width = TILEX, height = TILEY;
939 DrawGraphic(x, y, graphic, frame);
943 if (dx || dy) /* shifted graphic */
945 if (x < BX1) /* object enters playfield from the left */
952 else if (x > BX2) /* object enters playfield from the right */
958 else if (x==BX1 && dx < 0) /* object leaves playfield to the left */
964 else if (x==BX2 && dx > 0) /* object leaves playfield to the right */
966 else if (dx) /* general horizontal movement */
967 MarkTileDirty(x + SIGN(dx), y);
969 if (y < BY1) /* object enters playfield from the top */
971 if (cut_mode==CUT_BELOW) /* object completely above top border */
979 else if (y > BY2) /* object enters playfield from the bottom */
985 else if (y==BY1 && dy < 0) /* object leaves playfield to the top */
991 else if (dy > 0 && cut_mode == CUT_ABOVE)
993 if (y == BY2) /* object completely above bottom border */
999 MarkTileDirty(x, y + 1);
1000 } /* object leaves playfield to the bottom */
1001 else if (dy > 0 && (y == BY2 || cut_mode == CUT_BELOW))
1003 else if (dy) /* general vertical movement */
1004 MarkTileDirty(x, y + SIGN(dy));
1007 src_bitmap = graphic_info[graphic].bitmap;
1008 src_x = graphic_info[graphic].src_x;
1009 src_y = graphic_info[graphic].src_y;
1010 offset_x = graphic_info[graphic].offset_x;
1011 offset_y = graphic_info[graphic].offset_y;
1013 drawing_gc = src_bitmap->stored_clip_gc;
1015 src_x += frame * offset_x;
1016 src_y += frame * offset_y;
1021 dest_x = FX + x * TILEX + dx;
1022 dest_y = FY + y * TILEY + dy;
1025 if (!IN_SCR_FIELD(x,y))
1027 printf("DrawGraphicShifted(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
1028 printf("DrawGraphicShifted(): This should never happen!\n");
1033 if (mask_mode == USE_MASKING)
1035 SetClipOrigin(src_bitmap, drawing_gc, dest_x - src_x, dest_y - src_y);
1036 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1040 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1046 void DrawGraphicShiftedThruMask(int x, int y, int dx, int dy, int graphic,
1047 int frame, int cut_mode)
1049 DrawGraphicShifted(x,y, dx,dy, graphic, frame, cut_mode, USE_MASKING);
1052 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
1053 int cut_mode, int mask_mode)
1055 int lx = LEVELX(x), ly = LEVELY(y);
1059 if (IN_LEV_FIELD(lx, ly))
1061 SetRandomAnimationValue(lx, ly);
1063 graphic = el_act_dir2img(element, GfxAction[lx][ly], MovDir[lx][ly]);
1064 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1066 else /* border element */
1068 graphic = el2img(element);
1069 frame = getGraphicAnimationFrame(graphic, -1);
1072 if (element == EL_EXPANDABLE_WALL)
1074 boolean left_stopped = FALSE, right_stopped = FALSE;
1076 if (!IN_LEV_FIELD(lx - 1, ly) || IS_WALL(Feld[lx - 1][ly]))
1077 left_stopped = TRUE;
1078 if (!IN_LEV_FIELD(lx + 1, ly) || IS_WALL(Feld[lx + 1][ly]))
1079 right_stopped = TRUE;
1081 if (left_stopped && right_stopped)
1083 else if (left_stopped)
1085 graphic = IMG_EXPANDABLE_WALL_GROWING_RIGHT;
1086 frame = graphic_info[graphic].anim_frames - 1;
1088 else if (right_stopped)
1090 graphic = IMG_EXPANDABLE_WALL_GROWING_LEFT;
1091 frame = graphic_info[graphic].anim_frames - 1;
1095 else if (IS_AMOEBOID(element) || element == EL_AMOEBA_DROPPING)
1097 graphic = (element == EL_BD_AMOEBA ? IMG_BD_AMOEBA_PART1 :
1098 element == EL_AMOEBA_WET ? IMG_AMOEBA_WET_PART1 :
1099 element == EL_AMOEBA_DRY ? IMG_AMOEBA_DRY_PART1 :
1100 element == EL_AMOEBA_FULL ? IMG_AMOEBA_FULL_PART1 :
1101 IMG_AMOEBA_DEAD_PART1);
1103 graphic += (x + 2 * y + 4) % 4;
1108 if (IS_AMOEBOID(element) || element == EL_AMOEBA_DROPPING)
1110 if (Feld[lx][ly] == EL_AMOEBA_DROPPING)
1111 printf("---> %d -> %d / %d [%d]\n",
1112 element, graphic, frame, GfxRandom[lx][ly]);
1117 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, mask_mode);
1118 else if (mask_mode == USE_MASKING)
1119 DrawGraphicThruMask(x, y, graphic, frame);
1121 DrawGraphic(x, y, graphic, frame);
1124 void DrawLevelElementExt(int x, int y, int dx, int dy, int element,
1125 int cut_mode, int mask_mode)
1127 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1128 DrawScreenElementExt(SCREENX(x), SCREENY(y), dx, dy, element,
1129 cut_mode, mask_mode);
1132 void DrawScreenElementShifted(int x, int y, int dx, int dy, int element,
1135 DrawScreenElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1138 void DrawLevelElementShifted(int x, int y, int dx, int dy, int element,
1141 DrawLevelElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1145 void DrawOldScreenElementThruMask(int x, int y, int element)
1147 DrawOldScreenElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1150 void DrawScreenElementThruMask(int x, int y, int element)
1152 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1156 void DrawLevelElementThruMask(int x, int y, int element)
1158 DrawLevelElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1161 void DrawLevelFieldThruMask(int x, int y)
1163 DrawLevelElementExt(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
1166 static void DrawLevelFieldCrumbledSandExt(int x, int y, int graphic, int frame)
1170 int sx = SCREENX(x), sy = SCREENY(y);
1172 int width, height, cx, cy, i;
1173 int snip = TILEX / 8; /* number of border pixels from "crumbled graphic" */
1174 static int xy[4][2] =
1182 if (!IN_LEV_FIELD(x, y))
1185 element = (GfxElement[x][y] != EL_UNDEFINED ? GfxElement[x][y] : Feld[x][y]);
1187 /* crumble field itself */
1188 if (CAN_BE_CRUMBLED(element))
1190 if (!IN_SCR_FIELD(sx, sy))
1193 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1197 int xx = x + xy[i][0];
1198 int yy = y + xy[i][1];
1200 element = (IN_LEV_FIELD(xx, yy) ? Feld[xx][yy] : EL_STEELWALL);
1202 if (CAN_BE_CRUMBLED(element)) /* neighbour is of same type */
1205 if (i == 1 || i == 2)
1209 cx = (i == 2 ? TILEX - snip : 0);
1217 cy = (i == 3 ? TILEY - snip : 0);
1220 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1221 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
1224 MarkTileDirty(sx, sy);
1226 else /* crumble neighbour fields */
1228 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1232 int xx = x + xy[i][0];
1233 int yy = y + xy[i][1];
1234 int sxx = sx + xy[i][0];
1235 int syy = sy + xy[i][1];
1237 if (!IN_LEV_FIELD(xx, yy) ||
1238 !IN_SCR_FIELD(sxx, syy) ||
1239 !CAN_BE_CRUMBLED(Feld[xx][yy]))
1242 if (i == 1 || i == 2)
1246 cx = (i == 1 ? TILEX - snip : 0);
1254 cy = (i==0 ? TILEY-snip : 0);
1257 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1258 width, height, FX + sxx * TILEX + cx, FY + syy * TILEY + cy);
1260 MarkTileDirty(sxx, syy);
1265 void DrawLevelFieldCrumbledSand(int x, int y)
1267 DrawLevelFieldCrumbledSandExt(x, y, IMG_SAND_CRUMBLED, 0);
1270 void DrawLevelFieldCrumbledSandDigging(int x, int y, int direction,
1273 int graphic1 = el_act_dir2img(EL_SAND, ACTION_DIGGING, direction);
1274 int graphic2 = el_act_dir2img(EL_SAND_CRUMBLED, ACTION_DIGGING, direction);
1275 int frame1 = getGraphicAnimationFrame(graphic1, step_frame);
1276 int frame2 = getGraphicAnimationFrame(graphic2, step_frame);
1277 int sx = SCREENX(x), sy = SCREENY(y);
1279 DrawGraphic(sx, sy, graphic1, frame1);
1280 DrawLevelFieldCrumbledSandExt(x, y, graphic2, frame2);
1283 static int getBorderElement(int x, int y)
1287 { EL_STEELWALL_TOPLEFT, EL_INVISIBLE_STEELWALL_TOPLEFT },
1288 { EL_STEELWALL_TOPRIGHT, EL_INVISIBLE_STEELWALL_TOPRIGHT },
1289 { EL_STEELWALL_BOTTOMLEFT, EL_INVISIBLE_STEELWALL_BOTTOMLEFT },
1290 { EL_STEELWALL_BOTTOMRIGHT, EL_INVISIBLE_STEELWALL_BOTTOMRIGHT },
1291 { EL_STEELWALL_VERTICAL, EL_INVISIBLE_STEELWALL_VERTICAL },
1292 { EL_STEELWALL_HORIZONTAL, EL_INVISIBLE_STEELWALL_HORIZONTAL },
1293 { EL_STEELWALL, EL_INVISIBLE_STEELWALL }
1295 int steel_type = (BorderElement == EL_STEELWALL ? 0 : 1);
1296 int steel_position = (x == -1 && y == -1 ? 0 :
1297 x == lev_fieldx && y == -1 ? 1 :
1298 x == -1 && y == lev_fieldy ? 2 :
1299 x == lev_fieldx && y == lev_fieldy ? 3 :
1300 x == -1 || x == lev_fieldx ? 4 :
1301 y == -1 || y == lev_fieldy ? 5 : 6);
1303 return border[steel_position][steel_type];
1306 void DrawScreenElement(int x, int y, int element)
1308 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
1309 DrawLevelFieldCrumbledSand(LEVELX(x), LEVELY(y));
1312 void DrawLevelElement(int x, int y, int element)
1314 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1315 DrawScreenElement(SCREENX(x), SCREENY(y), element);
1318 void DrawScreenField(int x, int y)
1320 int lx = LEVELX(x), ly = LEVELY(y);
1321 int element, content;
1323 if (!IN_LEV_FIELD(lx, ly))
1325 if (lx < -1 || lx > lev_fieldx || ly < -1 || ly > lev_fieldy)
1328 element = getBorderElement(lx, ly);
1330 DrawScreenElement(x, y, element);
1334 element = Feld[lx][ly];
1335 content = Store[lx][ly];
1337 if (IS_MOVING(lx, ly))
1339 int horiz_move = (MovDir[lx][ly] == MV_LEFT || MovDir[lx][ly] == MV_RIGHT);
1340 boolean cut_mode = NO_CUTTING;
1342 if (element == EL_QUICKSAND_EMPTYING ||
1343 element == EL_MAGIC_WALL_EMPTYING ||
1344 element == EL_BD_MAGIC_WALL_EMPTYING ||
1345 element == EL_AMOEBA_DROPPING)
1346 cut_mode = CUT_ABOVE;
1347 else if (element == EL_QUICKSAND_FILLING ||
1348 element == EL_MAGIC_WALL_FILLING ||
1349 element == EL_BD_MAGIC_WALL_FILLING)
1350 cut_mode = CUT_BELOW;
1352 if (cut_mode == CUT_ABOVE)
1353 DrawScreenElementShifted(x, y, 0, 0, element, NO_CUTTING);
1355 DrawScreenElement(x, y, EL_EMPTY);
1358 DrawScreenElementShifted(x, y, MovPos[lx][ly], 0, element, NO_CUTTING);
1359 else if (cut_mode == NO_CUTTING)
1360 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], element, cut_mode);
1362 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], content, cut_mode);
1364 if (content == EL_ACID)
1365 DrawLevelElementThruMask(lx, ly + 1, EL_ACID);
1367 else if (IS_BLOCKED(lx, ly))
1372 boolean cut_mode = NO_CUTTING;
1373 int element_old, content_old;
1375 Blocked2Moving(lx, ly, &oldx, &oldy);
1378 horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
1379 MovDir[oldx][oldy] == MV_RIGHT);
1381 element_old = Feld[oldx][oldy];
1382 content_old = Store[oldx][oldy];
1384 if (element_old == EL_QUICKSAND_EMPTYING ||
1385 element_old == EL_MAGIC_WALL_EMPTYING ||
1386 element_old == EL_BD_MAGIC_WALL_EMPTYING ||
1387 element_old == EL_AMOEBA_DROPPING)
1388 cut_mode = CUT_ABOVE;
1390 DrawScreenElement(x, y, EL_EMPTY);
1393 DrawScreenElementShifted(sx, sy, MovPos[oldx][oldy], 0, element_old,
1395 else if (cut_mode == NO_CUTTING)
1396 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], element_old,
1399 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], content_old,
1402 else if (IS_DRAWABLE(element))
1403 DrawScreenElement(x, y, element);
1405 DrawScreenElement(x, y, EL_EMPTY);
1408 void DrawLevelField(int x, int y)
1410 if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1411 DrawScreenField(SCREENX(x), SCREENY(y));
1412 else if (IS_MOVING(x, y))
1416 Moving2Blocked(x, y, &newx, &newy);
1417 if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
1418 DrawScreenField(SCREENX(newx), SCREENY(newy));
1420 else if (IS_BLOCKED(x, y))
1424 Blocked2Moving(x, y, &oldx, &oldy);
1425 if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
1426 DrawScreenField(SCREENX(oldx), SCREENY(oldy));
1430 void DrawMiniElement(int x, int y, int element)
1434 graphic = el2edimg(element);
1435 DrawMiniGraphic(x, y, graphic);
1438 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
1440 int x = sx + scroll_x, y = sy + scroll_y;
1442 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
1443 DrawMiniElement(sx, sy, EL_EMPTY);
1444 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
1445 DrawMiniElement(sx, sy, Feld[x][y]);
1447 DrawMiniGraphic(sx, sy, el2edimg(getBorderElement(x, y)));
1450 void getMicroGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
1452 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
1453 int mini_startx = src_bitmap->width * 3 / 4;
1454 int mini_starty = src_bitmap->height * 2 / 3;
1455 int src_x = mini_startx + graphic_info[graphic].src_x / 8;
1456 int src_y = mini_starty + graphic_info[graphic].src_y / 8;
1458 if (src_x + MICRO_TILEX > src_bitmap->width ||
1459 src_y + MICRO_TILEY > src_bitmap->height)
1461 /* graphic of desired size seems not to be contained in this image;
1462 dirty workaround: get it from the middle of the normal sized image */
1464 getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
1465 src_x += (TILEX / 2 - MICRO_TILEX / 2);
1466 src_y += (TILEY / 2 - MICRO_TILEY / 2);
1469 *bitmap = src_bitmap;
1474 void DrawMicroElement(int xpos, int ypos, int element)
1478 int graphic = el2preimg(element);
1480 getMicroGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
1481 BlitBitmap(src_bitmap, drawto, src_x, src_y, MICRO_TILEX, MICRO_TILEY,
1489 SetDrawBackgroundMask(REDRAW_NONE);
1492 for(x=BX1; x<=BX2; x++)
1493 for(y=BY1; y<=BY2; y++)
1494 DrawScreenField(x, y);
1496 redraw_mask |= REDRAW_FIELD;
1499 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
1503 for(x=0; x<size_x; x++)
1504 for(y=0; y<size_y; y++)
1505 DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
1507 redraw_mask |= REDRAW_FIELD;
1510 static void DrawMicroLevelExt(int xpos, int ypos, int from_x, int from_y)
1514 DrawBackground(xpos, ypos, MICROLEV_XSIZE, MICROLEV_YSIZE);
1516 if (lev_fieldx < STD_LEV_FIELDX)
1517 xpos += (STD_LEV_FIELDX - lev_fieldx) / 2 * MICRO_TILEX;
1518 if (lev_fieldy < STD_LEV_FIELDY)
1519 ypos += (STD_LEV_FIELDY - lev_fieldy) / 2 * MICRO_TILEY;
1521 xpos += MICRO_TILEX;
1522 ypos += MICRO_TILEY;
1524 for(x=-1; x<=STD_LEV_FIELDX; x++)
1526 for(y=-1; y<=STD_LEV_FIELDY; y++)
1528 int lx = from_x + x, ly = from_y + y;
1530 if (lx >= 0 && lx < lev_fieldx && ly >= 0 && ly < lev_fieldy)
1531 DrawMicroElement(xpos + x * MICRO_TILEX, ypos + y * MICRO_TILEY,
1533 else if (lx >= -1 && lx < lev_fieldx+1 && ly >= -1 && ly < lev_fieldy+1
1534 && BorderElement != EL_EMPTY)
1535 DrawMicroElement(xpos + x * MICRO_TILEX, ypos + y * MICRO_TILEY,
1536 getBorderElement(lx, ly));
1540 redraw_mask |= REDRAW_MICROLEVEL;
1543 #define MICROLABEL_EMPTY 0
1544 #define MICROLABEL_LEVEL_NAME 1
1545 #define MICROLABEL_CREATED_BY 2
1546 #define MICROLABEL_LEVEL_AUTHOR 3
1547 #define MICROLABEL_IMPORTED_FROM 4
1548 #define MICROLABEL_LEVEL_IMPORT_INFO 5
1550 static void DrawMicroLevelLabelExt(int mode)
1552 char label_text[MAX_OUTPUT_LINESIZE + 1];
1553 int max_len_label_text;
1554 int font_nr = FONT_TEXT_2;
1556 if (mode == MICROLABEL_CREATED_BY || mode == MICROLABEL_IMPORTED_FROM)
1557 font_nr = FONT_TEXT_3;
1559 max_len_label_text = SXSIZE / getFontWidth(font_nr);
1561 DrawBackground(SX, MICROLABEL_YPOS, SXSIZE, getFontHeight(font_nr));
1563 strncpy(label_text, (mode == MICROLABEL_LEVEL_NAME ? level.name :
1564 mode == MICROLABEL_CREATED_BY ? "created by" :
1565 mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
1566 mode == MICROLABEL_IMPORTED_FROM ? "imported from" :
1567 mode == MICROLABEL_LEVEL_IMPORT_INFO ?
1568 leveldir_current->imported_from : ""),
1569 max_len_label_text);
1570 label_text[max_len_label_text] = '\0';
1572 if (strlen(label_text) > 0)
1574 int text_width = strlen(label_text) * getFontWidth(font_nr);
1575 int lxpos = SX + (SXSIZE - text_width) / 2;
1576 int lypos = MICROLABEL_YPOS;
1578 DrawText(lxpos, lypos, label_text, font_nr);
1581 redraw_mask |= REDRAW_MICROLEVEL;
1584 void DrawMicroLevel(int xpos, int ypos, boolean restart)
1586 static unsigned long scroll_delay = 0;
1587 static unsigned long label_delay = 0;
1588 static int from_x, from_y, scroll_direction;
1589 static int label_state, label_counter;
1590 int last_game_status = game_status; /* save current game status */
1592 /* force PREVIEW font on preview level */
1593 game_status = GAME_MODE_PSEUDO_PREVIEW;
1597 from_x = from_y = 0;
1598 scroll_direction = MV_RIGHT;
1602 DrawMicroLevelExt(xpos, ypos, from_x, from_y);
1603 DrawMicroLevelLabelExt(label_state);
1605 /* initialize delay counters */
1606 DelayReached(&scroll_delay, 0);
1607 DelayReached(&label_delay, 0);
1609 if (leveldir_current->name)
1611 int len = strlen(leveldir_current->name);
1612 int lxpos = SX + (SXSIZE - len * getFontWidth(FONT_TEXT_1)) / 2;
1613 int lypos = SY + 352;
1615 DrawText(lxpos, lypos, leveldir_current->name, FONT_TEXT_1);
1618 game_status = last_game_status; /* restore current game status */
1623 /* scroll micro level, if needed */
1624 if ((lev_fieldx > STD_LEV_FIELDX || lev_fieldy > STD_LEV_FIELDY) &&
1625 DelayReached(&scroll_delay, MICROLEVEL_SCROLL_DELAY))
1627 switch (scroll_direction)
1633 scroll_direction = MV_UP;
1637 if (from_x < lev_fieldx - STD_LEV_FIELDX)
1640 scroll_direction = MV_DOWN;
1647 scroll_direction = MV_RIGHT;
1651 if (from_y < lev_fieldy - STD_LEV_FIELDY)
1654 scroll_direction = MV_LEFT;
1661 DrawMicroLevelExt(xpos, ypos, from_x, from_y);
1664 /* redraw micro level label, if needed */
1665 if (strcmp(level.name, NAMELESS_LEVEL_NAME) != 0 &&
1666 strcmp(level.author, ANONYMOUS_NAME) != 0 &&
1667 strcmp(level.author, leveldir_current->name) != 0 &&
1668 DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
1670 int max_label_counter = 23;
1672 if (leveldir_current->imported_from != NULL)
1673 max_label_counter += 14;
1675 label_counter = (label_counter + 1) % max_label_counter;
1676 label_state = (label_counter >= 0 && label_counter <= 7 ?
1677 MICROLABEL_LEVEL_NAME :
1678 label_counter >= 9 && label_counter <= 12 ?
1679 MICROLABEL_CREATED_BY :
1680 label_counter >= 14 && label_counter <= 21 ?
1681 MICROLABEL_LEVEL_AUTHOR :
1682 label_counter >= 23 && label_counter <= 26 ?
1683 MICROLABEL_IMPORTED_FROM :
1684 label_counter >= 28 && label_counter <= 35 ?
1685 MICROLABEL_LEVEL_IMPORT_INFO : MICROLABEL_EMPTY);
1686 DrawMicroLevelLabelExt(label_state);
1689 game_status = last_game_status; /* restore current game status */
1692 int REQ_in_range(int x, int y)
1694 if (y > DY+249 && y < DY+278)
1696 if (x > DX+1 && x < DX+48)
1698 else if (x > DX+51 && x < DX+98)
1704 #define MAX_REQUEST_LINES 13
1705 #define MAX_REQUEST_LINE_LEN 7
1707 boolean Request(char *text, unsigned int req_state)
1709 int mx, my, ty, result = -1;
1710 unsigned int old_door_state;
1711 int last_game_status = game_status; /* save current game status */
1713 #if defined(PLATFORM_UNIX)
1714 /* pause network game while waiting for request to answer */
1715 if (options.network &&
1716 game_status == GAME_MODE_PLAYING &&
1717 req_state & REQUEST_WAIT_FOR)
1718 SendToServer_PausePlaying();
1721 old_door_state = GetDoorState();
1725 CloseDoor(DOOR_CLOSE_1);
1727 /* save old door content */
1728 BlitBitmap(bitmap_db_door, bitmap_db_door,
1729 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
1730 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
1732 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
1734 /* clear door drawing field */
1735 DrawBackground(DX, DY, DXSIZE, DYSIZE);
1737 /* force DOOR font on preview level */
1738 game_status = GAME_MODE_PSEUDO_DOOR;
1740 /* write text for request */
1741 for(ty=0; ty < MAX_REQUEST_LINES; ty++)
1743 char text_line[MAX_REQUEST_LINE_LEN + 1];
1749 for(tl=0,tx=0; tx < MAX_REQUEST_LINE_LEN; tl++,tx++)
1752 if (!tc || tc == ' ')
1763 strncpy(text_line, text, tl);
1766 DrawText(DX + (DXSIZE - tl * getFontWidth(FONT_TEXT_2)) / 2,
1767 DY + 8 + ty * (getFontHeight(FONT_TEXT_2) + 2),
1768 text_line, FONT_TEXT_2);
1770 text += tl + (tc == ' ' ? 1 : 0);
1773 game_status = last_game_status; /* restore current game status */
1775 if (req_state & REQ_ASK)
1777 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
1778 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
1780 else if (req_state & REQ_CONFIRM)
1782 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
1784 else if (req_state & REQ_PLAYER)
1786 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
1787 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
1788 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
1789 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
1792 /* copy request gadgets to door backbuffer */
1793 BlitBitmap(drawto, bitmap_db_door,
1794 DX, DY, DXSIZE, DYSIZE,
1795 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
1797 OpenDoor(DOOR_OPEN_1);
1803 if (!(req_state & REQUEST_WAIT_FOR))
1805 SetDrawBackgroundMask(REDRAW_FIELD);
1810 if (game_status != GAME_MODE_MAIN)
1813 button_status = MB_RELEASED;
1815 request_gadget_id = -1;
1817 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
1829 case EVENT_BUTTONPRESS:
1830 case EVENT_BUTTONRELEASE:
1831 case EVENT_MOTIONNOTIFY:
1833 if (event.type == EVENT_MOTIONNOTIFY)
1835 if (!PointerInWindow(window))
1836 continue; /* window and pointer are on different screens */
1841 motion_status = TRUE;
1842 mx = ((MotionEvent *) &event)->x;
1843 my = ((MotionEvent *) &event)->y;
1847 motion_status = FALSE;
1848 mx = ((ButtonEvent *) &event)->x;
1849 my = ((ButtonEvent *) &event)->y;
1850 if (event.type == EVENT_BUTTONPRESS)
1851 button_status = ((ButtonEvent *) &event)->button;
1853 button_status = MB_RELEASED;
1856 /* this sets 'request_gadget_id' */
1857 HandleGadgets(mx, my, button_status);
1859 switch(request_gadget_id)
1861 case TOOL_CTRL_ID_YES:
1864 case TOOL_CTRL_ID_NO:
1867 case TOOL_CTRL_ID_CONFIRM:
1868 result = TRUE | FALSE;
1871 case TOOL_CTRL_ID_PLAYER_1:
1874 case TOOL_CTRL_ID_PLAYER_2:
1877 case TOOL_CTRL_ID_PLAYER_3:
1880 case TOOL_CTRL_ID_PLAYER_4:
1891 case EVENT_KEYPRESS:
1892 switch(GetEventKey((KeyEvent *)&event, TRUE))
1905 if (req_state & REQ_PLAYER)
1909 case EVENT_KEYRELEASE:
1910 ClearPlayerAction();
1914 HandleOtherEvents(&event);
1918 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
1920 int joy = AnyJoystick();
1922 if (joy & JOY_BUTTON_1)
1924 else if (joy & JOY_BUTTON_2)
1930 /* don't eat all CPU time */
1934 if (game_status != GAME_MODE_MAIN)
1939 if (!(req_state & REQ_STAY_OPEN))
1941 CloseDoor(DOOR_CLOSE_1);
1943 if (!(req_state & REQ_STAY_CLOSED) && (old_door_state & DOOR_OPEN_1))
1945 BlitBitmap(bitmap_db_door, bitmap_db_door,
1946 DOOR_GFX_PAGEX2,DOOR_GFX_PAGEY1, DXSIZE,DYSIZE,
1947 DOOR_GFX_PAGEX1,DOOR_GFX_PAGEY1);
1948 OpenDoor(DOOR_OPEN_1);
1954 SetDrawBackgroundMask(REDRAW_FIELD);
1956 #if defined(PLATFORM_UNIX)
1957 /* continue network game after request */
1958 if (options.network &&
1959 game_status == GAME_MODE_PLAYING &&
1960 req_state & REQUEST_WAIT_FOR)
1961 SendToServer_ContinuePlaying();
1967 unsigned int OpenDoor(unsigned int door_state)
1969 unsigned int new_door_state;
1971 if (door_state & DOOR_COPY_BACK)
1973 BlitBitmap(bitmap_db_door, bitmap_db_door,
1974 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE + VYSIZE,
1975 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
1976 door_state &= ~DOOR_COPY_BACK;
1979 new_door_state = MoveDoor(door_state);
1981 return(new_door_state);
1984 unsigned int CloseDoor(unsigned int door_state)
1986 unsigned int new_door_state;
1988 BlitBitmap(backbuffer, bitmap_db_door,
1989 DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
1990 BlitBitmap(backbuffer, bitmap_db_door,
1991 VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
1993 new_door_state = MoveDoor(door_state);
1995 return(new_door_state);
1998 unsigned int GetDoorState()
2000 return MoveDoor(DOOR_GET_STATE);
2003 unsigned int SetDoorState(unsigned int door_state)
2005 return MoveDoor(door_state | DOOR_SET_STATE);
2008 unsigned int MoveDoor(unsigned int door_state)
2010 static int door1 = DOOR_OPEN_1;
2011 static int door2 = DOOR_CLOSE_2;
2012 static unsigned long door_delay = 0;
2013 int x, start, stepsize = door.step_offset;
2014 unsigned long door_delay_value = door.step_delay;
2016 if (door_state == DOOR_GET_STATE)
2017 return(door1 | door2);
2019 if (door_state & DOOR_SET_STATE)
2021 if (door_state & DOOR_ACTION_1)
2022 door1 = door_state & DOOR_ACTION_1;
2023 if (door_state & DOOR_ACTION_2)
2024 door2 = door_state & DOOR_ACTION_2;
2026 return(door1 | door2);
2029 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
2030 door_state &= ~DOOR_OPEN_1;
2031 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
2032 door_state &= ~DOOR_CLOSE_1;
2033 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
2034 door_state &= ~DOOR_OPEN_2;
2035 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
2036 door_state &= ~DOOR_CLOSE_2;
2038 if (setup.quick_doors)
2041 door_delay_value = 0;
2043 StopSound(SND_DOOR_OPENING);
2044 StopSound(SND_DOOR_CLOSING);
2047 if (global.autoplay_leveldir)
2049 door_state |= DOOR_NO_DELAY;
2050 door_state &= ~DOOR_CLOSE_ALL;
2053 if (door_state & DOOR_ACTION)
2055 if (!(door_state & DOOR_NO_DELAY))
2057 /* opening door sound has priority over simultaneously closing door */
2058 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
2059 PlaySoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
2060 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
2061 PlaySoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
2064 start = ((door_state & DOOR_NO_DELAY) ? DXSIZE : 0);
2066 for(x=start; x<=DXSIZE; x+=stepsize)
2068 Bitmap *bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
2069 GC gc = bitmap->stored_clip_gc;
2071 if (!(door_state & DOOR_NO_DELAY))
2072 WaitUntilDelayReached(&door_delay, door_delay_value);
2074 if (door_state & DOOR_ACTION_1)
2076 int i = (door_state & DOOR_OPEN_1 ? DXSIZE-x : x);
2077 int j = (DXSIZE - i) / 3;
2079 BlitBitmap(bitmap_db_door, drawto,
2080 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + i/2,
2081 DXSIZE,DYSIZE - i/2, DX, DY);
2083 ClearRectangle(drawto, DX, DY + DYSIZE - i/2, DXSIZE,i/2);
2085 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2086 BlitBitmapMasked(bitmap, drawto,
2087 DXSIZE, DOOR_GFX_PAGEY1, i, 77,
2088 DX + DXSIZE - i, DY + j);
2089 BlitBitmapMasked(bitmap, drawto,
2090 DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63,
2091 DX + DXSIZE - i, DY + 140 + j);
2092 SetClipOrigin(bitmap, gc, DX - DXSIZE + i, DY - (DOOR_GFX_PAGEY1 + j));
2093 BlitBitmapMasked(bitmap, drawto,
2094 DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j,
2096 BlitBitmapMasked(bitmap, drawto,
2097 DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63,
2100 BlitBitmapMasked(bitmap, drawto,
2101 DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
2103 BlitBitmapMasked(bitmap, drawto,
2104 DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
2106 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2107 BlitBitmapMasked(bitmap, drawto,
2108 DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
2109 DX + DXSIZE - i, DY + 77 + j);
2110 BlitBitmapMasked(bitmap, drawto,
2111 DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
2112 DX + DXSIZE - i, DY + 203 + j);
2114 redraw_mask |= REDRAW_DOOR_1;
2117 if (door_state & DOOR_ACTION_2)
2119 int i = (door_state & DOOR_OPEN_2 ? VXSIZE - x : x);
2120 int j = (VXSIZE - i) / 3;
2122 BlitBitmap(bitmap_db_door, drawto,
2123 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + i/2,
2124 VXSIZE, VYSIZE - i/2, VX, VY);
2126 ClearRectangle(drawto, VX, VY + VYSIZE-i/2, VXSIZE, i/2);
2128 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2129 BlitBitmapMasked(bitmap, drawto,
2130 VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2,
2131 VX + VXSIZE-i, VY+j);
2132 SetClipOrigin(bitmap, gc,
2133 VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
2134 BlitBitmapMasked(bitmap, drawto,
2135 VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j,
2138 BlitBitmapMasked(bitmap, drawto,
2139 VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2,
2140 i, VYSIZE / 2, VX, VY + VYSIZE / 2 - j);
2141 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2142 BlitBitmapMasked(bitmap, drawto,
2143 VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2,
2145 VX + VXSIZE - i, VY + VYSIZE / 2 + j);
2147 redraw_mask |= REDRAW_DOOR_2;
2152 if (game_status == GAME_MODE_MAIN)
2157 if (setup.quick_doors)
2159 StopSound(SND_DOOR_OPENING);
2160 StopSound(SND_DOOR_CLOSING);
2163 if (door_state & DOOR_ACTION_1)
2164 door1 = door_state & DOOR_ACTION_1;
2165 if (door_state & DOOR_ACTION_2)
2166 door2 = door_state & DOOR_ACTION_2;
2168 return (door1 | door2);
2171 void DrawSpecialEditorDoor()
2173 /* draw bigger toolbox window */
2174 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
2175 DOOR_GFX_PAGEX7, 0, EXSIZE + 8, 8,
2177 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
2178 EX - 4, VY - 4, EXSIZE + 8, EYSIZE - VYSIZE + 4,
2181 redraw_mask |= REDRAW_ALL;
2184 void UndrawSpecialEditorDoor()
2186 /* draw normal tape recorder window */
2187 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
2188 EX - 4, EY - 12, EXSIZE + 8, EYSIZE - VYSIZE + 12,
2191 redraw_mask |= REDRAW_ALL;
2195 /* ---------- new tool button stuff ---------------------------------------- */
2197 /* graphic position values for tool buttons */
2198 #define TOOL_BUTTON_YES_XPOS 2
2199 #define TOOL_BUTTON_YES_YPOS 250
2200 #define TOOL_BUTTON_YES_GFX_YPOS 0
2201 #define TOOL_BUTTON_YES_XSIZE 46
2202 #define TOOL_BUTTON_YES_YSIZE 28
2203 #define TOOL_BUTTON_NO_XPOS 52
2204 #define TOOL_BUTTON_NO_YPOS TOOL_BUTTON_YES_YPOS
2205 #define TOOL_BUTTON_NO_GFX_YPOS TOOL_BUTTON_YES_GFX_YPOS
2206 #define TOOL_BUTTON_NO_XSIZE TOOL_BUTTON_YES_XSIZE
2207 #define TOOL_BUTTON_NO_YSIZE TOOL_BUTTON_YES_YSIZE
2208 #define TOOL_BUTTON_CONFIRM_XPOS TOOL_BUTTON_YES_XPOS
2209 #define TOOL_BUTTON_CONFIRM_YPOS TOOL_BUTTON_YES_YPOS
2210 #define TOOL_BUTTON_CONFIRM_GFX_YPOS 30
2211 #define TOOL_BUTTON_CONFIRM_XSIZE 96
2212 #define TOOL_BUTTON_CONFIRM_YSIZE TOOL_BUTTON_YES_YSIZE
2213 #define TOOL_BUTTON_PLAYER_XSIZE 30
2214 #define TOOL_BUTTON_PLAYER_YSIZE 30
2215 #define TOOL_BUTTON_PLAYER_GFX_XPOS 5
2216 #define TOOL_BUTTON_PLAYER_GFX_YPOS 185
2217 #define TOOL_BUTTON_PLAYER_XPOS (5 + TOOL_BUTTON_PLAYER_XSIZE / 2)
2218 #define TOOL_BUTTON_PLAYER_YPOS (215 - TOOL_BUTTON_PLAYER_YSIZE / 2)
2219 #define TOOL_BUTTON_PLAYER1_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2220 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2221 #define TOOL_BUTTON_PLAYER2_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2222 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2223 #define TOOL_BUTTON_PLAYER3_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2224 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2225 #define TOOL_BUTTON_PLAYER4_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2226 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2227 #define TOOL_BUTTON_PLAYER1_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2228 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2229 #define TOOL_BUTTON_PLAYER2_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2230 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2231 #define TOOL_BUTTON_PLAYER3_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2232 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2233 #define TOOL_BUTTON_PLAYER4_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2234 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2243 } toolbutton_info[NUM_TOOL_BUTTONS] =
2246 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_GFX_YPOS,
2247 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_YPOS,
2248 TOOL_BUTTON_YES_XSIZE, TOOL_BUTTON_YES_YSIZE,
2253 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_GFX_YPOS,
2254 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_YPOS,
2255 TOOL_BUTTON_NO_XSIZE, TOOL_BUTTON_NO_YSIZE,
2260 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_GFX_YPOS,
2261 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_YPOS,
2262 TOOL_BUTTON_CONFIRM_XSIZE, TOOL_BUTTON_CONFIRM_YSIZE,
2263 TOOL_CTRL_ID_CONFIRM,
2267 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2268 TOOL_BUTTON_PLAYER1_XPOS, TOOL_BUTTON_PLAYER1_YPOS,
2269 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2270 TOOL_CTRL_ID_PLAYER_1,
2274 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2275 TOOL_BUTTON_PLAYER2_XPOS, TOOL_BUTTON_PLAYER2_YPOS,
2276 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2277 TOOL_CTRL_ID_PLAYER_2,
2281 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2282 TOOL_BUTTON_PLAYER3_XPOS, TOOL_BUTTON_PLAYER3_YPOS,
2283 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2284 TOOL_CTRL_ID_PLAYER_3,
2288 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2289 TOOL_BUTTON_PLAYER4_XPOS, TOOL_BUTTON_PLAYER4_YPOS,
2290 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2291 TOOL_CTRL_ID_PLAYER_4,
2296 void CreateToolButtons()
2300 for (i=0; i<NUM_TOOL_BUTTONS; i++)
2302 Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
2303 Bitmap *deco_bitmap = None;
2304 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
2305 struct GadgetInfo *gi;
2306 unsigned long event_mask;
2307 int gd_xoffset, gd_yoffset;
2308 int gd_x1, gd_x2, gd_y;
2311 event_mask = GD_EVENT_RELEASED;
2313 gd_xoffset = toolbutton_info[i].xpos;
2314 gd_yoffset = toolbutton_info[i].ypos;
2315 gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
2316 gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
2317 gd_y = DOOR_GFX_PAGEY1 + gd_yoffset;
2319 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
2321 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
2323 getMiniGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr),
2324 &deco_bitmap, &deco_x, &deco_y);
2325 deco_xpos = (toolbutton_info[i].width - MINI_TILEX) / 2;
2326 deco_ypos = (toolbutton_info[i].height - MINI_TILEY) / 2;
2329 gi = CreateGadget(GDI_CUSTOM_ID, id,
2330 GDI_INFO_TEXT, toolbutton_info[i].infotext,
2331 GDI_X, DX + toolbutton_info[i].x,
2332 GDI_Y, DY + toolbutton_info[i].y,
2333 GDI_WIDTH, toolbutton_info[i].width,
2334 GDI_HEIGHT, toolbutton_info[i].height,
2335 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
2336 GDI_STATE, GD_BUTTON_UNPRESSED,
2337 GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
2338 GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
2339 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
2340 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
2341 GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
2342 GDI_DECORATION_SHIFTING, 1, 1,
2343 GDI_EVENT_MASK, event_mask,
2344 GDI_CALLBACK_ACTION, HandleToolButtons,
2348 Error(ERR_EXIT, "cannot create gadget");
2350 tool_gadget[id] = gi;
2354 void FreeToolButtons()
2358 for (i=0; i<NUM_TOOL_BUTTONS; i++)
2359 FreeGadget(tool_gadget[i]);
2362 static void UnmapToolButtons()
2366 for (i=0; i<NUM_TOOL_BUTTONS; i++)
2367 UnmapGadget(tool_gadget[i]);
2370 static void HandleToolButtons(struct GadgetInfo *gi)
2372 request_gadget_id = gi->custom_id;
2375 int get_next_element(int element)
2379 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
2380 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
2381 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
2382 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
2383 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
2384 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
2385 case EL_AMOEBA_DROPPING: return EL_AMOEBA_WET;
2387 default: return element;
2391 int el_act_dir2img(int element, int action, int direction)
2393 direction = MV_DIR_BIT(direction);
2395 return element_info[element].direction_graphic[action][direction];
2398 int el_act2img(int element, int action)
2400 return element_info[element].graphic[action];
2403 int el_dir2img(int element, int direction)
2405 return el_act_dir2img(element, ACTION_DEFAULT, direction);
2408 int el2img(int element)
2410 return element_info[element].graphic[ACTION_DEFAULT];
2413 int el2edimg(int element)
2415 return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
2418 int el2preimg(int element)
2420 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];