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 && Feld[x][y] != EL_EXPLOSION ?
1204 GfxElement[x][y] : Feld[x][y]);
1206 /* crumble field itself */
1207 if (CAN_BE_CRUMBLED(element) && !IS_MOVING(x, y))
1209 if (!IN_SCR_FIELD(sx, sy))
1212 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1216 int xx = x + xy[i][0];
1217 int yy = y + xy[i][1];
1219 element = (IN_LEV_FIELD(xx, yy) ? Feld[xx][yy] : BorderElement);
1221 /* check if neighbour field is of same type */
1222 if (CAN_BE_CRUMBLED(element) && !IS_MOVING(xx, yy))
1226 if (Feld[x][y] == EL_CUSTOM_START + 123)
1227 printf("::: crumble [%d] THE CHAOS ENGINE (%d, %d): %d, %d\n",
1228 i, Feld[x][y], element,
1229 CAN_BE_CRUMBLED(element), IS_MOVING(x, y));
1232 if (i == 1 || i == 2)
1236 cx = (i == 2 ? TILEX - snip : 0);
1244 cy = (i == 3 ? TILEY - snip : 0);
1247 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1248 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
1251 MarkTileDirty(sx, sy);
1253 else /* crumble neighbour fields */
1255 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1259 int xx = x + xy[i][0];
1260 int yy = y + xy[i][1];
1261 int sxx = sx + xy[i][0];
1262 int syy = sy + xy[i][1];
1264 if (!IN_LEV_FIELD(xx, yy) ||
1265 !IN_SCR_FIELD(sxx, syy) ||
1266 !CAN_BE_CRUMBLED(Feld[xx][yy]) ||
1270 if (i == 1 || i == 2)
1274 cx = (i == 1 ? TILEX - snip : 0);
1282 cy = (i==0 ? TILEY-snip : 0);
1285 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1286 width, height, FX + sxx * TILEX + cx, FY + syy * TILEY + cy);
1288 MarkTileDirty(sxx, syy);
1293 void DrawLevelFieldCrumbledSand(int x, int y)
1295 DrawLevelFieldCrumbledSandExt(x, y, IMG_SAND_CRUMBLED, 0);
1298 void DrawLevelFieldCrumbledSandDigging(int x, int y, int direction,
1301 int graphic1 = el_act_dir2img(EL_SAND, ACTION_DIGGING, direction);
1302 int graphic2 = el_act_dir2img(EL_SAND_CRUMBLED, ACTION_DIGGING, direction);
1303 int frame1 = getGraphicAnimationFrame(graphic1, step_frame);
1304 int frame2 = getGraphicAnimationFrame(graphic2, step_frame);
1305 int sx = SCREENX(x), sy = SCREENY(y);
1307 DrawGraphic(sx, sy, graphic1, frame1);
1308 DrawLevelFieldCrumbledSandExt(x, y, graphic2, frame2);
1311 void DrawLevelFieldCrumbledSandNeighbours(int x, int y)
1313 int sx = SCREENX(x), sy = SCREENY(y);
1314 static int xy[4][2] =
1325 int xx = x + xy[i][0];
1326 int yy = y + xy[i][1];
1327 int sxx = sx + xy[i][0];
1328 int syy = sy + xy[i][1];
1330 if (!IN_LEV_FIELD(xx, yy) ||
1331 !IN_SCR_FIELD(sxx, syy) ||
1332 !CAN_BE_CRUMBLED(Feld[xx][yy]) ||
1336 DrawLevelField(xx, yy);
1340 static int getBorderElement(int x, int y)
1344 { EL_STEELWALL_TOPLEFT, EL_INVISIBLE_STEELWALL_TOPLEFT },
1345 { EL_STEELWALL_TOPRIGHT, EL_INVISIBLE_STEELWALL_TOPRIGHT },
1346 { EL_STEELWALL_BOTTOMLEFT, EL_INVISIBLE_STEELWALL_BOTTOMLEFT },
1347 { EL_STEELWALL_BOTTOMRIGHT, EL_INVISIBLE_STEELWALL_BOTTOMRIGHT },
1348 { EL_STEELWALL_VERTICAL, EL_INVISIBLE_STEELWALL_VERTICAL },
1349 { EL_STEELWALL_HORIZONTAL, EL_INVISIBLE_STEELWALL_HORIZONTAL },
1350 { EL_STEELWALL, EL_INVISIBLE_STEELWALL }
1352 int steel_type = (BorderElement == EL_STEELWALL ? 0 : 1);
1353 int steel_position = (x == -1 && y == -1 ? 0 :
1354 x == lev_fieldx && y == -1 ? 1 :
1355 x == -1 && y == lev_fieldy ? 2 :
1356 x == lev_fieldx && y == lev_fieldy ? 3 :
1357 x == -1 || x == lev_fieldx ? 4 :
1358 y == -1 || y == lev_fieldy ? 5 : 6);
1360 return border[steel_position][steel_type];
1363 void DrawScreenElement(int x, int y, int element)
1365 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
1366 DrawLevelFieldCrumbledSand(LEVELX(x), LEVELY(y));
1369 void DrawLevelElement(int x, int y, int element)
1371 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1372 DrawScreenElement(SCREENX(x), SCREENY(y), element);
1375 void DrawScreenField(int x, int y)
1377 int lx = LEVELX(x), ly = LEVELY(y);
1378 int element, content;
1380 if (!IN_LEV_FIELD(lx, ly))
1382 if (lx < -1 || lx > lev_fieldx || ly < -1 || ly > lev_fieldy)
1385 element = getBorderElement(lx, ly);
1387 DrawScreenElement(x, y, element);
1391 element = Feld[lx][ly];
1392 content = Store[lx][ly];
1394 if (IS_MOVING(lx, ly))
1396 int horiz_move = (MovDir[lx][ly] == MV_LEFT || MovDir[lx][ly] == MV_RIGHT);
1397 boolean cut_mode = NO_CUTTING;
1399 if (element == EL_QUICKSAND_EMPTYING ||
1400 element == EL_MAGIC_WALL_EMPTYING ||
1401 element == EL_BD_MAGIC_WALL_EMPTYING ||
1402 element == EL_AMOEBA_DROPPING)
1403 cut_mode = CUT_ABOVE;
1404 else if (element == EL_QUICKSAND_FILLING ||
1405 element == EL_MAGIC_WALL_FILLING ||
1406 element == EL_BD_MAGIC_WALL_FILLING)
1407 cut_mode = CUT_BELOW;
1409 if (cut_mode == CUT_ABOVE)
1410 DrawScreenElementShifted(x, y, 0, 0, element, NO_CUTTING);
1412 DrawScreenElement(x, y, EL_EMPTY);
1415 DrawScreenElementShifted(x, y, MovPos[lx][ly], 0, element, NO_CUTTING);
1416 else if (cut_mode == NO_CUTTING)
1417 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], element, cut_mode);
1419 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], content, cut_mode);
1421 if (content == EL_ACID)
1422 DrawLevelElementThruMask(lx, ly + 1, EL_ACID);
1424 else if (IS_BLOCKED(lx, ly))
1429 boolean cut_mode = NO_CUTTING;
1430 int element_old, content_old;
1432 Blocked2Moving(lx, ly, &oldx, &oldy);
1435 horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
1436 MovDir[oldx][oldy] == MV_RIGHT);
1438 element_old = Feld[oldx][oldy];
1439 content_old = Store[oldx][oldy];
1441 if (element_old == EL_QUICKSAND_EMPTYING ||
1442 element_old == EL_MAGIC_WALL_EMPTYING ||
1443 element_old == EL_BD_MAGIC_WALL_EMPTYING ||
1444 element_old == EL_AMOEBA_DROPPING)
1445 cut_mode = CUT_ABOVE;
1447 DrawScreenElement(x, y, EL_EMPTY);
1450 DrawScreenElementShifted(sx, sy, MovPos[oldx][oldy], 0, element_old,
1452 else if (cut_mode == NO_CUTTING)
1453 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], element_old,
1456 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], content_old,
1459 else if (IS_DRAWABLE(element))
1460 DrawScreenElement(x, y, element);
1462 DrawScreenElement(x, y, EL_EMPTY);
1465 void DrawLevelField(int x, int y)
1467 if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1468 DrawScreenField(SCREENX(x), SCREENY(y));
1469 else if (IS_MOVING(x, y))
1473 Moving2Blocked(x, y, &newx, &newy);
1474 if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
1475 DrawScreenField(SCREENX(newx), SCREENY(newy));
1477 else if (IS_BLOCKED(x, y))
1481 Blocked2Moving(x, y, &oldx, &oldy);
1482 if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
1483 DrawScreenField(SCREENX(oldx), SCREENY(oldy));
1487 void DrawMiniElement(int x, int y, int element)
1491 graphic = el2edimg(element);
1492 DrawMiniGraphic(x, y, graphic);
1495 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
1497 int x = sx + scroll_x, y = sy + scroll_y;
1499 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
1500 DrawMiniElement(sx, sy, EL_EMPTY);
1501 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
1502 DrawMiniElement(sx, sy, Feld[x][y]);
1504 DrawMiniGraphic(sx, sy, el2edimg(getBorderElement(x, y)));
1507 void getMicroGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
1509 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
1510 int mini_startx = src_bitmap->width * 3 / 4;
1511 int mini_starty = src_bitmap->height * 2 / 3;
1512 int src_x = mini_startx + graphic_info[graphic].src_x / 8;
1513 int src_y = mini_starty + graphic_info[graphic].src_y / 8;
1515 *bitmap = src_bitmap;
1520 void DrawMicroElement(int xpos, int ypos, int element)
1524 int graphic = el2preimg(element);
1526 getMicroGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
1527 BlitBitmap(src_bitmap, drawto, src_x, src_y, MICRO_TILEX, MICRO_TILEY,
1535 SetDrawBackgroundMask(REDRAW_NONE);
1538 for(x=BX1; x<=BX2; x++)
1539 for(y=BY1; y<=BY2; y++)
1540 DrawScreenField(x, y);
1542 redraw_mask |= REDRAW_FIELD;
1545 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
1549 for(x=0; x<size_x; x++)
1550 for(y=0; y<size_y; y++)
1551 DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
1553 redraw_mask |= REDRAW_FIELD;
1556 static void DrawMicroLevelExt(int xpos, int ypos, int from_x, int from_y)
1560 DrawBackground(xpos, ypos, MICROLEV_XSIZE, MICROLEV_YSIZE);
1562 if (lev_fieldx < STD_LEV_FIELDX)
1563 xpos += (STD_LEV_FIELDX - lev_fieldx) / 2 * MICRO_TILEX;
1564 if (lev_fieldy < STD_LEV_FIELDY)
1565 ypos += (STD_LEV_FIELDY - lev_fieldy) / 2 * MICRO_TILEY;
1567 xpos += MICRO_TILEX;
1568 ypos += MICRO_TILEY;
1570 for(x=-1; x<=STD_LEV_FIELDX; x++)
1572 for(y=-1; y<=STD_LEV_FIELDY; y++)
1574 int lx = from_x + x, ly = from_y + y;
1576 if (lx >= 0 && lx < lev_fieldx && ly >= 0 && ly < lev_fieldy)
1577 DrawMicroElement(xpos + x * MICRO_TILEX, ypos + y * MICRO_TILEY,
1578 level.field[lx][ly]);
1579 else if (lx >= -1 && lx < lev_fieldx+1 && ly >= -1 && ly < lev_fieldy+1
1580 && BorderElement != EL_EMPTY)
1581 DrawMicroElement(xpos + x * MICRO_TILEX, ypos + y * MICRO_TILEY,
1582 getBorderElement(lx, ly));
1586 redraw_mask |= REDRAW_MICROLEVEL;
1589 #define MICROLABEL_EMPTY 0
1590 #define MICROLABEL_LEVEL_NAME 1
1591 #define MICROLABEL_CREATED_BY 2
1592 #define MICROLABEL_LEVEL_AUTHOR 3
1593 #define MICROLABEL_IMPORTED_FROM 4
1594 #define MICROLABEL_LEVEL_IMPORT_INFO 5
1596 static void DrawMicroLevelLabelExt(int mode)
1598 char label_text[MAX_OUTPUT_LINESIZE + 1];
1599 int max_len_label_text;
1600 int font_nr = FONT_TEXT_2;
1602 if (mode == MICROLABEL_CREATED_BY || mode == MICROLABEL_IMPORTED_FROM)
1603 font_nr = FONT_TEXT_3;
1605 max_len_label_text = SXSIZE / getFontWidth(font_nr);
1607 DrawBackground(SX, MICROLABEL_YPOS, SXSIZE, getFontHeight(font_nr));
1609 strncpy(label_text, (mode == MICROLABEL_LEVEL_NAME ? level.name :
1610 mode == MICROLABEL_CREATED_BY ? "created by" :
1611 mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
1612 mode == MICROLABEL_IMPORTED_FROM ? "imported from" :
1613 mode == MICROLABEL_LEVEL_IMPORT_INFO ?
1614 leveldir_current->imported_from : ""),
1615 max_len_label_text);
1616 label_text[max_len_label_text] = '\0';
1618 if (strlen(label_text) > 0)
1620 int text_width = strlen(label_text) * getFontWidth(font_nr);
1621 int lxpos = SX + (SXSIZE - text_width) / 2;
1622 int lypos = MICROLABEL_YPOS;
1624 DrawText(lxpos, lypos, label_text, font_nr);
1627 redraw_mask |= REDRAW_MICROLEVEL;
1630 void DrawMicroLevel(int xpos, int ypos, boolean restart)
1632 static unsigned long scroll_delay = 0;
1633 static unsigned long label_delay = 0;
1634 static int from_x, from_y, scroll_direction;
1635 static int label_state, label_counter;
1636 int last_game_status = game_status; /* save current game status */
1638 /* force PREVIEW font on preview level */
1639 game_status = GAME_MODE_PSEUDO_PREVIEW;
1643 from_x = from_y = 0;
1644 scroll_direction = MV_RIGHT;
1648 DrawMicroLevelExt(xpos, ypos, from_x, from_y);
1649 DrawMicroLevelLabelExt(label_state);
1651 /* initialize delay counters */
1652 DelayReached(&scroll_delay, 0);
1653 DelayReached(&label_delay, 0);
1655 if (leveldir_current->name)
1657 int len = strlen(leveldir_current->name);
1658 int lxpos = SX + (SXSIZE - len * getFontWidth(FONT_TEXT_1)) / 2;
1659 int lypos = SY + 352;
1661 DrawText(lxpos, lypos, leveldir_current->name, FONT_TEXT_1);
1664 game_status = last_game_status; /* restore current game status */
1669 /* scroll micro level, if needed */
1670 if ((lev_fieldx > STD_LEV_FIELDX || lev_fieldy > STD_LEV_FIELDY) &&
1671 DelayReached(&scroll_delay, MICROLEVEL_SCROLL_DELAY))
1673 switch (scroll_direction)
1679 scroll_direction = MV_UP;
1683 if (from_x < lev_fieldx - STD_LEV_FIELDX)
1686 scroll_direction = MV_DOWN;
1693 scroll_direction = MV_RIGHT;
1697 if (from_y < lev_fieldy - STD_LEV_FIELDY)
1700 scroll_direction = MV_LEFT;
1707 DrawMicroLevelExt(xpos, ypos, from_x, from_y);
1710 /* redraw micro level label, if needed */
1711 if (strcmp(level.name, NAMELESS_LEVEL_NAME) != 0 &&
1712 strcmp(level.author, ANONYMOUS_NAME) != 0 &&
1713 strcmp(level.author, leveldir_current->name) != 0 &&
1714 DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
1716 int max_label_counter = 23;
1718 if (leveldir_current->imported_from != NULL)
1719 max_label_counter += 14;
1721 label_counter = (label_counter + 1) % max_label_counter;
1722 label_state = (label_counter >= 0 && label_counter <= 7 ?
1723 MICROLABEL_LEVEL_NAME :
1724 label_counter >= 9 && label_counter <= 12 ?
1725 MICROLABEL_CREATED_BY :
1726 label_counter >= 14 && label_counter <= 21 ?
1727 MICROLABEL_LEVEL_AUTHOR :
1728 label_counter >= 23 && label_counter <= 26 ?
1729 MICROLABEL_IMPORTED_FROM :
1730 label_counter >= 28 && label_counter <= 35 ?
1731 MICROLABEL_LEVEL_IMPORT_INFO : MICROLABEL_EMPTY);
1732 DrawMicroLevelLabelExt(label_state);
1735 game_status = last_game_status; /* restore current game status */
1738 int REQ_in_range(int x, int y)
1740 if (y > DY+249 && y < DY+278)
1742 if (x > DX+1 && x < DX+48)
1744 else if (x > DX+51 && x < DX+98)
1750 #define MAX_REQUEST_LINES 13
1751 #define MAX_REQUEST_LINE_LEN 7
1753 boolean Request(char *text, unsigned int req_state)
1755 int mx, my, ty, result = -1;
1756 unsigned int old_door_state;
1757 int last_game_status = game_status; /* save current game status */
1759 #if defined(PLATFORM_UNIX)
1760 /* pause network game while waiting for request to answer */
1761 if (options.network &&
1762 game_status == GAME_MODE_PLAYING &&
1763 req_state & REQUEST_WAIT_FOR)
1764 SendToServer_PausePlaying();
1767 old_door_state = GetDoorState();
1769 /* simulate releasing mouse button over last gadget, if still pressed */
1771 HandleGadgets(-1, -1, 0);
1775 CloseDoor(DOOR_CLOSE_1);
1777 /* save old door content */
1778 BlitBitmap(bitmap_db_door, bitmap_db_door,
1779 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
1780 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
1782 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
1784 /* clear door drawing field */
1785 DrawBackground(DX, DY, DXSIZE, DYSIZE);
1787 /* force DOOR font on preview level */
1788 game_status = GAME_MODE_PSEUDO_DOOR;
1790 /* write text for request */
1791 for(ty=0; ty < MAX_REQUEST_LINES; ty++)
1793 char text_line[MAX_REQUEST_LINE_LEN + 1];
1799 for(tl=0,tx=0; tx < MAX_REQUEST_LINE_LEN; tl++,tx++)
1802 if (!tc || tc == ' ')
1813 strncpy(text_line, text, tl);
1816 DrawText(DX + (DXSIZE - tl * getFontWidth(FONT_TEXT_2)) / 2,
1817 DY + 8 + ty * (getFontHeight(FONT_TEXT_2) + 2),
1818 text_line, FONT_TEXT_2);
1820 text += tl + (tc == ' ' ? 1 : 0);
1823 game_status = last_game_status; /* restore current game status */
1825 if (req_state & REQ_ASK)
1827 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
1828 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
1830 else if (req_state & REQ_CONFIRM)
1832 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
1834 else if (req_state & REQ_PLAYER)
1836 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
1837 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
1838 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
1839 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
1842 /* copy request gadgets to door backbuffer */
1843 BlitBitmap(drawto, bitmap_db_door,
1844 DX, DY, DXSIZE, DYSIZE,
1845 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
1847 OpenDoor(DOOR_OPEN_1);
1853 if (!(req_state & REQUEST_WAIT_FOR))
1855 SetDrawBackgroundMask(REDRAW_FIELD);
1860 if (game_status != GAME_MODE_MAIN)
1863 button_status = MB_RELEASED;
1865 request_gadget_id = -1;
1867 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
1879 case EVENT_BUTTONPRESS:
1880 case EVENT_BUTTONRELEASE:
1881 case EVENT_MOTIONNOTIFY:
1883 if (event.type == EVENT_MOTIONNOTIFY)
1885 if (!PointerInWindow(window))
1886 continue; /* window and pointer are on different screens */
1891 motion_status = TRUE;
1892 mx = ((MotionEvent *) &event)->x;
1893 my = ((MotionEvent *) &event)->y;
1897 motion_status = FALSE;
1898 mx = ((ButtonEvent *) &event)->x;
1899 my = ((ButtonEvent *) &event)->y;
1900 if (event.type == EVENT_BUTTONPRESS)
1901 button_status = ((ButtonEvent *) &event)->button;
1903 button_status = MB_RELEASED;
1906 /* this sets 'request_gadget_id' */
1907 HandleGadgets(mx, my, button_status);
1909 switch(request_gadget_id)
1911 case TOOL_CTRL_ID_YES:
1914 case TOOL_CTRL_ID_NO:
1917 case TOOL_CTRL_ID_CONFIRM:
1918 result = TRUE | FALSE;
1921 case TOOL_CTRL_ID_PLAYER_1:
1924 case TOOL_CTRL_ID_PLAYER_2:
1927 case TOOL_CTRL_ID_PLAYER_3:
1930 case TOOL_CTRL_ID_PLAYER_4:
1941 case EVENT_KEYPRESS:
1942 switch(GetEventKey((KeyEvent *)&event, TRUE))
1955 if (req_state & REQ_PLAYER)
1959 case EVENT_KEYRELEASE:
1960 ClearPlayerAction();
1964 HandleOtherEvents(&event);
1968 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
1970 int joy = AnyJoystick();
1972 if (joy & JOY_BUTTON_1)
1974 else if (joy & JOY_BUTTON_2)
1980 /* don't eat all CPU time */
1984 if (game_status != GAME_MODE_MAIN)
1989 if (!(req_state & REQ_STAY_OPEN))
1991 CloseDoor(DOOR_CLOSE_1);
1993 if (!(req_state & REQ_STAY_CLOSED) && (old_door_state & DOOR_OPEN_1))
1995 BlitBitmap(bitmap_db_door, bitmap_db_door,
1996 DOOR_GFX_PAGEX2,DOOR_GFX_PAGEY1, DXSIZE,DYSIZE,
1997 DOOR_GFX_PAGEX1,DOOR_GFX_PAGEY1);
1998 OpenDoor(DOOR_OPEN_1);
2004 SetDrawBackgroundMask(REDRAW_FIELD);
2006 #if defined(PLATFORM_UNIX)
2007 /* continue network game after request */
2008 if (options.network &&
2009 game_status == GAME_MODE_PLAYING &&
2010 req_state & REQUEST_WAIT_FOR)
2011 SendToServer_ContinuePlaying();
2017 unsigned int OpenDoor(unsigned int door_state)
2019 unsigned int new_door_state;
2021 if (door_state & DOOR_COPY_BACK)
2023 BlitBitmap(bitmap_db_door, bitmap_db_door,
2024 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE + VYSIZE,
2025 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2026 door_state &= ~DOOR_COPY_BACK;
2029 new_door_state = MoveDoor(door_state);
2031 return(new_door_state);
2034 unsigned int CloseDoor(unsigned int door_state)
2036 unsigned int new_door_state;
2038 BlitBitmap(backbuffer, bitmap_db_door,
2039 DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2040 BlitBitmap(backbuffer, bitmap_db_door,
2041 VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
2043 new_door_state = MoveDoor(door_state);
2045 return(new_door_state);
2048 unsigned int GetDoorState()
2050 return MoveDoor(DOOR_GET_STATE);
2053 unsigned int SetDoorState(unsigned int door_state)
2055 return MoveDoor(door_state | DOOR_SET_STATE);
2058 unsigned int MoveDoor(unsigned int door_state)
2060 static int door1 = DOOR_OPEN_1;
2061 static int door2 = DOOR_CLOSE_2;
2062 static unsigned long door_delay = 0;
2063 int x, start, stepsize = door.step_offset;
2064 unsigned long door_delay_value = door.step_delay;
2066 if (door_state == DOOR_GET_STATE)
2067 return(door1 | door2);
2069 if (door_state & DOOR_SET_STATE)
2071 if (door_state & DOOR_ACTION_1)
2072 door1 = door_state & DOOR_ACTION_1;
2073 if (door_state & DOOR_ACTION_2)
2074 door2 = door_state & DOOR_ACTION_2;
2076 return(door1 | door2);
2079 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
2080 door_state &= ~DOOR_OPEN_1;
2081 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
2082 door_state &= ~DOOR_CLOSE_1;
2083 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
2084 door_state &= ~DOOR_OPEN_2;
2085 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
2086 door_state &= ~DOOR_CLOSE_2;
2088 if (setup.quick_doors)
2091 door_delay_value = 0;
2093 StopSound(SND_DOOR_OPENING);
2094 StopSound(SND_DOOR_CLOSING);
2097 if (global.autoplay_leveldir)
2099 door_state |= DOOR_NO_DELAY;
2100 door_state &= ~DOOR_CLOSE_ALL;
2103 if (door_state & DOOR_ACTION)
2105 if (!(door_state & DOOR_NO_DELAY))
2107 /* opening door sound has priority over simultaneously closing door */
2108 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
2109 PlaySoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
2110 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
2111 PlaySoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
2114 start = ((door_state & DOOR_NO_DELAY) ? DXSIZE : 0);
2116 for(x=start; x<=DXSIZE; x+=stepsize)
2118 Bitmap *bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
2119 GC gc = bitmap->stored_clip_gc;
2121 if (!(door_state & DOOR_NO_DELAY))
2122 WaitUntilDelayReached(&door_delay, door_delay_value);
2124 if (door_state & DOOR_ACTION_1)
2126 int i = (door_state & DOOR_OPEN_1 ? DXSIZE-x : x);
2127 int j = (DXSIZE - i) / 3;
2129 BlitBitmap(bitmap_db_door, drawto,
2130 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + i/2,
2131 DXSIZE,DYSIZE - i/2, DX, DY);
2133 ClearRectangle(drawto, DX, DY + DYSIZE - i/2, DXSIZE,i/2);
2135 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2136 BlitBitmapMasked(bitmap, drawto,
2137 DXSIZE, DOOR_GFX_PAGEY1, i, 77,
2138 DX + DXSIZE - i, DY + j);
2139 BlitBitmapMasked(bitmap, drawto,
2140 DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63,
2141 DX + DXSIZE - i, DY + 140 + j);
2142 SetClipOrigin(bitmap, gc, DX - DXSIZE + i, DY - (DOOR_GFX_PAGEY1 + j));
2143 BlitBitmapMasked(bitmap, drawto,
2144 DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j,
2146 BlitBitmapMasked(bitmap, drawto,
2147 DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63,
2150 BlitBitmapMasked(bitmap, drawto,
2151 DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
2153 BlitBitmapMasked(bitmap, drawto,
2154 DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
2156 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2157 BlitBitmapMasked(bitmap, drawto,
2158 DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
2159 DX + DXSIZE - i, DY + 77 + j);
2160 BlitBitmapMasked(bitmap, drawto,
2161 DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
2162 DX + DXSIZE - i, DY + 203 + j);
2164 redraw_mask |= REDRAW_DOOR_1;
2167 if (door_state & DOOR_ACTION_2)
2169 int i = (door_state & DOOR_OPEN_2 ? VXSIZE - x : x);
2170 int j = (VXSIZE - i) / 3;
2172 BlitBitmap(bitmap_db_door, drawto,
2173 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + i/2,
2174 VXSIZE, VYSIZE - i/2, VX, VY);
2176 ClearRectangle(drawto, VX, VY + VYSIZE-i/2, VXSIZE, i/2);
2178 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2179 BlitBitmapMasked(bitmap, drawto,
2180 VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2,
2181 VX + VXSIZE-i, VY+j);
2182 SetClipOrigin(bitmap, gc,
2183 VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
2184 BlitBitmapMasked(bitmap, drawto,
2185 VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j,
2188 BlitBitmapMasked(bitmap, drawto,
2189 VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2,
2190 i, VYSIZE / 2, VX, VY + VYSIZE / 2 - j);
2191 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2192 BlitBitmapMasked(bitmap, drawto,
2193 VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2,
2195 VX + VXSIZE - i, VY + VYSIZE / 2 + j);
2197 redraw_mask |= REDRAW_DOOR_2;
2202 if (game_status == GAME_MODE_MAIN)
2207 if (setup.quick_doors)
2209 StopSound(SND_DOOR_OPENING);
2210 StopSound(SND_DOOR_CLOSING);
2213 if (door_state & DOOR_ACTION_1)
2214 door1 = door_state & DOOR_ACTION_1;
2215 if (door_state & DOOR_ACTION_2)
2216 door2 = door_state & DOOR_ACTION_2;
2218 return (door1 | door2);
2221 void DrawSpecialEditorDoor()
2223 /* draw bigger toolbox window */
2224 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
2225 DOOR_GFX_PAGEX7, 0, EXSIZE + 8, 8,
2227 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
2228 EX - 4, VY - 4, EXSIZE + 8, EYSIZE - VYSIZE + 4,
2231 redraw_mask |= REDRAW_ALL;
2234 void UndrawSpecialEditorDoor()
2236 /* draw normal tape recorder window */
2237 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
2238 EX - 4, EY - 12, EXSIZE + 8, EYSIZE - VYSIZE + 12,
2241 redraw_mask |= REDRAW_ALL;
2245 /* ---------- new tool button stuff ---------------------------------------- */
2247 /* graphic position values for tool buttons */
2248 #define TOOL_BUTTON_YES_XPOS 2
2249 #define TOOL_BUTTON_YES_YPOS 250
2250 #define TOOL_BUTTON_YES_GFX_YPOS 0
2251 #define TOOL_BUTTON_YES_XSIZE 46
2252 #define TOOL_BUTTON_YES_YSIZE 28
2253 #define TOOL_BUTTON_NO_XPOS 52
2254 #define TOOL_BUTTON_NO_YPOS TOOL_BUTTON_YES_YPOS
2255 #define TOOL_BUTTON_NO_GFX_YPOS TOOL_BUTTON_YES_GFX_YPOS
2256 #define TOOL_BUTTON_NO_XSIZE TOOL_BUTTON_YES_XSIZE
2257 #define TOOL_BUTTON_NO_YSIZE TOOL_BUTTON_YES_YSIZE
2258 #define TOOL_BUTTON_CONFIRM_XPOS TOOL_BUTTON_YES_XPOS
2259 #define TOOL_BUTTON_CONFIRM_YPOS TOOL_BUTTON_YES_YPOS
2260 #define TOOL_BUTTON_CONFIRM_GFX_YPOS 30
2261 #define TOOL_BUTTON_CONFIRM_XSIZE 96
2262 #define TOOL_BUTTON_CONFIRM_YSIZE TOOL_BUTTON_YES_YSIZE
2263 #define TOOL_BUTTON_PLAYER_XSIZE 30
2264 #define TOOL_BUTTON_PLAYER_YSIZE 30
2265 #define TOOL_BUTTON_PLAYER_GFX_XPOS 5
2266 #define TOOL_BUTTON_PLAYER_GFX_YPOS 185
2267 #define TOOL_BUTTON_PLAYER_XPOS (5 + TOOL_BUTTON_PLAYER_XSIZE / 2)
2268 #define TOOL_BUTTON_PLAYER_YPOS (215 - TOOL_BUTTON_PLAYER_YSIZE / 2)
2269 #define TOOL_BUTTON_PLAYER1_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2270 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2271 #define TOOL_BUTTON_PLAYER2_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2272 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2273 #define TOOL_BUTTON_PLAYER3_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2274 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2275 #define TOOL_BUTTON_PLAYER4_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2276 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2277 #define TOOL_BUTTON_PLAYER1_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2278 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2279 #define TOOL_BUTTON_PLAYER2_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2280 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2281 #define TOOL_BUTTON_PLAYER3_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2282 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2283 #define TOOL_BUTTON_PLAYER4_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2284 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2293 } toolbutton_info[NUM_TOOL_BUTTONS] =
2296 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_GFX_YPOS,
2297 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_YPOS,
2298 TOOL_BUTTON_YES_XSIZE, TOOL_BUTTON_YES_YSIZE,
2303 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_GFX_YPOS,
2304 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_YPOS,
2305 TOOL_BUTTON_NO_XSIZE, TOOL_BUTTON_NO_YSIZE,
2310 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_GFX_YPOS,
2311 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_YPOS,
2312 TOOL_BUTTON_CONFIRM_XSIZE, TOOL_BUTTON_CONFIRM_YSIZE,
2313 TOOL_CTRL_ID_CONFIRM,
2317 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2318 TOOL_BUTTON_PLAYER1_XPOS, TOOL_BUTTON_PLAYER1_YPOS,
2319 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2320 TOOL_CTRL_ID_PLAYER_1,
2324 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2325 TOOL_BUTTON_PLAYER2_XPOS, TOOL_BUTTON_PLAYER2_YPOS,
2326 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2327 TOOL_CTRL_ID_PLAYER_2,
2331 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2332 TOOL_BUTTON_PLAYER3_XPOS, TOOL_BUTTON_PLAYER3_YPOS,
2333 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2334 TOOL_CTRL_ID_PLAYER_3,
2338 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2339 TOOL_BUTTON_PLAYER4_XPOS, TOOL_BUTTON_PLAYER4_YPOS,
2340 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2341 TOOL_CTRL_ID_PLAYER_4,
2346 void CreateToolButtons()
2350 for (i=0; i<NUM_TOOL_BUTTONS; i++)
2352 Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
2353 Bitmap *deco_bitmap = None;
2354 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
2355 struct GadgetInfo *gi;
2356 unsigned long event_mask;
2357 int gd_xoffset, gd_yoffset;
2358 int gd_x1, gd_x2, gd_y;
2361 event_mask = GD_EVENT_RELEASED;
2363 gd_xoffset = toolbutton_info[i].xpos;
2364 gd_yoffset = toolbutton_info[i].ypos;
2365 gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
2366 gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
2367 gd_y = DOOR_GFX_PAGEY1 + gd_yoffset;
2369 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
2371 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
2373 getMiniGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr),
2374 &deco_bitmap, &deco_x, &deco_y);
2375 deco_xpos = (toolbutton_info[i].width - MINI_TILEX) / 2;
2376 deco_ypos = (toolbutton_info[i].height - MINI_TILEY) / 2;
2379 gi = CreateGadget(GDI_CUSTOM_ID, id,
2380 GDI_INFO_TEXT, toolbutton_info[i].infotext,
2381 GDI_X, DX + toolbutton_info[i].x,
2382 GDI_Y, DY + toolbutton_info[i].y,
2383 GDI_WIDTH, toolbutton_info[i].width,
2384 GDI_HEIGHT, toolbutton_info[i].height,
2385 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
2386 GDI_STATE, GD_BUTTON_UNPRESSED,
2387 GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
2388 GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
2389 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
2390 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
2391 GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
2392 GDI_DECORATION_SHIFTING, 1, 1,
2393 GDI_EVENT_MASK, event_mask,
2394 GDI_CALLBACK_ACTION, HandleToolButtons,
2398 Error(ERR_EXIT, "cannot create gadget");
2400 tool_gadget[id] = gi;
2404 void FreeToolButtons()
2408 for (i=0; i<NUM_TOOL_BUTTONS; i++)
2409 FreeGadget(tool_gadget[i]);
2412 static void UnmapToolButtons()
2416 for (i=0; i<NUM_TOOL_BUTTONS; i++)
2417 UnmapGadget(tool_gadget[i]);
2420 static void HandleToolButtons(struct GadgetInfo *gi)
2422 request_gadget_id = gi->custom_id;
2425 int get_next_element(int element)
2429 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
2430 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
2431 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
2432 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
2433 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
2434 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
2435 case EL_AMOEBA_DROPPING: return EL_AMOEBA_WET;
2437 default: return element;
2441 int el_act_dir2img(int element, int action, int direction)
2443 element = GFX_ELEMENT(element);
2444 direction = MV_DIR_BIT(direction);
2446 return element_info[element].direction_graphic[action][direction];
2449 int el_act2img(int element, int action)
2451 element = GFX_ELEMENT(element);
2453 return element_info[element].graphic[action];
2456 int el_dir2img(int element, int direction)
2458 element = GFX_ELEMENT(element);
2460 return el_act_dir2img(element, ACTION_DEFAULT, direction);
2463 int el2img(int element)
2465 element = GFX_ELEMENT(element);
2467 return element_info[element].graphic[ACTION_DEFAULT];
2470 int el2edimg(int element)
2472 element = GFX_ELEMENT(element);
2474 return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
2477 int el2preimg(int element)
2479 element = GFX_ELEMENT(element);
2481 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];