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 /* check if neighbour field is of same type */
1203 if (CAN_BE_CRUMBLED(element))
1206 if (i == 1 || i == 2)
1210 cx = (i == 2 ? TILEX - snip : 0);
1218 cy = (i == 3 ? TILEY - snip : 0);
1221 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1222 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
1225 MarkTileDirty(sx, sy);
1227 else /* crumble neighbour fields */
1229 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1233 int xx = x + xy[i][0];
1234 int yy = y + xy[i][1];
1235 int sxx = sx + xy[i][0];
1236 int syy = sy + xy[i][1];
1238 if (!IN_LEV_FIELD(xx, yy) ||
1239 !IN_SCR_FIELD(sxx, syy) ||
1240 !CAN_BE_CRUMBLED(Feld[xx][yy]))
1243 if (i == 1 || i == 2)
1247 cx = (i == 1 ? TILEX - snip : 0);
1255 cy = (i==0 ? TILEY-snip : 0);
1258 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1259 width, height, FX + sxx * TILEX + cx, FY + syy * TILEY + cy);
1261 MarkTileDirty(sxx, syy);
1266 void DrawLevelFieldCrumbledSand(int x, int y)
1268 DrawLevelFieldCrumbledSandExt(x, y, IMG_SAND_CRUMBLED, 0);
1271 void DrawLevelFieldCrumbledSandDigging(int x, int y, int direction,
1274 int graphic1 = el_act_dir2img(EL_SAND, ACTION_DIGGING, direction);
1275 int graphic2 = el_act_dir2img(EL_SAND_CRUMBLED, ACTION_DIGGING, direction);
1276 int frame1 = getGraphicAnimationFrame(graphic1, step_frame);
1277 int frame2 = getGraphicAnimationFrame(graphic2, step_frame);
1278 int sx = SCREENX(x), sy = SCREENY(y);
1280 DrawGraphic(sx, sy, graphic1, frame1);
1281 DrawLevelFieldCrumbledSandExt(x, y, graphic2, frame2);
1284 static int getBorderElement(int x, int y)
1288 { EL_STEELWALL_TOPLEFT, EL_INVISIBLE_STEELWALL_TOPLEFT },
1289 { EL_STEELWALL_TOPRIGHT, EL_INVISIBLE_STEELWALL_TOPRIGHT },
1290 { EL_STEELWALL_BOTTOMLEFT, EL_INVISIBLE_STEELWALL_BOTTOMLEFT },
1291 { EL_STEELWALL_BOTTOMRIGHT, EL_INVISIBLE_STEELWALL_BOTTOMRIGHT },
1292 { EL_STEELWALL_VERTICAL, EL_INVISIBLE_STEELWALL_VERTICAL },
1293 { EL_STEELWALL_HORIZONTAL, EL_INVISIBLE_STEELWALL_HORIZONTAL },
1294 { EL_STEELWALL, EL_INVISIBLE_STEELWALL }
1296 int steel_type = (BorderElement == EL_STEELWALL ? 0 : 1);
1297 int steel_position = (x == -1 && y == -1 ? 0 :
1298 x == lev_fieldx && y == -1 ? 1 :
1299 x == -1 && y == lev_fieldy ? 2 :
1300 x == lev_fieldx && y == lev_fieldy ? 3 :
1301 x == -1 || x == lev_fieldx ? 4 :
1302 y == -1 || y == lev_fieldy ? 5 : 6);
1304 return border[steel_position][steel_type];
1307 void DrawScreenElement(int x, int y, int element)
1309 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
1310 DrawLevelFieldCrumbledSand(LEVELX(x), LEVELY(y));
1313 void DrawLevelElement(int x, int y, int element)
1315 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1316 DrawScreenElement(SCREENX(x), SCREENY(y), element);
1319 void DrawScreenField(int x, int y)
1321 int lx = LEVELX(x), ly = LEVELY(y);
1322 int element, content;
1324 if (!IN_LEV_FIELD(lx, ly))
1326 if (lx < -1 || lx > lev_fieldx || ly < -1 || ly > lev_fieldy)
1329 element = getBorderElement(lx, ly);
1331 DrawScreenElement(x, y, element);
1335 element = Feld[lx][ly];
1336 content = Store[lx][ly];
1338 if (IS_MOVING(lx, ly))
1340 int horiz_move = (MovDir[lx][ly] == MV_LEFT || MovDir[lx][ly] == MV_RIGHT);
1341 boolean cut_mode = NO_CUTTING;
1343 if (element == EL_QUICKSAND_EMPTYING ||
1344 element == EL_MAGIC_WALL_EMPTYING ||
1345 element == EL_BD_MAGIC_WALL_EMPTYING ||
1346 element == EL_AMOEBA_DROPPING)
1347 cut_mode = CUT_ABOVE;
1348 else if (element == EL_QUICKSAND_FILLING ||
1349 element == EL_MAGIC_WALL_FILLING ||
1350 element == EL_BD_MAGIC_WALL_FILLING)
1351 cut_mode = CUT_BELOW;
1353 if (cut_mode == CUT_ABOVE)
1354 DrawScreenElementShifted(x, y, 0, 0, element, NO_CUTTING);
1356 DrawScreenElement(x, y, EL_EMPTY);
1359 DrawScreenElementShifted(x, y, MovPos[lx][ly], 0, element, NO_CUTTING);
1360 else if (cut_mode == NO_CUTTING)
1361 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], element, cut_mode);
1363 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], content, cut_mode);
1365 if (content == EL_ACID)
1366 DrawLevelElementThruMask(lx, ly + 1, EL_ACID);
1368 else if (IS_BLOCKED(lx, ly))
1373 boolean cut_mode = NO_CUTTING;
1374 int element_old, content_old;
1376 Blocked2Moving(lx, ly, &oldx, &oldy);
1379 horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
1380 MovDir[oldx][oldy] == MV_RIGHT);
1382 element_old = Feld[oldx][oldy];
1383 content_old = Store[oldx][oldy];
1385 if (element_old == EL_QUICKSAND_EMPTYING ||
1386 element_old == EL_MAGIC_WALL_EMPTYING ||
1387 element_old == EL_BD_MAGIC_WALL_EMPTYING ||
1388 element_old == EL_AMOEBA_DROPPING)
1389 cut_mode = CUT_ABOVE;
1391 DrawScreenElement(x, y, EL_EMPTY);
1394 DrawScreenElementShifted(sx, sy, MovPos[oldx][oldy], 0, element_old,
1396 else if (cut_mode == NO_CUTTING)
1397 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], element_old,
1400 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], content_old,
1403 else if (IS_DRAWABLE(element))
1404 DrawScreenElement(x, y, element);
1406 DrawScreenElement(x, y, EL_EMPTY);
1409 void DrawLevelField(int x, int y)
1411 if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1412 DrawScreenField(SCREENX(x), SCREENY(y));
1413 else if (IS_MOVING(x, y))
1417 Moving2Blocked(x, y, &newx, &newy);
1418 if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
1419 DrawScreenField(SCREENX(newx), SCREENY(newy));
1421 else if (IS_BLOCKED(x, y))
1425 Blocked2Moving(x, y, &oldx, &oldy);
1426 if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
1427 DrawScreenField(SCREENX(oldx), SCREENY(oldy));
1431 void DrawMiniElement(int x, int y, int element)
1435 graphic = el2edimg(element);
1436 DrawMiniGraphic(x, y, graphic);
1439 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
1441 int x = sx + scroll_x, y = sy + scroll_y;
1443 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
1444 DrawMiniElement(sx, sy, EL_EMPTY);
1445 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
1446 DrawMiniElement(sx, sy, Feld[x][y]);
1448 DrawMiniGraphic(sx, sy, el2edimg(getBorderElement(x, y)));
1451 void getMicroGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
1453 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
1454 int mini_startx = src_bitmap->width * 3 / 4;
1455 int mini_starty = src_bitmap->height * 2 / 3;
1456 int src_x = mini_startx + graphic_info[graphic].src_x / 8;
1457 int src_y = mini_starty + graphic_info[graphic].src_y / 8;
1459 if (src_x + MICRO_TILEX > src_bitmap->width ||
1460 src_y + MICRO_TILEY > src_bitmap->height)
1462 /* graphic of desired size seems not to be contained in this image;
1463 dirty workaround: get it from the middle of the normal sized image */
1465 getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
1466 src_x += (TILEX / 2 - MICRO_TILEX / 2);
1467 src_y += (TILEY / 2 - MICRO_TILEY / 2);
1470 *bitmap = src_bitmap;
1475 void DrawMicroElement(int xpos, int ypos, int element)
1479 int graphic = el2preimg(element);
1481 getMicroGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
1482 BlitBitmap(src_bitmap, drawto, src_x, src_y, MICRO_TILEX, MICRO_TILEY,
1490 SetDrawBackgroundMask(REDRAW_NONE);
1493 for(x=BX1; x<=BX2; x++)
1494 for(y=BY1; y<=BY2; y++)
1495 DrawScreenField(x, y);
1497 redraw_mask |= REDRAW_FIELD;
1500 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
1504 for(x=0; x<size_x; x++)
1505 for(y=0; y<size_y; y++)
1506 DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
1508 redraw_mask |= REDRAW_FIELD;
1511 static void DrawMicroLevelExt(int xpos, int ypos, int from_x, int from_y)
1515 DrawBackground(xpos, ypos, MICROLEV_XSIZE, MICROLEV_YSIZE);
1517 if (lev_fieldx < STD_LEV_FIELDX)
1518 xpos += (STD_LEV_FIELDX - lev_fieldx) / 2 * MICRO_TILEX;
1519 if (lev_fieldy < STD_LEV_FIELDY)
1520 ypos += (STD_LEV_FIELDY - lev_fieldy) / 2 * MICRO_TILEY;
1522 xpos += MICRO_TILEX;
1523 ypos += MICRO_TILEY;
1525 for(x=-1; x<=STD_LEV_FIELDX; x++)
1527 for(y=-1; y<=STD_LEV_FIELDY; y++)
1529 int lx = from_x + x, ly = from_y + y;
1531 if (lx >= 0 && lx < lev_fieldx && ly >= 0 && ly < lev_fieldy)
1532 DrawMicroElement(xpos + x * MICRO_TILEX, ypos + y * MICRO_TILEY,
1534 else if (lx >= -1 && lx < lev_fieldx+1 && ly >= -1 && ly < lev_fieldy+1
1535 && BorderElement != EL_EMPTY)
1536 DrawMicroElement(xpos + x * MICRO_TILEX, ypos + y * MICRO_TILEY,
1537 getBorderElement(lx, ly));
1541 redraw_mask |= REDRAW_MICROLEVEL;
1544 #define MICROLABEL_EMPTY 0
1545 #define MICROLABEL_LEVEL_NAME 1
1546 #define MICROLABEL_CREATED_BY 2
1547 #define MICROLABEL_LEVEL_AUTHOR 3
1548 #define MICROLABEL_IMPORTED_FROM 4
1549 #define MICROLABEL_LEVEL_IMPORT_INFO 5
1551 static void DrawMicroLevelLabelExt(int mode)
1553 char label_text[MAX_OUTPUT_LINESIZE + 1];
1554 int max_len_label_text;
1555 int font_nr = FONT_TEXT_2;
1557 if (mode == MICROLABEL_CREATED_BY || mode == MICROLABEL_IMPORTED_FROM)
1558 font_nr = FONT_TEXT_3;
1560 max_len_label_text = SXSIZE / getFontWidth(font_nr);
1562 DrawBackground(SX, MICROLABEL_YPOS, SXSIZE, getFontHeight(font_nr));
1564 strncpy(label_text, (mode == MICROLABEL_LEVEL_NAME ? level.name :
1565 mode == MICROLABEL_CREATED_BY ? "created by" :
1566 mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
1567 mode == MICROLABEL_IMPORTED_FROM ? "imported from" :
1568 mode == MICROLABEL_LEVEL_IMPORT_INFO ?
1569 leveldir_current->imported_from : ""),
1570 max_len_label_text);
1571 label_text[max_len_label_text] = '\0';
1573 if (strlen(label_text) > 0)
1575 int text_width = strlen(label_text) * getFontWidth(font_nr);
1576 int lxpos = SX + (SXSIZE - text_width) / 2;
1577 int lypos = MICROLABEL_YPOS;
1579 DrawText(lxpos, lypos, label_text, font_nr);
1582 redraw_mask |= REDRAW_MICROLEVEL;
1585 void DrawMicroLevel(int xpos, int ypos, boolean restart)
1587 static unsigned long scroll_delay = 0;
1588 static unsigned long label_delay = 0;
1589 static int from_x, from_y, scroll_direction;
1590 static int label_state, label_counter;
1591 int last_game_status = game_status; /* save current game status */
1593 /* force PREVIEW font on preview level */
1594 game_status = GAME_MODE_PSEUDO_PREVIEW;
1598 from_x = from_y = 0;
1599 scroll_direction = MV_RIGHT;
1603 DrawMicroLevelExt(xpos, ypos, from_x, from_y);
1604 DrawMicroLevelLabelExt(label_state);
1606 /* initialize delay counters */
1607 DelayReached(&scroll_delay, 0);
1608 DelayReached(&label_delay, 0);
1610 if (leveldir_current->name)
1612 int len = strlen(leveldir_current->name);
1613 int lxpos = SX + (SXSIZE - len * getFontWidth(FONT_TEXT_1)) / 2;
1614 int lypos = SY + 352;
1616 DrawText(lxpos, lypos, leveldir_current->name, FONT_TEXT_1);
1619 game_status = last_game_status; /* restore current game status */
1624 /* scroll micro level, if needed */
1625 if ((lev_fieldx > STD_LEV_FIELDX || lev_fieldy > STD_LEV_FIELDY) &&
1626 DelayReached(&scroll_delay, MICROLEVEL_SCROLL_DELAY))
1628 switch (scroll_direction)
1634 scroll_direction = MV_UP;
1638 if (from_x < lev_fieldx - STD_LEV_FIELDX)
1641 scroll_direction = MV_DOWN;
1648 scroll_direction = MV_RIGHT;
1652 if (from_y < lev_fieldy - STD_LEV_FIELDY)
1655 scroll_direction = MV_LEFT;
1662 DrawMicroLevelExt(xpos, ypos, from_x, from_y);
1665 /* redraw micro level label, if needed */
1666 if (strcmp(level.name, NAMELESS_LEVEL_NAME) != 0 &&
1667 strcmp(level.author, ANONYMOUS_NAME) != 0 &&
1668 strcmp(level.author, leveldir_current->name) != 0 &&
1669 DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
1671 int max_label_counter = 23;
1673 if (leveldir_current->imported_from != NULL)
1674 max_label_counter += 14;
1676 label_counter = (label_counter + 1) % max_label_counter;
1677 label_state = (label_counter >= 0 && label_counter <= 7 ?
1678 MICROLABEL_LEVEL_NAME :
1679 label_counter >= 9 && label_counter <= 12 ?
1680 MICROLABEL_CREATED_BY :
1681 label_counter >= 14 && label_counter <= 21 ?
1682 MICROLABEL_LEVEL_AUTHOR :
1683 label_counter >= 23 && label_counter <= 26 ?
1684 MICROLABEL_IMPORTED_FROM :
1685 label_counter >= 28 && label_counter <= 35 ?
1686 MICROLABEL_LEVEL_IMPORT_INFO : MICROLABEL_EMPTY);
1687 DrawMicroLevelLabelExt(label_state);
1690 game_status = last_game_status; /* restore current game status */
1693 int REQ_in_range(int x, int y)
1695 if (y > DY+249 && y < DY+278)
1697 if (x > DX+1 && x < DX+48)
1699 else if (x > DX+51 && x < DX+98)
1705 #define MAX_REQUEST_LINES 13
1706 #define MAX_REQUEST_LINE_LEN 7
1708 boolean Request(char *text, unsigned int req_state)
1710 int mx, my, ty, result = -1;
1711 unsigned int old_door_state;
1712 int last_game_status = game_status; /* save current game status */
1714 #if defined(PLATFORM_UNIX)
1715 /* pause network game while waiting for request to answer */
1716 if (options.network &&
1717 game_status == GAME_MODE_PLAYING &&
1718 req_state & REQUEST_WAIT_FOR)
1719 SendToServer_PausePlaying();
1722 old_door_state = GetDoorState();
1726 CloseDoor(DOOR_CLOSE_1);
1728 /* save old door content */
1729 BlitBitmap(bitmap_db_door, bitmap_db_door,
1730 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
1731 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
1733 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
1735 /* clear door drawing field */
1736 DrawBackground(DX, DY, DXSIZE, DYSIZE);
1738 /* force DOOR font on preview level */
1739 game_status = GAME_MODE_PSEUDO_DOOR;
1741 /* write text for request */
1742 for(ty=0; ty < MAX_REQUEST_LINES; ty++)
1744 char text_line[MAX_REQUEST_LINE_LEN + 1];
1750 for(tl=0,tx=0; tx < MAX_REQUEST_LINE_LEN; tl++,tx++)
1753 if (!tc || tc == ' ')
1764 strncpy(text_line, text, tl);
1767 DrawText(DX + (DXSIZE - tl * getFontWidth(FONT_TEXT_2)) / 2,
1768 DY + 8 + ty * (getFontHeight(FONT_TEXT_2) + 2),
1769 text_line, FONT_TEXT_2);
1771 text += tl + (tc == ' ' ? 1 : 0);
1774 game_status = last_game_status; /* restore current game status */
1776 if (req_state & REQ_ASK)
1778 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
1779 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
1781 else if (req_state & REQ_CONFIRM)
1783 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
1785 else if (req_state & REQ_PLAYER)
1787 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
1788 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
1789 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
1790 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
1793 /* copy request gadgets to door backbuffer */
1794 BlitBitmap(drawto, bitmap_db_door,
1795 DX, DY, DXSIZE, DYSIZE,
1796 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
1798 OpenDoor(DOOR_OPEN_1);
1804 if (!(req_state & REQUEST_WAIT_FOR))
1806 SetDrawBackgroundMask(REDRAW_FIELD);
1811 if (game_status != GAME_MODE_MAIN)
1814 button_status = MB_RELEASED;
1816 request_gadget_id = -1;
1818 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
1830 case EVENT_BUTTONPRESS:
1831 case EVENT_BUTTONRELEASE:
1832 case EVENT_MOTIONNOTIFY:
1834 if (event.type == EVENT_MOTIONNOTIFY)
1836 if (!PointerInWindow(window))
1837 continue; /* window and pointer are on different screens */
1842 motion_status = TRUE;
1843 mx = ((MotionEvent *) &event)->x;
1844 my = ((MotionEvent *) &event)->y;
1848 motion_status = FALSE;
1849 mx = ((ButtonEvent *) &event)->x;
1850 my = ((ButtonEvent *) &event)->y;
1851 if (event.type == EVENT_BUTTONPRESS)
1852 button_status = ((ButtonEvent *) &event)->button;
1854 button_status = MB_RELEASED;
1857 /* this sets 'request_gadget_id' */
1858 HandleGadgets(mx, my, button_status);
1860 switch(request_gadget_id)
1862 case TOOL_CTRL_ID_YES:
1865 case TOOL_CTRL_ID_NO:
1868 case TOOL_CTRL_ID_CONFIRM:
1869 result = TRUE | FALSE;
1872 case TOOL_CTRL_ID_PLAYER_1:
1875 case TOOL_CTRL_ID_PLAYER_2:
1878 case TOOL_CTRL_ID_PLAYER_3:
1881 case TOOL_CTRL_ID_PLAYER_4:
1892 case EVENT_KEYPRESS:
1893 switch(GetEventKey((KeyEvent *)&event, TRUE))
1906 if (req_state & REQ_PLAYER)
1910 case EVENT_KEYRELEASE:
1911 ClearPlayerAction();
1915 HandleOtherEvents(&event);
1919 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
1921 int joy = AnyJoystick();
1923 if (joy & JOY_BUTTON_1)
1925 else if (joy & JOY_BUTTON_2)
1931 /* don't eat all CPU time */
1935 if (game_status != GAME_MODE_MAIN)
1940 if (!(req_state & REQ_STAY_OPEN))
1942 CloseDoor(DOOR_CLOSE_1);
1944 if (!(req_state & REQ_STAY_CLOSED) && (old_door_state & DOOR_OPEN_1))
1946 BlitBitmap(bitmap_db_door, bitmap_db_door,
1947 DOOR_GFX_PAGEX2,DOOR_GFX_PAGEY1, DXSIZE,DYSIZE,
1948 DOOR_GFX_PAGEX1,DOOR_GFX_PAGEY1);
1949 OpenDoor(DOOR_OPEN_1);
1955 SetDrawBackgroundMask(REDRAW_FIELD);
1957 #if defined(PLATFORM_UNIX)
1958 /* continue network game after request */
1959 if (options.network &&
1960 game_status == GAME_MODE_PLAYING &&
1961 req_state & REQUEST_WAIT_FOR)
1962 SendToServer_ContinuePlaying();
1968 unsigned int OpenDoor(unsigned int door_state)
1970 unsigned int new_door_state;
1972 if (door_state & DOOR_COPY_BACK)
1974 BlitBitmap(bitmap_db_door, bitmap_db_door,
1975 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE + VYSIZE,
1976 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
1977 door_state &= ~DOOR_COPY_BACK;
1980 new_door_state = MoveDoor(door_state);
1982 return(new_door_state);
1985 unsigned int CloseDoor(unsigned int door_state)
1987 unsigned int new_door_state;
1989 BlitBitmap(backbuffer, bitmap_db_door,
1990 DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
1991 BlitBitmap(backbuffer, bitmap_db_door,
1992 VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
1994 new_door_state = MoveDoor(door_state);
1996 return(new_door_state);
1999 unsigned int GetDoorState()
2001 return MoveDoor(DOOR_GET_STATE);
2004 unsigned int SetDoorState(unsigned int door_state)
2006 return MoveDoor(door_state | DOOR_SET_STATE);
2009 unsigned int MoveDoor(unsigned int door_state)
2011 static int door1 = DOOR_OPEN_1;
2012 static int door2 = DOOR_CLOSE_2;
2013 static unsigned long door_delay = 0;
2014 int x, start, stepsize = door.step_offset;
2015 unsigned long door_delay_value = door.step_delay;
2017 if (door_state == DOOR_GET_STATE)
2018 return(door1 | door2);
2020 if (door_state & DOOR_SET_STATE)
2022 if (door_state & DOOR_ACTION_1)
2023 door1 = door_state & DOOR_ACTION_1;
2024 if (door_state & DOOR_ACTION_2)
2025 door2 = door_state & DOOR_ACTION_2;
2027 return(door1 | door2);
2030 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
2031 door_state &= ~DOOR_OPEN_1;
2032 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
2033 door_state &= ~DOOR_CLOSE_1;
2034 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
2035 door_state &= ~DOOR_OPEN_2;
2036 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
2037 door_state &= ~DOOR_CLOSE_2;
2039 if (setup.quick_doors)
2042 door_delay_value = 0;
2044 StopSound(SND_DOOR_OPENING);
2045 StopSound(SND_DOOR_CLOSING);
2048 if (global.autoplay_leveldir)
2050 door_state |= DOOR_NO_DELAY;
2051 door_state &= ~DOOR_CLOSE_ALL;
2054 if (door_state & DOOR_ACTION)
2056 if (!(door_state & DOOR_NO_DELAY))
2058 /* opening door sound has priority over simultaneously closing door */
2059 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
2060 PlaySoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
2061 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
2062 PlaySoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
2065 start = ((door_state & DOOR_NO_DELAY) ? DXSIZE : 0);
2067 for(x=start; x<=DXSIZE; x+=stepsize)
2069 Bitmap *bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
2070 GC gc = bitmap->stored_clip_gc;
2072 if (!(door_state & DOOR_NO_DELAY))
2073 WaitUntilDelayReached(&door_delay, door_delay_value);
2075 if (door_state & DOOR_ACTION_1)
2077 int i = (door_state & DOOR_OPEN_1 ? DXSIZE-x : x);
2078 int j = (DXSIZE - i) / 3;
2080 BlitBitmap(bitmap_db_door, drawto,
2081 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + i/2,
2082 DXSIZE,DYSIZE - i/2, DX, DY);
2084 ClearRectangle(drawto, DX, DY + DYSIZE - i/2, DXSIZE,i/2);
2086 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2087 BlitBitmapMasked(bitmap, drawto,
2088 DXSIZE, DOOR_GFX_PAGEY1, i, 77,
2089 DX + DXSIZE - i, DY + j);
2090 BlitBitmapMasked(bitmap, drawto,
2091 DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63,
2092 DX + DXSIZE - i, DY + 140 + j);
2093 SetClipOrigin(bitmap, gc, DX - DXSIZE + i, DY - (DOOR_GFX_PAGEY1 + j));
2094 BlitBitmapMasked(bitmap, drawto,
2095 DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j,
2097 BlitBitmapMasked(bitmap, drawto,
2098 DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63,
2101 BlitBitmapMasked(bitmap, drawto,
2102 DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
2104 BlitBitmapMasked(bitmap, drawto,
2105 DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
2107 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2108 BlitBitmapMasked(bitmap, drawto,
2109 DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
2110 DX + DXSIZE - i, DY + 77 + j);
2111 BlitBitmapMasked(bitmap, drawto,
2112 DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
2113 DX + DXSIZE - i, DY + 203 + j);
2115 redraw_mask |= REDRAW_DOOR_1;
2118 if (door_state & DOOR_ACTION_2)
2120 int i = (door_state & DOOR_OPEN_2 ? VXSIZE - x : x);
2121 int j = (VXSIZE - i) / 3;
2123 BlitBitmap(bitmap_db_door, drawto,
2124 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + i/2,
2125 VXSIZE, VYSIZE - i/2, VX, VY);
2127 ClearRectangle(drawto, VX, VY + VYSIZE-i/2, VXSIZE, i/2);
2129 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2130 BlitBitmapMasked(bitmap, drawto,
2131 VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2,
2132 VX + VXSIZE-i, VY+j);
2133 SetClipOrigin(bitmap, gc,
2134 VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
2135 BlitBitmapMasked(bitmap, drawto,
2136 VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j,
2139 BlitBitmapMasked(bitmap, drawto,
2140 VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2,
2141 i, VYSIZE / 2, VX, VY + VYSIZE / 2 - j);
2142 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2143 BlitBitmapMasked(bitmap, drawto,
2144 VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2,
2146 VX + VXSIZE - i, VY + VYSIZE / 2 + j);
2148 redraw_mask |= REDRAW_DOOR_2;
2153 if (game_status == GAME_MODE_MAIN)
2158 if (setup.quick_doors)
2160 StopSound(SND_DOOR_OPENING);
2161 StopSound(SND_DOOR_CLOSING);
2164 if (door_state & DOOR_ACTION_1)
2165 door1 = door_state & DOOR_ACTION_1;
2166 if (door_state & DOOR_ACTION_2)
2167 door2 = door_state & DOOR_ACTION_2;
2169 return (door1 | door2);
2172 void DrawSpecialEditorDoor()
2174 /* draw bigger toolbox window */
2175 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
2176 DOOR_GFX_PAGEX7, 0, EXSIZE + 8, 8,
2178 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
2179 EX - 4, VY - 4, EXSIZE + 8, EYSIZE - VYSIZE + 4,
2182 redraw_mask |= REDRAW_ALL;
2185 void UndrawSpecialEditorDoor()
2187 /* draw normal tape recorder window */
2188 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
2189 EX - 4, EY - 12, EXSIZE + 8, EYSIZE - VYSIZE + 12,
2192 redraw_mask |= REDRAW_ALL;
2196 /* ---------- new tool button stuff ---------------------------------------- */
2198 /* graphic position values for tool buttons */
2199 #define TOOL_BUTTON_YES_XPOS 2
2200 #define TOOL_BUTTON_YES_YPOS 250
2201 #define TOOL_BUTTON_YES_GFX_YPOS 0
2202 #define TOOL_BUTTON_YES_XSIZE 46
2203 #define TOOL_BUTTON_YES_YSIZE 28
2204 #define TOOL_BUTTON_NO_XPOS 52
2205 #define TOOL_BUTTON_NO_YPOS TOOL_BUTTON_YES_YPOS
2206 #define TOOL_BUTTON_NO_GFX_YPOS TOOL_BUTTON_YES_GFX_YPOS
2207 #define TOOL_BUTTON_NO_XSIZE TOOL_BUTTON_YES_XSIZE
2208 #define TOOL_BUTTON_NO_YSIZE TOOL_BUTTON_YES_YSIZE
2209 #define TOOL_BUTTON_CONFIRM_XPOS TOOL_BUTTON_YES_XPOS
2210 #define TOOL_BUTTON_CONFIRM_YPOS TOOL_BUTTON_YES_YPOS
2211 #define TOOL_BUTTON_CONFIRM_GFX_YPOS 30
2212 #define TOOL_BUTTON_CONFIRM_XSIZE 96
2213 #define TOOL_BUTTON_CONFIRM_YSIZE TOOL_BUTTON_YES_YSIZE
2214 #define TOOL_BUTTON_PLAYER_XSIZE 30
2215 #define TOOL_BUTTON_PLAYER_YSIZE 30
2216 #define TOOL_BUTTON_PLAYER_GFX_XPOS 5
2217 #define TOOL_BUTTON_PLAYER_GFX_YPOS 185
2218 #define TOOL_BUTTON_PLAYER_XPOS (5 + TOOL_BUTTON_PLAYER_XSIZE / 2)
2219 #define TOOL_BUTTON_PLAYER_YPOS (215 - TOOL_BUTTON_PLAYER_YSIZE / 2)
2220 #define TOOL_BUTTON_PLAYER1_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2221 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2222 #define TOOL_BUTTON_PLAYER2_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2223 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2224 #define TOOL_BUTTON_PLAYER3_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2225 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2226 #define TOOL_BUTTON_PLAYER4_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2227 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2228 #define TOOL_BUTTON_PLAYER1_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2229 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2230 #define TOOL_BUTTON_PLAYER2_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2231 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2232 #define TOOL_BUTTON_PLAYER3_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2233 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2234 #define TOOL_BUTTON_PLAYER4_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2235 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2244 } toolbutton_info[NUM_TOOL_BUTTONS] =
2247 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_GFX_YPOS,
2248 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_YPOS,
2249 TOOL_BUTTON_YES_XSIZE, TOOL_BUTTON_YES_YSIZE,
2254 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_GFX_YPOS,
2255 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_YPOS,
2256 TOOL_BUTTON_NO_XSIZE, TOOL_BUTTON_NO_YSIZE,
2261 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_GFX_YPOS,
2262 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_YPOS,
2263 TOOL_BUTTON_CONFIRM_XSIZE, TOOL_BUTTON_CONFIRM_YSIZE,
2264 TOOL_CTRL_ID_CONFIRM,
2268 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2269 TOOL_BUTTON_PLAYER1_XPOS, TOOL_BUTTON_PLAYER1_YPOS,
2270 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2271 TOOL_CTRL_ID_PLAYER_1,
2275 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2276 TOOL_BUTTON_PLAYER2_XPOS, TOOL_BUTTON_PLAYER2_YPOS,
2277 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2278 TOOL_CTRL_ID_PLAYER_2,
2282 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2283 TOOL_BUTTON_PLAYER3_XPOS, TOOL_BUTTON_PLAYER3_YPOS,
2284 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2285 TOOL_CTRL_ID_PLAYER_3,
2289 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2290 TOOL_BUTTON_PLAYER4_XPOS, TOOL_BUTTON_PLAYER4_YPOS,
2291 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2292 TOOL_CTRL_ID_PLAYER_4,
2297 void CreateToolButtons()
2301 for (i=0; i<NUM_TOOL_BUTTONS; i++)
2303 Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
2304 Bitmap *deco_bitmap = None;
2305 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
2306 struct GadgetInfo *gi;
2307 unsigned long event_mask;
2308 int gd_xoffset, gd_yoffset;
2309 int gd_x1, gd_x2, gd_y;
2312 event_mask = GD_EVENT_RELEASED;
2314 gd_xoffset = toolbutton_info[i].xpos;
2315 gd_yoffset = toolbutton_info[i].ypos;
2316 gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
2317 gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
2318 gd_y = DOOR_GFX_PAGEY1 + gd_yoffset;
2320 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
2322 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
2324 getMiniGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr),
2325 &deco_bitmap, &deco_x, &deco_y);
2326 deco_xpos = (toolbutton_info[i].width - MINI_TILEX) / 2;
2327 deco_ypos = (toolbutton_info[i].height - MINI_TILEY) / 2;
2330 gi = CreateGadget(GDI_CUSTOM_ID, id,
2331 GDI_INFO_TEXT, toolbutton_info[i].infotext,
2332 GDI_X, DX + toolbutton_info[i].x,
2333 GDI_Y, DY + toolbutton_info[i].y,
2334 GDI_WIDTH, toolbutton_info[i].width,
2335 GDI_HEIGHT, toolbutton_info[i].height,
2336 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
2337 GDI_STATE, GD_BUTTON_UNPRESSED,
2338 GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
2339 GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
2340 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
2341 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
2342 GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
2343 GDI_DECORATION_SHIFTING, 1, 1,
2344 GDI_EVENT_MASK, event_mask,
2345 GDI_CALLBACK_ACTION, HandleToolButtons,
2349 Error(ERR_EXIT, "cannot create gadget");
2351 tool_gadget[id] = gi;
2355 void FreeToolButtons()
2359 for (i=0; i<NUM_TOOL_BUTTONS; i++)
2360 FreeGadget(tool_gadget[i]);
2363 static void UnmapToolButtons()
2367 for (i=0; i<NUM_TOOL_BUTTONS; i++)
2368 UnmapGadget(tool_gadget[i]);
2371 static void HandleToolButtons(struct GadgetInfo *gi)
2373 request_gadget_id = gi->custom_id;
2376 int get_next_element(int element)
2380 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
2381 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
2382 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
2383 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
2384 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
2385 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
2386 case EL_AMOEBA_DROPPING: return EL_AMOEBA_WET;
2388 default: return element;
2392 int el_act_dir2img(int element, int action, int direction)
2394 element = GFX_ELEMENT(element);
2395 direction = MV_DIR_BIT(direction);
2397 return element_info[element].direction_graphic[action][direction];
2400 int el_act2img(int element, int action)
2402 element = GFX_ELEMENT(element);
2404 return element_info[element].graphic[action];
2407 int el_dir2img(int element, int direction)
2409 element = GFX_ELEMENT(element);
2411 return el_act_dir2img(element, ACTION_DEFAULT, direction);
2414 int el2img(int element)
2416 element = GFX_ELEMENT(element);
2418 return element_info[element].graphic[ACTION_DEFAULT];
2421 int el2edimg(int element)
2423 element = GFX_ELEMENT(element);
2425 return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
2428 int el2preimg(int element)
2430 element = GFX_ELEMENT(element);
2432 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];