1 /***********************************************************
2 * Rocks'n'Diamonds -- McDuffin Strikes Back! *
3 *----------------------------------------------------------*
4 * (c) 1995-2002 Artsoft Entertainment *
6 * Detmolder Strasse 189 *
9 * e-mail: info@artsoft.org *
10 *----------------------------------------------------------*
12 ***********************************************************/
14 #include "libgame/libgame.h"
23 /* tool button identifiers */
24 #define TOOL_CTRL_ID_YES 0
25 #define TOOL_CTRL_ID_NO 1
26 #define TOOL_CTRL_ID_CONFIRM 2
27 #define TOOL_CTRL_ID_PLAYER_1 3
28 #define TOOL_CTRL_ID_PLAYER_2 4
29 #define TOOL_CTRL_ID_PLAYER_3 5
30 #define TOOL_CTRL_ID_PLAYER_4 6
32 #define NUM_TOOL_BUTTONS 7
34 /* forward declaration for internal use */
35 static void UnmapToolButtons();
36 static void HandleToolButtons(struct GadgetInfo *);
38 static struct GadgetInfo *tool_gadget[NUM_TOOL_BUTTONS];
39 static int request_gadget_id = -1;
41 void SetDrawtoField(int mode)
43 if (mode == DRAW_BUFFERED && setup.soft_scrolling)
54 drawto_field = fieldbuffer;
56 else /* DRAW_DIRECT, DRAW_BACKBUFFER */
67 drawto_field = (mode == DRAW_DIRECT ? window : backbuffer);
71 void RedrawPlayfield(boolean force_redraw, int x, int y, int width, int height)
73 if (game_status == GAME_MODE_PLAYING)
79 width = gfx.sxsize + 2 * TILEX;
80 height = gfx.sysize + 2 * TILEY;
83 if (force_redraw || setup.direct_draw)
86 int x1 = (x - SX) / TILEX, y1 = (y - SY) / TILEY;
87 int x2 = (x - SX + width) / TILEX, y2 = (y - SY + height) / TILEY;
89 if (setup.direct_draw)
90 SetDrawtoField(DRAW_BACKBUFFER);
92 for(xx=BX1; xx<=BX2; xx++)
93 for(yy=BY1; yy<=BY2; yy++)
94 if (xx >= x1 && xx <= x2 && yy >= y1 && yy <= y2)
95 DrawScreenField(xx, yy);
98 if (setup.direct_draw)
99 SetDrawtoField(DRAW_DIRECT);
102 if (setup.soft_scrolling)
104 int fx = FX, fy = FY;
106 fx += (ScreenMovDir & (MV_LEFT|MV_RIGHT) ? ScreenGfxPos : 0);
107 fy += (ScreenMovDir & (MV_UP|MV_DOWN) ? ScreenGfxPos : 0);
109 BlitBitmap(fieldbuffer, backbuffer, fx,fy, SXSIZE,SYSIZE, SX,SY);
113 BlitBitmap(drawto, window, x, y, width, height, x, y);
119 DrawBuffer *buffer = (drawto_field == window ? backbuffer : drawto_field);
121 if (setup.direct_draw && game_status == GAME_MODE_PLAYING)
122 redraw_mask &= ~REDRAW_MAIN;
124 if (redraw_mask & REDRAW_TILES && redraw_tiles > REDRAWTILES_THRESHOLD)
125 redraw_mask |= REDRAW_FIELD;
127 if (redraw_mask & REDRAW_FIELD)
128 redraw_mask &= ~REDRAW_TILES;
130 if (redraw_mask == REDRAW_NONE)
133 if (global.fps_slowdown && game_status == GAME_MODE_PLAYING)
135 static boolean last_frame_skipped = FALSE;
136 boolean skip_even_when_not_scrolling = TRUE;
137 boolean just_scrolling = (ScreenMovDir != 0);
138 boolean verbose = FALSE;
140 if (global.fps_slowdown_factor > 1 &&
141 (FrameCounter % global.fps_slowdown_factor) &&
142 (just_scrolling || skip_even_when_not_scrolling))
144 redraw_mask &= ~REDRAW_MAIN;
146 last_frame_skipped = TRUE;
149 printf("FRAME SKIPPED\n");
153 if (last_frame_skipped)
154 redraw_mask |= REDRAW_FIELD;
156 last_frame_skipped = FALSE;
159 printf("frame not skipped\n");
163 /* synchronize X11 graphics at this point; if we would synchronize the
164 display immediately after the buffer switching (after the XFlush),
165 this could mean that we have to wait for the graphics to complete,
166 although we could go on doing calculations for the next frame */
170 if (redraw_mask & REDRAW_ALL)
172 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
176 if (redraw_mask & REDRAW_FIELD)
178 if (game_status != GAME_MODE_PLAYING ||
179 redraw_mask & REDRAW_FROM_BACKBUFFER)
181 BlitBitmap(backbuffer, window,
182 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE, REAL_SX, REAL_SY);
186 int fx = FX, fy = FY;
188 if (setup.soft_scrolling)
190 fx += (ScreenMovDir & (MV_LEFT | MV_RIGHT) ? ScreenGfxPos : 0);
191 fy += (ScreenMovDir & (MV_UP | MV_DOWN) ? ScreenGfxPos : 0);
194 if (setup.soft_scrolling ||
195 ABS(ScreenMovPos) + ScrollStepSize == TILEX ||
196 ABS(ScreenMovPos) == ScrollStepSize ||
197 redraw_tiles > REDRAWTILES_THRESHOLD)
199 BlitBitmap(buffer, window, fx, fy, SXSIZE, SYSIZE, SX, SY);
203 printf("redrawing all (ScreenGfxPos == %d) because %s\n",
205 (setup.soft_scrolling ?
206 "setup.soft_scrolling" :
207 ABS(ScreenGfxPos) + ScrollStepSize == TILEX ?
208 "ABS(ScreenGfxPos) + ScrollStepSize == TILEX" :
209 ABS(ScreenGfxPos) == ScrollStepSize ?
210 "ABS(ScreenGfxPos) == ScrollStepSize" :
211 "redraw_tiles > REDRAWTILES_THRESHOLD"));
217 redraw_mask &= ~REDRAW_MAIN;
220 if (redraw_mask & REDRAW_DOORS)
222 if (redraw_mask & REDRAW_DOOR_1)
223 BlitBitmap(backbuffer, window, DX, DY, DXSIZE, DYSIZE, DX, DY);
224 if (redraw_mask & REDRAW_DOOR_2)
226 if ((redraw_mask & REDRAW_DOOR_2) == REDRAW_DOOR_2)
227 BlitBitmap(backbuffer, window, VX,VY, VXSIZE,VYSIZE, VX,VY);
230 if (redraw_mask & REDRAW_VIDEO_1)
231 BlitBitmap(backbuffer, window,
232 VX+VIDEO_DISPLAY1_XPOS,VY+VIDEO_DISPLAY1_YPOS,
233 VIDEO_DISPLAY_XSIZE,VIDEO_DISPLAY_YSIZE,
234 VX+VIDEO_DISPLAY1_XPOS,VY+VIDEO_DISPLAY1_YPOS);
235 if (redraw_mask & REDRAW_VIDEO_2)
236 BlitBitmap(backbuffer, window,
237 VX+VIDEO_DISPLAY2_XPOS,VY+VIDEO_DISPLAY2_YPOS,
238 VIDEO_DISPLAY_XSIZE,VIDEO_DISPLAY_YSIZE,
239 VX+VIDEO_DISPLAY2_XPOS,VY+VIDEO_DISPLAY2_YPOS);
240 if (redraw_mask & REDRAW_VIDEO_3)
241 BlitBitmap(backbuffer, window,
242 VX+VIDEO_CONTROL_XPOS,VY+VIDEO_CONTROL_YPOS,
243 VIDEO_CONTROL_XSIZE,VIDEO_CONTROL_YSIZE,
244 VX+VIDEO_CONTROL_XPOS,VY+VIDEO_CONTROL_YPOS);
248 if (redraw_mask & REDRAW_DOOR_3)
249 BlitBitmap(backbuffer, window, EX, EY, EXSIZE, EYSIZE, EX, EY);
251 redraw_mask &= ~REDRAW_DOORS;
254 if (redraw_mask & REDRAW_MICROLEVEL)
256 BlitBitmap(backbuffer, window, SX, SY + 10 * TILEY, SXSIZE, 7 * TILEY,
257 SX, SY + 10 * TILEY);
259 redraw_mask &= ~REDRAW_MICROLEVEL;
262 if (redraw_mask & REDRAW_TILES)
264 for(x=0; x<SCR_FIELDX; x++)
265 for(y=0; y<SCR_FIELDY; y++)
266 if (redraw[redraw_x1 + x][redraw_y1 + y])
267 BlitBitmap(buffer, window,
268 FX + x * TILEX, FX + y * TILEY, TILEX, TILEY,
269 SX + x * TILEX, SY + y * TILEY);
272 if (redraw_mask & REDRAW_FPS) /* display frames per second */
277 sprintf(info1, " (only every %d. frame)", global.fps_slowdown_factor);
278 if (!global.fps_slowdown)
281 sprintf(text, "%.1f fps%s", global.frames_per_second, info1);
282 DrawTextExt(window, SX, SY, text, FONT_TEXT_2, BLIT_OPAQUE);
287 for(x=0; x<MAX_BUF_XSIZE; x++)
288 for(y=0; y<MAX_BUF_YSIZE; y++)
291 redraw_mask = REDRAW_NONE;
297 long fading_delay = 300;
299 if (setup.fading && (redraw_mask & REDRAW_FIELD))
306 ClearRectangle(window, REAL_SX,REAL_SY,FULL_SXSIZE,FULL_SYSIZE);
309 for(i=0;i<2*FULL_SYSIZE;i++)
311 for(y=0;y<FULL_SYSIZE;y++)
313 BlitBitmap(backbuffer, window,
314 REAL_SX,REAL_SY+i, FULL_SXSIZE,1, REAL_SX,REAL_SY+i);
322 for(i=1;i<FULL_SYSIZE;i+=2)
323 BlitBitmap(backbuffer, window,
324 REAL_SX,REAL_SY+i, FULL_SXSIZE,1, REAL_SX,REAL_SY+i);
330 SetClipOrigin(clip_gc[PIX_FADEMASK], 0, 0);
331 BlitBitmapMasked(backbuffer, window,
332 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
337 SetClipOrigin(clip_gc[PIX_FADEMASK], -1, -1);
338 BlitBitmapMasked(backbuffer, window,
339 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
344 SetClipOrigin(clip_gc[PIX_FADEMASK], 0, -1);
345 BlitBitmapMasked(backbuffer, window,
346 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
351 SetClipOrigin(clip_gc[PIX_FADEMASK], -1, 0);
352 BlitBitmapMasked(backbuffer, window,
353 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
358 redraw_mask &= ~REDRAW_MAIN;
365 void SetMainBackgroundImage(int graphic)
367 SetMainBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
368 graphic_info[graphic].bitmap ?
369 graphic_info[graphic].bitmap :
370 graphic_info[IMG_BACKGROUND].bitmap);
373 void SetDoorBackgroundImage(int graphic)
375 SetDoorBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
376 graphic_info[graphic].bitmap ?
377 graphic_info[graphic].bitmap :
378 graphic_info[IMG_BACKGROUND].bitmap);
381 void DrawBackground(int dest_x, int dest_y, int width, int height)
383 ClearRectangleOnBackground(backbuffer, dest_x, dest_y, width, height);
385 redraw_mask |= REDRAW_FIELD;
390 DrawBackground(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
392 if (setup.soft_scrolling && game_status == GAME_MODE_PLAYING)
394 ClearRectangle(fieldbuffer, 0, 0, FXSIZE, FYSIZE);
395 SetDrawtoField(DRAW_BUFFERED);
398 SetDrawtoField(DRAW_BACKBUFFER);
400 if (setup.direct_draw && game_status == GAME_MODE_PLAYING)
402 ClearRectangle(window, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
403 SetDrawtoField(DRAW_DIRECT);
407 void MarkTileDirty(int x, int y)
409 int xx = redraw_x1 + x;
410 int yy = redraw_y1 + y;
415 redraw[xx][yy] = TRUE;
416 redraw_mask |= REDRAW_TILES;
419 void SetBorderElement()
423 BorderElement = EL_EMPTY;
425 for(y=0; y<lev_fieldy && BorderElement == EL_EMPTY; y++)
427 for(x=0; x<lev_fieldx; x++)
429 if (!IS_INDESTRUCTIBLE(Feld[x][y]))
430 BorderElement = EL_STEELWALL;
432 if (y != 0 && y != lev_fieldy - 1 && x != lev_fieldx - 1)
438 void SetRandomAnimationValue(int x, int y)
440 gfx.anim_random_frame = GfxRandom[x][y];
443 inline int getGraphicAnimationFrame(int graphic, int sync_frame)
445 /* animation synchronized with global frame counter, not move position */
446 if (graphic_info[graphic].anim_global_sync || sync_frame < 0)
447 sync_frame = FrameCounter;
449 return getAnimationFrame(graphic_info[graphic].anim_frames,
450 graphic_info[graphic].anim_delay,
451 graphic_info[graphic].anim_mode,
452 graphic_info[graphic].anim_start_frame,
456 inline void DrawGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
457 int graphic, int sync_frame, int mask_mode)
459 int frame = getGraphicAnimationFrame(graphic, sync_frame);
461 if (mask_mode == USE_MASKING)
462 DrawGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
464 DrawGraphicExt(dst_bitmap, x, y, graphic, frame);
467 inline void DrawGraphicAnimation(int x, int y, int graphic)
469 int lx = LEVELX(x), ly = LEVELY(y);
471 if (!IN_SCR_FIELD(x, y))
474 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
475 graphic, GfxFrame[lx][ly], NO_MASKING);
479 void DrawLevelGraphicAnimation(int x, int y, int graphic)
481 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
484 void DrawLevelElementAnimation(int x, int y, int element)
487 int graphic = el_act_dir2img(element, GfxAction[x][y], MovDir[x][y]);
489 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
491 DrawGraphicAnimation(SCREENX(x), SCREENY(y), el2img(element));
495 inline void DrawLevelGraphicAnimationIfNeeded(int x, int y, int graphic)
497 int sx = SCREENX(x), sy = SCREENY(y);
499 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
502 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
505 DrawGraphicAnimation(sx, sy, graphic);
508 void DrawLevelElementAnimationIfNeeded(int x, int y, int element)
510 int sx = SCREENX(x), sy = SCREENY(y);
513 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
516 graphic = el_act_dir2img(element, GfxAction[x][y], MovDir[x][y]);
518 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
521 DrawGraphicAnimation(sx, sy, graphic);
524 void DrawAllPlayers()
528 for(i=0; i<MAX_PLAYERS; i++)
529 if (stored_player[i].active)
530 DrawPlayer(&stored_player[i]);
533 void DrawPlayerField(int x, int y)
535 if (!IS_PLAYER(x, y))
538 DrawPlayer(PLAYERINFO(x, y));
541 void DrawPlayer(struct PlayerInfo *player)
544 int jx = player->jx, jy = player->jy;
545 int last_jx = player->last_jx, last_jy = player->last_jy;
546 int next_jx = jx + (jx - last_jx), next_jy = jy + (jy - last_jy);
547 int sx = SCREENX(jx), sy = SCREENY(jy);
548 int sxx = 0, syy = 0;
549 int element = Feld[jx][jy], last_element = Feld[last_jx][last_jy];
552 boolean player_is_moving = (last_jx != jx || last_jy != jy ? TRUE : FALSE);
553 int move_dir = player->MovDir;
554 int action = ACTION_DEFAULT;
556 int jx = player->jx, jy = player->jy;
557 int move_dir = player->MovDir;
558 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? +1 : 0);
559 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? +1 : 0);
560 int last_jx = (player->is_moving ? jx - dx : jx);
561 int last_jy = (player->is_moving ? jy - dy : jy);
562 int next_jx = jx + dx;
563 int next_jy = jy + dy;
564 int sx = SCREENX(jx), sy = SCREENY(jy);
565 int sxx = 0, syy = 0;
566 int element = Feld[jx][jy], last_element = Feld[last_jx][last_jy];
569 boolean player_is_moving = (player->MovPos ? TRUE : FALSE);
570 int action = ACTION_DEFAULT;
573 if (!player->active || !IN_SCR_FIELD(SCREENX(last_jx), SCREENY(last_jy)))
577 if (!IN_LEV_FIELD(jx,jy))
579 printf("DrawPlayerField(): x = %d, y = %d\n",jx,jy);
580 printf("DrawPlayerField(): sx = %d, sy = %d\n",sx,sy);
581 printf("DrawPlayerField(): This should never happen!\n");
586 if (element == EL_EXPLOSION)
589 action = (player->Pushing ? ACTION_PUSHING :
590 player->is_digging ? ACTION_DIGGING :
591 player->is_collecting ? ACTION_COLLECTING :
592 player->is_moving ? ACTION_MOVING :
593 player->snapped ? ACTION_SNAPPING : ACTION_DEFAULT);
595 InitPlayerGfxAnimation(player, action, move_dir);
597 /* ----------------------------------------------------------------------- */
598 /* draw things in the field the player is leaving, if needed */
599 /* ----------------------------------------------------------------------- */
602 if (player->is_moving)
604 if (player_is_moving)
607 if (Back[last_jx][last_jy] && IS_DRAWABLE(last_element))
609 DrawLevelElement(last_jx, last_jy, Back[last_jx][last_jy]);
611 if (last_element == EL_DYNAMITE_ACTIVE ||
612 last_element == EL_SP_DISK_RED_ACTIVE)
613 DrawDynamite(last_jx, last_jy);
615 DrawLevelFieldThruMask(last_jx, last_jy);
617 else if (last_element == EL_DYNAMITE_ACTIVE ||
618 last_element == EL_SP_DISK_RED_ACTIVE)
619 DrawDynamite(last_jx, last_jy);
621 DrawLevelField(last_jx, last_jy);
623 if (player->Pushing && IN_SCR_FIELD(SCREENX(next_jx), SCREENY(next_jy)))
627 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
631 if (Feld[next_jx][next_jy] == EL_SOKOBAN_FIELD_FULL)
632 DrawLevelElement(next_jx, next_jy, EL_SOKOBAN_FIELD_EMPTY);
634 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
637 DrawLevelField(next_jx, next_jy);
643 if (!IN_SCR_FIELD(sx, sy))
646 if (setup.direct_draw)
647 SetDrawtoField(DRAW_BUFFERED);
649 /* ----------------------------------------------------------------------- */
650 /* draw things behind the player, if needed */
651 /* ----------------------------------------------------------------------- */
654 DrawLevelElement(jx, jy, Back[jx][jy]);
655 else if (IS_ACTIVE_BOMB(element))
656 DrawLevelElement(jx, jy, EL_EMPTY);
659 if (player_is_moving && GfxElement[jx][jy] != EL_UNDEFINED)
661 if (GfxElement[jx][jy] == EL_SAND)
662 DrawLevelFieldCrumbledSandDigging(jx, jy, move_dir, player->StepFrame);
665 int old_element = GfxElement[jx][jy];
666 int old_graphic = el_act_dir2img(old_element, action, move_dir);
667 int frame = getGraphicAnimationFrame(old_graphic, player->StepFrame);
669 DrawGraphic(sx, sy, old_graphic, frame);
674 GfxElement[jx][jy] = EL_UNDEFINED;
676 DrawLevelField(jx, jy);
680 /* ----------------------------------------------------------------------- */
681 /* draw player himself */
682 /* ----------------------------------------------------------------------- */
684 if (player->use_murphy_graphic)
686 static int last_horizontal_dir = MV_LEFT;
689 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
690 last_horizontal_dir = move_dir;
692 direction = (player->snapped ? move_dir : last_horizontal_dir);
694 graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, direction);
697 graphic = el_act_dir2img(player->element_nr, player->GfxAction, move_dir);
699 frame = getGraphicAnimationFrame(graphic, player->Frame);
703 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
704 sxx = player->GfxPos;
706 syy = player->GfxPos;
709 if (!setup.soft_scrolling && ScreenMovPos)
712 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
714 if (SHIELD_ON(player))
716 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
717 IMG_SHIELD_NORMAL_ACTIVE);
718 int frame = getGraphicAnimationFrame(graphic, -1);
720 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
723 /* ----------------------------------------------------------------------- */
724 /* draw things the player is pushing, if needed */
725 /* ----------------------------------------------------------------------- */
728 printf("::: %d, %d [%d, %d] [%d]\n",
729 player->Pushing, player_is_moving, player->GfxAction,
730 player->is_moving, player_is_moving);
734 if (player->Pushing && player->is_moving)
736 if (player->Pushing && player_is_moving)
739 int px = SCREENX(next_jx), py = SCREENY(next_jy);
741 if (Back[next_jx][next_jy])
742 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
745 if ((sxx || syy) && element == EL_SOKOBAN_OBJECT)
746 DrawGraphicShiftedThruMask(px, py, sxx, syy, IMG_SOKOBAN_OBJECT, 0,
750 (element == EL_SOKOBAN_FIELD_EMPTY ||
751 Feld[next_jx][next_jy] == EL_SOKOBAN_FIELD_FULL))
752 DrawGraphicShiftedThruMask(px, py, sxx, syy, IMG_SOKOBAN_OBJECT, 0,
758 int element = MovingOrBlocked2Element(next_jx, next_jy);
761 int element = Feld[jx][jy];
763 int element = Feld[next_jx][next_jy];
768 int graphic = el2img(element);
772 if ((sxx || syy) && IS_PUSHABLE(element))
775 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
776 frame = getGraphicAnimationFrame(graphic, player->Frame);
780 printf("::: pushing %d: %d ...\n", sxx, frame);
783 DrawGraphicShifted(px, py, sxx, syy, graphic, frame,
784 NO_CUTTING, NO_MASKING);
789 /* ----------------------------------------------------------------------- */
790 /* draw things in front of player (active dynamite or dynabombs) */
791 /* ----------------------------------------------------------------------- */
793 if (IS_ACTIVE_BOMB(element))
795 graphic = el2img(element);
796 frame = getGraphicAnimationFrame(graphic, GfxFrame[jx][jy]);
798 if (game.emulation == EMU_SUPAPLEX)
799 DrawGraphic(sx, sy, IMG_SP_DISK_RED, frame);
801 DrawGraphicThruMask(sx, sy, graphic, frame);
804 if (player_is_moving && last_element == EL_EXPLOSION)
807 int graphic = el_act2img(GfxElement[last_jx][last_jy], ACTION_EXPLODING);
809 int stored = Store[last_jx][last_jy];
810 int graphic = (game.emulation != EMU_SUPAPLEX ? IMG_EXPLOSION :
811 stored == EL_SP_INFOTRON ? IMG_SP_EXPLOSION_INFOTRON :
814 int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
815 int phase = ExplodePhase[last_jx][last_jy] - 1;
816 int frame = getGraphicAnimationFrame(graphic, phase - delay);
819 DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy), graphic, frame);
822 /* ----------------------------------------------------------------------- */
823 /* draw elements the player is just walking/passing through/under */
824 /* ----------------------------------------------------------------------- */
826 /* handle the field the player is leaving ... */
827 if (player_is_moving && IS_ACCESSIBLE_INSIDE(last_element))
828 DrawLevelField(last_jx, last_jy);
829 else if (player_is_moving && IS_ACCESSIBLE_UNDER(last_element))
830 DrawLevelFieldThruMask(last_jx, last_jy);
832 /* ... and the field the player is entering */
833 if (IS_ACCESSIBLE_INSIDE(element))
834 DrawLevelField(jx, jy);
835 else if (IS_ACCESSIBLE_UNDER(element))
836 DrawLevelFieldThruMask(jx, jy);
838 if (setup.direct_draw)
840 int dest_x = SX + SCREENX(MIN(jx, last_jx)) * TILEX;
841 int dest_y = SY + SCREENY(MIN(jy, last_jy)) * TILEY;
842 int x_size = TILEX * (1 + ABS(jx - last_jx));
843 int y_size = TILEY * (1 + ABS(jy - last_jy));
845 BlitBitmap(drawto_field, window,
846 dest_x, dest_y, x_size, y_size, dest_x, dest_y);
847 SetDrawtoField(DRAW_DIRECT);
850 MarkTileDirty(sx,sy);
853 void getGraphicSource(int graphic, int frame, Bitmap **bitmap, int *x, int *y)
855 struct GraphicInfo *g = &graphic_info[graphic];
859 if (g->offset_y == 0) /* frames are ordered horizontally */
861 int max_width = g->anim_frames_per_line * g->width;
863 *x = (g->src_x + frame * g->offset_x) % max_width;
864 *y = g->src_y + (g->src_x + frame * g->offset_x) / max_width * g->height;
866 else if (g->offset_x == 0) /* frames are ordered vertically */
868 int max_height = g->anim_frames_per_line * g->height;
870 *x = g->src_x + (g->src_y + frame * g->offset_y) / max_height * g->width;
871 *y = (g->src_y + frame * g->offset_y) % max_height;
873 else /* frames are ordered diagonally */
875 *x = g->src_x + frame * g->offset_x;
876 *y = g->src_y + frame * g->offset_y;
880 void DrawGraphic(int x, int y, int graphic, int frame)
883 if (!IN_SCR_FIELD(x, y))
885 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
886 printf("DrawGraphic(): This should never happen!\n");
891 DrawGraphicExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic, frame);
895 void DrawGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
901 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
902 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
905 void DrawGraphicThruMask(int x, int y, int graphic, int frame)
908 if (!IN_SCR_FIELD(x, y))
910 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
911 printf("DrawGraphicThruMask(): This should never happen!\n");
916 DrawGraphicThruMaskExt(drawto_field, FX + x * TILEX, FY + y *TILEY, graphic,
921 void DrawGraphicThruMaskExt(DrawBuffer *d, int dest_x, int dest_y, int graphic,
929 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
930 drawing_gc = src_bitmap->stored_clip_gc;
932 GC drawing_gc = src_bitmap->stored_clip_gc;
933 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
934 int src_x = graphic_info[graphic].src_x;
935 int src_y = graphic_info[graphic].src_y;
936 int offset_x = graphic_info[graphic].offset_x;
937 int offset_y = graphic_info[graphic].offset_y;
939 src_x += frame * offset_x;
940 src_y += frame * offset_y;
944 SetClipOrigin(src_bitmap, drawing_gc, dest_x - src_x, dest_y - src_y);
945 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX, TILEY, dest_x, dest_y);
948 void DrawMiniGraphic(int x, int y, int graphic)
950 DrawMiniGraphicExt(drawto, SX + x * MINI_TILEX,SY + y * MINI_TILEY, graphic);
951 MarkTileDirty(x / 2, y / 2);
954 void getMiniGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
956 struct GraphicInfo *g = &graphic_info[graphic];
958 int mini_starty = g->bitmap->height * 2 / 3;
961 *x = mini_startx + g->src_x / 2;
962 *y = mini_starty + g->src_y / 2;
965 void DrawMiniGraphicExt(DrawBuffer *d, int x, int y, int graphic)
970 getMiniGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
971 BlitBitmap(src_bitmap, d, src_x, src_y, MINI_TILEX, MINI_TILEY, x, y);
974 void DrawGraphicShifted(int x,int y, int dx,int dy, int graphic, int frame,
975 int cut_mode, int mask_mode)
980 int width = TILEX, height = TILEY;
986 DrawGraphic(x, y, graphic, frame);
990 if (dx || dy) /* shifted graphic */
992 if (x < BX1) /* object enters playfield from the left */
999 else if (x > BX2) /* object enters playfield from the right */
1005 else if (x==BX1 && dx < 0) /* object leaves playfield to the left */
1011 else if (x==BX2 && dx > 0) /* object leaves playfield to the right */
1013 else if (dx) /* general horizontal movement */
1014 MarkTileDirty(x + SIGN(dx), y);
1016 if (y < BY1) /* object enters playfield from the top */
1018 if (cut_mode==CUT_BELOW) /* object completely above top border */
1026 else if (y > BY2) /* object enters playfield from the bottom */
1032 else if (y==BY1 && dy < 0) /* object leaves playfield to the top */
1038 else if (dy > 0 && cut_mode == CUT_ABOVE)
1040 if (y == BY2) /* object completely above bottom border */
1046 MarkTileDirty(x, y + 1);
1047 } /* object leaves playfield to the bottom */
1048 else if (dy > 0 && (y == BY2 || cut_mode == CUT_BELOW))
1050 else if (dy) /* general vertical movement */
1051 MarkTileDirty(x, y + SIGN(dy));
1055 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1057 src_bitmap = graphic_info[graphic].bitmap;
1058 src_x = graphic_info[graphic].src_x;
1059 src_y = graphic_info[graphic].src_y;
1060 offset_x = graphic_info[graphic].offset_x;
1061 offset_y = graphic_info[graphic].offset_y;
1063 src_x += frame * offset_x;
1064 src_y += frame * offset_y;
1067 drawing_gc = src_bitmap->stored_clip_gc;
1072 dest_x = FX + x * TILEX + dx;
1073 dest_y = FY + y * TILEY + dy;
1076 if (!IN_SCR_FIELD(x,y))
1078 printf("DrawGraphicShifted(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
1079 printf("DrawGraphicShifted(): This should never happen!\n");
1084 if (mask_mode == USE_MASKING)
1086 SetClipOrigin(src_bitmap, drawing_gc, dest_x - src_x, dest_y - src_y);
1087 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1091 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1097 void DrawGraphicShiftedThruMask(int x, int y, int dx, int dy, int graphic,
1098 int frame, int cut_mode)
1100 DrawGraphicShifted(x,y, dx,dy, graphic, frame, cut_mode, USE_MASKING);
1103 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
1104 int cut_mode, int mask_mode)
1106 int lx = LEVELX(x), ly = LEVELY(y);
1110 if (IN_LEV_FIELD(lx, ly))
1112 SetRandomAnimationValue(lx, ly);
1114 graphic = el_act_dir2img(element, GfxAction[lx][ly], MovDir[lx][ly]);
1115 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1117 else /* border element */
1119 graphic = el2img(element);
1120 frame = getGraphicAnimationFrame(graphic, -1);
1123 if (element == EL_EXPANDABLE_WALL)
1125 boolean left_stopped = FALSE, right_stopped = FALSE;
1127 if (!IN_LEV_FIELD(lx - 1, ly) || IS_WALL(Feld[lx - 1][ly]))
1128 left_stopped = TRUE;
1129 if (!IN_LEV_FIELD(lx + 1, ly) || IS_WALL(Feld[lx + 1][ly]))
1130 right_stopped = TRUE;
1132 if (left_stopped && right_stopped)
1134 else if (left_stopped)
1136 graphic = IMG_EXPANDABLE_WALL_GROWING_RIGHT;
1137 frame = graphic_info[graphic].anim_frames - 1;
1139 else if (right_stopped)
1141 graphic = IMG_EXPANDABLE_WALL_GROWING_LEFT;
1142 frame = graphic_info[graphic].anim_frames - 1;
1147 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, mask_mode);
1148 else if (mask_mode == USE_MASKING)
1149 DrawGraphicThruMask(x, y, graphic, frame);
1151 DrawGraphic(x, y, graphic, frame);
1154 void DrawLevelElementExt(int x, int y, int dx, int dy, int element,
1155 int cut_mode, int mask_mode)
1157 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1158 DrawScreenElementExt(SCREENX(x), SCREENY(y), dx, dy, element,
1159 cut_mode, mask_mode);
1162 void DrawScreenElementShifted(int x, int y, int dx, int dy, int element,
1165 DrawScreenElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1168 void DrawLevelElementShifted(int x, int y, int dx, int dy, int element,
1171 DrawLevelElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1174 void DrawLevelElementThruMask(int x, int y, int element)
1176 DrawLevelElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1179 void DrawLevelFieldThruMask(int x, int y)
1181 DrawLevelElementExt(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
1184 static void DrawLevelFieldCrumbledSandExt(int x, int y, int graphic, int frame)
1188 int sx = SCREENX(x), sy = SCREENY(y);
1190 int width, height, cx, cy, i;
1191 int snip = TILEX / 8; /* number of border pixels from "crumbled graphic" */
1192 static int xy[4][2] =
1200 if (!IN_LEV_FIELD(x, y))
1203 element = (GfxElement[x][y] != EL_UNDEFINED ? GfxElement[x][y] : Feld[x][y]);
1205 /* crumble field itself */
1206 if (CAN_BE_CRUMBLED(element) && !IS_MOVING(x, y))
1208 if (!IN_SCR_FIELD(sx, sy))
1211 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1215 int xx = x + xy[i][0];
1216 int yy = y + xy[i][1];
1218 element = (IN_LEV_FIELD(xx, yy) ? Feld[xx][yy] : BorderElement);
1220 /* check if neighbour field is of same type */
1221 if (CAN_BE_CRUMBLED(element) && !IS_MOVING(xx, yy))
1224 if (i == 1 || i == 2)
1228 cx = (i == 2 ? TILEX - snip : 0);
1236 cy = (i == 3 ? TILEY - snip : 0);
1239 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1240 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
1243 MarkTileDirty(sx, sy);
1245 else /* crumble neighbour fields */
1247 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1251 int xx = x + xy[i][0];
1252 int yy = y + xy[i][1];
1253 int sxx = sx + xy[i][0];
1254 int syy = sy + xy[i][1];
1256 if (!IN_LEV_FIELD(xx, yy) ||
1257 !IN_SCR_FIELD(sxx, syy) ||
1258 !CAN_BE_CRUMBLED(Feld[xx][yy]) ||
1262 if (i == 1 || i == 2)
1266 cx = (i == 1 ? TILEX - snip : 0);
1274 cy = (i==0 ? TILEY-snip : 0);
1277 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1278 width, height, FX + sxx * TILEX + cx, FY + syy * TILEY + cy);
1280 MarkTileDirty(sxx, syy);
1285 void DrawLevelFieldCrumbledSand(int x, int y)
1287 DrawLevelFieldCrumbledSandExt(x, y, IMG_SAND_CRUMBLED, 0);
1290 void DrawLevelFieldCrumbledSandDigging(int x, int y, int direction,
1293 int graphic1 = el_act_dir2img(EL_SAND, ACTION_DIGGING, direction);
1294 int graphic2 = el_act_dir2img(EL_SAND_CRUMBLED, ACTION_DIGGING, direction);
1295 int frame1 = getGraphicAnimationFrame(graphic1, step_frame);
1296 int frame2 = getGraphicAnimationFrame(graphic2, step_frame);
1297 int sx = SCREENX(x), sy = SCREENY(y);
1299 DrawGraphic(sx, sy, graphic1, frame1);
1300 DrawLevelFieldCrumbledSandExt(x, y, graphic2, frame2);
1303 void DrawLevelFieldCrumbledSandNeighbours(int x, int y)
1305 int sx = SCREENX(x), sy = SCREENY(y);
1306 static int xy[4][2] =
1317 int xx = x + xy[i][0];
1318 int yy = y + xy[i][1];
1319 int sxx = sx + xy[i][0];
1320 int syy = sy + xy[i][1];
1322 if (!IN_LEV_FIELD(xx, yy) ||
1323 !IN_SCR_FIELD(sxx, syy) ||
1324 !CAN_BE_CRUMBLED(Feld[xx][yy]) ||
1328 DrawLevelField(xx, yy);
1332 static int getBorderElement(int x, int y)
1336 { EL_STEELWALL_TOPLEFT, EL_INVISIBLE_STEELWALL_TOPLEFT },
1337 { EL_STEELWALL_TOPRIGHT, EL_INVISIBLE_STEELWALL_TOPRIGHT },
1338 { EL_STEELWALL_BOTTOMLEFT, EL_INVISIBLE_STEELWALL_BOTTOMLEFT },
1339 { EL_STEELWALL_BOTTOMRIGHT, EL_INVISIBLE_STEELWALL_BOTTOMRIGHT },
1340 { EL_STEELWALL_VERTICAL, EL_INVISIBLE_STEELWALL_VERTICAL },
1341 { EL_STEELWALL_HORIZONTAL, EL_INVISIBLE_STEELWALL_HORIZONTAL },
1342 { EL_STEELWALL, EL_INVISIBLE_STEELWALL }
1344 int steel_type = (BorderElement == EL_STEELWALL ? 0 : 1);
1345 int steel_position = (x == -1 && y == -1 ? 0 :
1346 x == lev_fieldx && y == -1 ? 1 :
1347 x == -1 && y == lev_fieldy ? 2 :
1348 x == lev_fieldx && y == lev_fieldy ? 3 :
1349 x == -1 || x == lev_fieldx ? 4 :
1350 y == -1 || y == lev_fieldy ? 5 : 6);
1352 return border[steel_position][steel_type];
1355 void DrawScreenElement(int x, int y, int element)
1357 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
1358 DrawLevelFieldCrumbledSand(LEVELX(x), LEVELY(y));
1361 void DrawLevelElement(int x, int y, int element)
1363 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1364 DrawScreenElement(SCREENX(x), SCREENY(y), element);
1367 void DrawScreenField(int x, int y)
1369 int lx = LEVELX(x), ly = LEVELY(y);
1370 int element, content;
1372 if (!IN_LEV_FIELD(lx, ly))
1374 if (lx < -1 || lx > lev_fieldx || ly < -1 || ly > lev_fieldy)
1377 element = getBorderElement(lx, ly);
1379 DrawScreenElement(x, y, element);
1383 element = Feld[lx][ly];
1384 content = Store[lx][ly];
1386 if (IS_MOVING(lx, ly))
1388 int horiz_move = (MovDir[lx][ly] == MV_LEFT || MovDir[lx][ly] == MV_RIGHT);
1389 boolean cut_mode = NO_CUTTING;
1391 if (element == EL_QUICKSAND_EMPTYING ||
1392 element == EL_MAGIC_WALL_EMPTYING ||
1393 element == EL_BD_MAGIC_WALL_EMPTYING ||
1394 element == EL_AMOEBA_DROPPING)
1395 cut_mode = CUT_ABOVE;
1396 else if (element == EL_QUICKSAND_FILLING ||
1397 element == EL_MAGIC_WALL_FILLING ||
1398 element == EL_BD_MAGIC_WALL_FILLING)
1399 cut_mode = CUT_BELOW;
1401 if (cut_mode == CUT_ABOVE)
1402 DrawScreenElementShifted(x, y, 0, 0, element, NO_CUTTING);
1404 DrawScreenElement(x, y, EL_EMPTY);
1407 DrawScreenElementShifted(x, y, MovPos[lx][ly], 0, element, NO_CUTTING);
1408 else if (cut_mode == NO_CUTTING)
1409 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], element, cut_mode);
1411 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], content, cut_mode);
1413 if (content == EL_ACID)
1414 DrawLevelElementThruMask(lx, ly + 1, EL_ACID);
1416 else if (IS_BLOCKED(lx, ly))
1421 boolean cut_mode = NO_CUTTING;
1422 int element_old, content_old;
1424 Blocked2Moving(lx, ly, &oldx, &oldy);
1427 horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
1428 MovDir[oldx][oldy] == MV_RIGHT);
1430 element_old = Feld[oldx][oldy];
1431 content_old = Store[oldx][oldy];
1433 if (element_old == EL_QUICKSAND_EMPTYING ||
1434 element_old == EL_MAGIC_WALL_EMPTYING ||
1435 element_old == EL_BD_MAGIC_WALL_EMPTYING ||
1436 element_old == EL_AMOEBA_DROPPING)
1437 cut_mode = CUT_ABOVE;
1439 DrawScreenElement(x, y, EL_EMPTY);
1442 DrawScreenElementShifted(sx, sy, MovPos[oldx][oldy], 0, element_old,
1444 else if (cut_mode == NO_CUTTING)
1445 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], element_old,
1448 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], content_old,
1451 else if (IS_DRAWABLE(element))
1452 DrawScreenElement(x, y, element);
1454 DrawScreenElement(x, y, EL_EMPTY);
1457 void DrawLevelField(int x, int y)
1459 if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1460 DrawScreenField(SCREENX(x), SCREENY(y));
1461 else if (IS_MOVING(x, y))
1465 Moving2Blocked(x, y, &newx, &newy);
1466 if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
1467 DrawScreenField(SCREENX(newx), SCREENY(newy));
1469 else if (IS_BLOCKED(x, y))
1473 Blocked2Moving(x, y, &oldx, &oldy);
1474 if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
1475 DrawScreenField(SCREENX(oldx), SCREENY(oldy));
1479 void DrawMiniElement(int x, int y, int element)
1483 graphic = el2edimg(element);
1484 DrawMiniGraphic(x, y, graphic);
1487 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
1489 int x = sx + scroll_x, y = sy + scroll_y;
1491 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
1492 DrawMiniElement(sx, sy, EL_EMPTY);
1493 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
1494 DrawMiniElement(sx, sy, Feld[x][y]);
1496 DrawMiniGraphic(sx, sy, el2edimg(getBorderElement(x, y)));
1499 void getMicroGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
1501 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
1502 int mini_startx = src_bitmap->width * 3 / 4;
1503 int mini_starty = src_bitmap->height * 2 / 3;
1504 int src_x = mini_startx + graphic_info[graphic].src_x / 8;
1505 int src_y = mini_starty + graphic_info[graphic].src_y / 8;
1507 *bitmap = src_bitmap;
1512 void DrawMicroElement(int xpos, int ypos, int element)
1516 int graphic = el2preimg(element);
1518 getMicroGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
1519 BlitBitmap(src_bitmap, drawto, src_x, src_y, MICRO_TILEX, MICRO_TILEY,
1527 SetDrawBackgroundMask(REDRAW_NONE);
1530 for(x=BX1; x<=BX2; x++)
1531 for(y=BY1; y<=BY2; y++)
1532 DrawScreenField(x, y);
1534 redraw_mask |= REDRAW_FIELD;
1537 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
1541 for(x=0; x<size_x; x++)
1542 for(y=0; y<size_y; y++)
1543 DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
1545 redraw_mask |= REDRAW_FIELD;
1548 static void DrawMicroLevelExt(int xpos, int ypos, int from_x, int from_y)
1552 DrawBackground(xpos, ypos, MICROLEV_XSIZE, MICROLEV_YSIZE);
1554 if (lev_fieldx < STD_LEV_FIELDX)
1555 xpos += (STD_LEV_FIELDX - lev_fieldx) / 2 * MICRO_TILEX;
1556 if (lev_fieldy < STD_LEV_FIELDY)
1557 ypos += (STD_LEV_FIELDY - lev_fieldy) / 2 * MICRO_TILEY;
1559 xpos += MICRO_TILEX;
1560 ypos += MICRO_TILEY;
1562 for(x=-1; x<=STD_LEV_FIELDX; x++)
1564 for(y=-1; y<=STD_LEV_FIELDY; y++)
1566 int lx = from_x + x, ly = from_y + y;
1568 if (lx >= 0 && lx < lev_fieldx && ly >= 0 && ly < lev_fieldy)
1569 DrawMicroElement(xpos + x * MICRO_TILEX, ypos + y * MICRO_TILEY,
1570 level.field[lx][ly]);
1571 else if (lx >= -1 && lx < lev_fieldx+1 && ly >= -1 && ly < lev_fieldy+1
1572 && BorderElement != EL_EMPTY)
1573 DrawMicroElement(xpos + x * MICRO_TILEX, ypos + y * MICRO_TILEY,
1574 getBorderElement(lx, ly));
1578 redraw_mask |= REDRAW_MICROLEVEL;
1581 #define MICROLABEL_EMPTY 0
1582 #define MICROLABEL_LEVEL_NAME 1
1583 #define MICROLABEL_CREATED_BY 2
1584 #define MICROLABEL_LEVEL_AUTHOR 3
1585 #define MICROLABEL_IMPORTED_FROM 4
1586 #define MICROLABEL_LEVEL_IMPORT_INFO 5
1588 static void DrawMicroLevelLabelExt(int mode)
1590 char label_text[MAX_OUTPUT_LINESIZE + 1];
1591 int max_len_label_text;
1592 int font_nr = FONT_TEXT_2;
1594 if (mode == MICROLABEL_CREATED_BY || mode == MICROLABEL_IMPORTED_FROM)
1595 font_nr = FONT_TEXT_3;
1597 max_len_label_text = SXSIZE / getFontWidth(font_nr);
1599 DrawBackground(SX, MICROLABEL_YPOS, SXSIZE, getFontHeight(font_nr));
1601 strncpy(label_text, (mode == MICROLABEL_LEVEL_NAME ? level.name :
1602 mode == MICROLABEL_CREATED_BY ? "created by" :
1603 mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
1604 mode == MICROLABEL_IMPORTED_FROM ? "imported from" :
1605 mode == MICROLABEL_LEVEL_IMPORT_INFO ?
1606 leveldir_current->imported_from : ""),
1607 max_len_label_text);
1608 label_text[max_len_label_text] = '\0';
1610 if (strlen(label_text) > 0)
1612 int text_width = strlen(label_text) * getFontWidth(font_nr);
1613 int lxpos = SX + (SXSIZE - text_width) / 2;
1614 int lypos = MICROLABEL_YPOS;
1616 DrawText(lxpos, lypos, label_text, font_nr);
1619 redraw_mask |= REDRAW_MICROLEVEL;
1622 void DrawMicroLevel(int xpos, int ypos, boolean restart)
1624 static unsigned long scroll_delay = 0;
1625 static unsigned long label_delay = 0;
1626 static int from_x, from_y, scroll_direction;
1627 static int label_state, label_counter;
1628 int last_game_status = game_status; /* save current game status */
1630 /* force PREVIEW font on preview level */
1631 game_status = GAME_MODE_PSEUDO_PREVIEW;
1635 from_x = from_y = 0;
1636 scroll_direction = MV_RIGHT;
1640 DrawMicroLevelExt(xpos, ypos, from_x, from_y);
1641 DrawMicroLevelLabelExt(label_state);
1643 /* initialize delay counters */
1644 DelayReached(&scroll_delay, 0);
1645 DelayReached(&label_delay, 0);
1647 if (leveldir_current->name)
1649 int len = strlen(leveldir_current->name);
1650 int lxpos = SX + (SXSIZE - len * getFontWidth(FONT_TEXT_1)) / 2;
1651 int lypos = SY + 352;
1653 DrawText(lxpos, lypos, leveldir_current->name, FONT_TEXT_1);
1656 game_status = last_game_status; /* restore current game status */
1661 /* scroll micro level, if needed */
1662 if ((lev_fieldx > STD_LEV_FIELDX || lev_fieldy > STD_LEV_FIELDY) &&
1663 DelayReached(&scroll_delay, MICROLEVEL_SCROLL_DELAY))
1665 switch (scroll_direction)
1671 scroll_direction = MV_UP;
1675 if (from_x < lev_fieldx - STD_LEV_FIELDX)
1678 scroll_direction = MV_DOWN;
1685 scroll_direction = MV_RIGHT;
1689 if (from_y < lev_fieldy - STD_LEV_FIELDY)
1692 scroll_direction = MV_LEFT;
1699 DrawMicroLevelExt(xpos, ypos, from_x, from_y);
1702 /* redraw micro level label, if needed */
1703 if (strcmp(level.name, NAMELESS_LEVEL_NAME) != 0 &&
1704 strcmp(level.author, ANONYMOUS_NAME) != 0 &&
1705 strcmp(level.author, leveldir_current->name) != 0 &&
1706 DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
1708 int max_label_counter = 23;
1710 if (leveldir_current->imported_from != NULL)
1711 max_label_counter += 14;
1713 label_counter = (label_counter + 1) % max_label_counter;
1714 label_state = (label_counter >= 0 && label_counter <= 7 ?
1715 MICROLABEL_LEVEL_NAME :
1716 label_counter >= 9 && label_counter <= 12 ?
1717 MICROLABEL_CREATED_BY :
1718 label_counter >= 14 && label_counter <= 21 ?
1719 MICROLABEL_LEVEL_AUTHOR :
1720 label_counter >= 23 && label_counter <= 26 ?
1721 MICROLABEL_IMPORTED_FROM :
1722 label_counter >= 28 && label_counter <= 35 ?
1723 MICROLABEL_LEVEL_IMPORT_INFO : MICROLABEL_EMPTY);
1724 DrawMicroLevelLabelExt(label_state);
1727 game_status = last_game_status; /* restore current game status */
1730 int REQ_in_range(int x, int y)
1732 if (y > DY+249 && y < DY+278)
1734 if (x > DX+1 && x < DX+48)
1736 else if (x > DX+51 && x < DX+98)
1742 #define MAX_REQUEST_LINES 13
1743 #define MAX_REQUEST_LINE_LEN 7
1745 boolean Request(char *text, unsigned int req_state)
1747 int mx, my, ty, result = -1;
1748 unsigned int old_door_state;
1749 int last_game_status = game_status; /* save current game status */
1751 #if defined(PLATFORM_UNIX)
1752 /* pause network game while waiting for request to answer */
1753 if (options.network &&
1754 game_status == GAME_MODE_PLAYING &&
1755 req_state & REQUEST_WAIT_FOR)
1756 SendToServer_PausePlaying();
1759 old_door_state = GetDoorState();
1761 /* simulate releasing mouse button over last gadget, if still pressed */
1763 HandleGadgets(-1, -1, 0);
1767 CloseDoor(DOOR_CLOSE_1);
1769 /* save old door content */
1770 BlitBitmap(bitmap_db_door, bitmap_db_door,
1771 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
1772 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
1774 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
1776 /* clear door drawing field */
1777 DrawBackground(DX, DY, DXSIZE, DYSIZE);
1779 /* force DOOR font on preview level */
1780 game_status = GAME_MODE_PSEUDO_DOOR;
1782 /* write text for request */
1783 for(ty=0; ty < MAX_REQUEST_LINES; ty++)
1785 char text_line[MAX_REQUEST_LINE_LEN + 1];
1791 for(tl=0,tx=0; tx < MAX_REQUEST_LINE_LEN; tl++,tx++)
1794 if (!tc || tc == ' ')
1805 strncpy(text_line, text, tl);
1808 DrawText(DX + (DXSIZE - tl * getFontWidth(FONT_TEXT_2)) / 2,
1809 DY + 8 + ty * (getFontHeight(FONT_TEXT_2) + 2),
1810 text_line, FONT_TEXT_2);
1812 text += tl + (tc == ' ' ? 1 : 0);
1815 game_status = last_game_status; /* restore current game status */
1817 if (req_state & REQ_ASK)
1819 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
1820 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
1822 else if (req_state & REQ_CONFIRM)
1824 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
1826 else if (req_state & REQ_PLAYER)
1828 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
1829 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
1830 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
1831 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
1834 /* copy request gadgets to door backbuffer */
1835 BlitBitmap(drawto, bitmap_db_door,
1836 DX, DY, DXSIZE, DYSIZE,
1837 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
1839 OpenDoor(DOOR_OPEN_1);
1845 if (!(req_state & REQUEST_WAIT_FOR))
1847 SetDrawBackgroundMask(REDRAW_FIELD);
1852 if (game_status != GAME_MODE_MAIN)
1855 button_status = MB_RELEASED;
1857 request_gadget_id = -1;
1859 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
1871 case EVENT_BUTTONPRESS:
1872 case EVENT_BUTTONRELEASE:
1873 case EVENT_MOTIONNOTIFY:
1875 if (event.type == EVENT_MOTIONNOTIFY)
1877 if (!PointerInWindow(window))
1878 continue; /* window and pointer are on different screens */
1883 motion_status = TRUE;
1884 mx = ((MotionEvent *) &event)->x;
1885 my = ((MotionEvent *) &event)->y;
1889 motion_status = FALSE;
1890 mx = ((ButtonEvent *) &event)->x;
1891 my = ((ButtonEvent *) &event)->y;
1892 if (event.type == EVENT_BUTTONPRESS)
1893 button_status = ((ButtonEvent *) &event)->button;
1895 button_status = MB_RELEASED;
1898 /* this sets 'request_gadget_id' */
1899 HandleGadgets(mx, my, button_status);
1901 switch(request_gadget_id)
1903 case TOOL_CTRL_ID_YES:
1906 case TOOL_CTRL_ID_NO:
1909 case TOOL_CTRL_ID_CONFIRM:
1910 result = TRUE | FALSE;
1913 case TOOL_CTRL_ID_PLAYER_1:
1916 case TOOL_CTRL_ID_PLAYER_2:
1919 case TOOL_CTRL_ID_PLAYER_3:
1922 case TOOL_CTRL_ID_PLAYER_4:
1933 case EVENT_KEYPRESS:
1934 switch(GetEventKey((KeyEvent *)&event, TRUE))
1947 if (req_state & REQ_PLAYER)
1951 case EVENT_KEYRELEASE:
1952 ClearPlayerAction();
1956 HandleOtherEvents(&event);
1960 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
1962 int joy = AnyJoystick();
1964 if (joy & JOY_BUTTON_1)
1966 else if (joy & JOY_BUTTON_2)
1972 /* don't eat all CPU time */
1976 if (game_status != GAME_MODE_MAIN)
1981 if (!(req_state & REQ_STAY_OPEN))
1983 CloseDoor(DOOR_CLOSE_1);
1985 if (!(req_state & REQ_STAY_CLOSED) && (old_door_state & DOOR_OPEN_1))
1987 BlitBitmap(bitmap_db_door, bitmap_db_door,
1988 DOOR_GFX_PAGEX2,DOOR_GFX_PAGEY1, DXSIZE,DYSIZE,
1989 DOOR_GFX_PAGEX1,DOOR_GFX_PAGEY1);
1990 OpenDoor(DOOR_OPEN_1);
1996 SetDrawBackgroundMask(REDRAW_FIELD);
1998 #if defined(PLATFORM_UNIX)
1999 /* continue network game after request */
2000 if (options.network &&
2001 game_status == GAME_MODE_PLAYING &&
2002 req_state & REQUEST_WAIT_FOR)
2003 SendToServer_ContinuePlaying();
2009 unsigned int OpenDoor(unsigned int door_state)
2011 unsigned int new_door_state;
2013 if (door_state & DOOR_COPY_BACK)
2015 BlitBitmap(bitmap_db_door, bitmap_db_door,
2016 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE + VYSIZE,
2017 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2018 door_state &= ~DOOR_COPY_BACK;
2021 new_door_state = MoveDoor(door_state);
2023 return(new_door_state);
2026 unsigned int CloseDoor(unsigned int door_state)
2028 unsigned int new_door_state;
2030 BlitBitmap(backbuffer, bitmap_db_door,
2031 DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2032 BlitBitmap(backbuffer, bitmap_db_door,
2033 VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
2035 new_door_state = MoveDoor(door_state);
2037 return(new_door_state);
2040 unsigned int GetDoorState()
2042 return MoveDoor(DOOR_GET_STATE);
2045 unsigned int SetDoorState(unsigned int door_state)
2047 return MoveDoor(door_state | DOOR_SET_STATE);
2050 unsigned int MoveDoor(unsigned int door_state)
2052 static int door1 = DOOR_OPEN_1;
2053 static int door2 = DOOR_CLOSE_2;
2054 static unsigned long door_delay = 0;
2055 int x, start, stepsize = door.step_offset;
2056 unsigned long door_delay_value = door.step_delay;
2058 if (door_state == DOOR_GET_STATE)
2059 return(door1 | door2);
2061 if (door_state & DOOR_SET_STATE)
2063 if (door_state & DOOR_ACTION_1)
2064 door1 = door_state & DOOR_ACTION_1;
2065 if (door_state & DOOR_ACTION_2)
2066 door2 = door_state & DOOR_ACTION_2;
2068 return(door1 | door2);
2071 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
2072 door_state &= ~DOOR_OPEN_1;
2073 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
2074 door_state &= ~DOOR_CLOSE_1;
2075 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
2076 door_state &= ~DOOR_OPEN_2;
2077 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
2078 door_state &= ~DOOR_CLOSE_2;
2080 if (setup.quick_doors)
2083 door_delay_value = 0;
2085 StopSound(SND_DOOR_OPENING);
2086 StopSound(SND_DOOR_CLOSING);
2089 if (global.autoplay_leveldir)
2091 door_state |= DOOR_NO_DELAY;
2092 door_state &= ~DOOR_CLOSE_ALL;
2095 if (door_state & DOOR_ACTION)
2097 if (!(door_state & DOOR_NO_DELAY))
2099 /* opening door sound has priority over simultaneously closing door */
2100 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
2101 PlaySoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
2102 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
2103 PlaySoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
2106 start = ((door_state & DOOR_NO_DELAY) ? DXSIZE : 0);
2108 for(x=start; x<=DXSIZE; x+=stepsize)
2110 Bitmap *bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
2111 GC gc = bitmap->stored_clip_gc;
2113 if (!(door_state & DOOR_NO_DELAY))
2114 WaitUntilDelayReached(&door_delay, door_delay_value);
2116 if (door_state & DOOR_ACTION_1)
2118 int i = (door_state & DOOR_OPEN_1 ? DXSIZE-x : x);
2119 int j = (DXSIZE - i) / 3;
2121 BlitBitmap(bitmap_db_door, drawto,
2122 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + i/2,
2123 DXSIZE,DYSIZE - i/2, DX, DY);
2125 ClearRectangle(drawto, DX, DY + DYSIZE - i/2, DXSIZE,i/2);
2127 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2128 BlitBitmapMasked(bitmap, drawto,
2129 DXSIZE, DOOR_GFX_PAGEY1, i, 77,
2130 DX + DXSIZE - i, DY + j);
2131 BlitBitmapMasked(bitmap, drawto,
2132 DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63,
2133 DX + DXSIZE - i, DY + 140 + j);
2134 SetClipOrigin(bitmap, gc, DX - DXSIZE + i, DY - (DOOR_GFX_PAGEY1 + j));
2135 BlitBitmapMasked(bitmap, drawto,
2136 DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j,
2138 BlitBitmapMasked(bitmap, drawto,
2139 DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63,
2142 BlitBitmapMasked(bitmap, drawto,
2143 DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
2145 BlitBitmapMasked(bitmap, drawto,
2146 DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
2148 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2149 BlitBitmapMasked(bitmap, drawto,
2150 DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
2151 DX + DXSIZE - i, DY + 77 + j);
2152 BlitBitmapMasked(bitmap, drawto,
2153 DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
2154 DX + DXSIZE - i, DY + 203 + j);
2156 redraw_mask |= REDRAW_DOOR_1;
2159 if (door_state & DOOR_ACTION_2)
2161 int i = (door_state & DOOR_OPEN_2 ? VXSIZE - x : x);
2162 int j = (VXSIZE - i) / 3;
2164 BlitBitmap(bitmap_db_door, drawto,
2165 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + i/2,
2166 VXSIZE, VYSIZE - i/2, VX, VY);
2168 ClearRectangle(drawto, VX, VY + VYSIZE-i/2, VXSIZE, i/2);
2170 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2171 BlitBitmapMasked(bitmap, drawto,
2172 VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2,
2173 VX + VXSIZE-i, VY+j);
2174 SetClipOrigin(bitmap, gc,
2175 VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
2176 BlitBitmapMasked(bitmap, drawto,
2177 VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j,
2180 BlitBitmapMasked(bitmap, drawto,
2181 VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2,
2182 i, VYSIZE / 2, VX, VY + VYSIZE / 2 - j);
2183 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2184 BlitBitmapMasked(bitmap, drawto,
2185 VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2,
2187 VX + VXSIZE - i, VY + VYSIZE / 2 + j);
2189 redraw_mask |= REDRAW_DOOR_2;
2194 if (game_status == GAME_MODE_MAIN)
2199 if (setup.quick_doors)
2201 StopSound(SND_DOOR_OPENING);
2202 StopSound(SND_DOOR_CLOSING);
2205 if (door_state & DOOR_ACTION_1)
2206 door1 = door_state & DOOR_ACTION_1;
2207 if (door_state & DOOR_ACTION_2)
2208 door2 = door_state & DOOR_ACTION_2;
2210 return (door1 | door2);
2213 void DrawSpecialEditorDoor()
2215 /* draw bigger toolbox window */
2216 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
2217 DOOR_GFX_PAGEX7, 0, EXSIZE + 8, 8,
2219 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
2220 EX - 4, VY - 4, EXSIZE + 8, EYSIZE - VYSIZE + 4,
2223 redraw_mask |= REDRAW_ALL;
2226 void UndrawSpecialEditorDoor()
2228 /* draw normal tape recorder window */
2229 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
2230 EX - 4, EY - 12, EXSIZE + 8, EYSIZE - VYSIZE + 12,
2233 redraw_mask |= REDRAW_ALL;
2237 /* ---------- new tool button stuff ---------------------------------------- */
2239 /* graphic position values for tool buttons */
2240 #define TOOL_BUTTON_YES_XPOS 2
2241 #define TOOL_BUTTON_YES_YPOS 250
2242 #define TOOL_BUTTON_YES_GFX_YPOS 0
2243 #define TOOL_BUTTON_YES_XSIZE 46
2244 #define TOOL_BUTTON_YES_YSIZE 28
2245 #define TOOL_BUTTON_NO_XPOS 52
2246 #define TOOL_BUTTON_NO_YPOS TOOL_BUTTON_YES_YPOS
2247 #define TOOL_BUTTON_NO_GFX_YPOS TOOL_BUTTON_YES_GFX_YPOS
2248 #define TOOL_BUTTON_NO_XSIZE TOOL_BUTTON_YES_XSIZE
2249 #define TOOL_BUTTON_NO_YSIZE TOOL_BUTTON_YES_YSIZE
2250 #define TOOL_BUTTON_CONFIRM_XPOS TOOL_BUTTON_YES_XPOS
2251 #define TOOL_BUTTON_CONFIRM_YPOS TOOL_BUTTON_YES_YPOS
2252 #define TOOL_BUTTON_CONFIRM_GFX_YPOS 30
2253 #define TOOL_BUTTON_CONFIRM_XSIZE 96
2254 #define TOOL_BUTTON_CONFIRM_YSIZE TOOL_BUTTON_YES_YSIZE
2255 #define TOOL_BUTTON_PLAYER_XSIZE 30
2256 #define TOOL_BUTTON_PLAYER_YSIZE 30
2257 #define TOOL_BUTTON_PLAYER_GFX_XPOS 5
2258 #define TOOL_BUTTON_PLAYER_GFX_YPOS 185
2259 #define TOOL_BUTTON_PLAYER_XPOS (5 + TOOL_BUTTON_PLAYER_XSIZE / 2)
2260 #define TOOL_BUTTON_PLAYER_YPOS (215 - TOOL_BUTTON_PLAYER_YSIZE / 2)
2261 #define TOOL_BUTTON_PLAYER1_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2262 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2263 #define TOOL_BUTTON_PLAYER2_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2264 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2265 #define TOOL_BUTTON_PLAYER3_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2266 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2267 #define TOOL_BUTTON_PLAYER4_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2268 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2269 #define TOOL_BUTTON_PLAYER1_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2270 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2271 #define TOOL_BUTTON_PLAYER2_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2272 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2273 #define TOOL_BUTTON_PLAYER3_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2274 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2275 #define TOOL_BUTTON_PLAYER4_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2276 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2285 } toolbutton_info[NUM_TOOL_BUTTONS] =
2288 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_GFX_YPOS,
2289 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_YPOS,
2290 TOOL_BUTTON_YES_XSIZE, TOOL_BUTTON_YES_YSIZE,
2295 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_GFX_YPOS,
2296 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_YPOS,
2297 TOOL_BUTTON_NO_XSIZE, TOOL_BUTTON_NO_YSIZE,
2302 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_GFX_YPOS,
2303 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_YPOS,
2304 TOOL_BUTTON_CONFIRM_XSIZE, TOOL_BUTTON_CONFIRM_YSIZE,
2305 TOOL_CTRL_ID_CONFIRM,
2309 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2310 TOOL_BUTTON_PLAYER1_XPOS, TOOL_BUTTON_PLAYER1_YPOS,
2311 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2312 TOOL_CTRL_ID_PLAYER_1,
2316 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2317 TOOL_BUTTON_PLAYER2_XPOS, TOOL_BUTTON_PLAYER2_YPOS,
2318 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2319 TOOL_CTRL_ID_PLAYER_2,
2323 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2324 TOOL_BUTTON_PLAYER3_XPOS, TOOL_BUTTON_PLAYER3_YPOS,
2325 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2326 TOOL_CTRL_ID_PLAYER_3,
2330 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2331 TOOL_BUTTON_PLAYER4_XPOS, TOOL_BUTTON_PLAYER4_YPOS,
2332 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2333 TOOL_CTRL_ID_PLAYER_4,
2338 void CreateToolButtons()
2342 for (i=0; i<NUM_TOOL_BUTTONS; i++)
2344 Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
2345 Bitmap *deco_bitmap = None;
2346 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
2347 struct GadgetInfo *gi;
2348 unsigned long event_mask;
2349 int gd_xoffset, gd_yoffset;
2350 int gd_x1, gd_x2, gd_y;
2353 event_mask = GD_EVENT_RELEASED;
2355 gd_xoffset = toolbutton_info[i].xpos;
2356 gd_yoffset = toolbutton_info[i].ypos;
2357 gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
2358 gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
2359 gd_y = DOOR_GFX_PAGEY1 + gd_yoffset;
2361 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
2363 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
2365 getMiniGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr),
2366 &deco_bitmap, &deco_x, &deco_y);
2367 deco_xpos = (toolbutton_info[i].width - MINI_TILEX) / 2;
2368 deco_ypos = (toolbutton_info[i].height - MINI_TILEY) / 2;
2371 gi = CreateGadget(GDI_CUSTOM_ID, id,
2372 GDI_INFO_TEXT, toolbutton_info[i].infotext,
2373 GDI_X, DX + toolbutton_info[i].x,
2374 GDI_Y, DY + toolbutton_info[i].y,
2375 GDI_WIDTH, toolbutton_info[i].width,
2376 GDI_HEIGHT, toolbutton_info[i].height,
2377 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
2378 GDI_STATE, GD_BUTTON_UNPRESSED,
2379 GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
2380 GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
2381 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
2382 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
2383 GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
2384 GDI_DECORATION_SHIFTING, 1, 1,
2385 GDI_EVENT_MASK, event_mask,
2386 GDI_CALLBACK_ACTION, HandleToolButtons,
2390 Error(ERR_EXIT, "cannot create gadget");
2392 tool_gadget[id] = gi;
2396 void FreeToolButtons()
2400 for (i=0; i<NUM_TOOL_BUTTONS; i++)
2401 FreeGadget(tool_gadget[i]);
2404 static void UnmapToolButtons()
2408 for (i=0; i<NUM_TOOL_BUTTONS; i++)
2409 UnmapGadget(tool_gadget[i]);
2412 static void HandleToolButtons(struct GadgetInfo *gi)
2414 request_gadget_id = gi->custom_id;
2417 int get_next_element(int element)
2421 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
2422 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
2423 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
2424 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
2425 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
2426 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
2427 case EL_AMOEBA_DROPPING: return EL_AMOEBA_WET;
2429 default: return element;
2433 int el_act_dir2img(int element, int action, int direction)
2435 element = GFX_ELEMENT(element);
2436 direction = MV_DIR_BIT(direction);
2438 return element_info[element].direction_graphic[action][direction];
2441 int el_act2img(int element, int action)
2443 element = GFX_ELEMENT(element);
2445 return element_info[element].graphic[action];
2448 int el_dir2img(int element, int direction)
2450 element = GFX_ELEMENT(element);
2452 return el_act_dir2img(element, ACTION_DEFAULT, direction);
2455 int el2img(int element)
2457 element = GFX_ELEMENT(element);
2459 return element_info[element].graphic[ACTION_DEFAULT];
2462 int el2edimg(int element)
2464 element = GFX_ELEMENT(element);
2466 return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
2469 int el2preimg(int element)
2471 element = GFX_ELEMENT(element);
2473 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];