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 *);
37 static int el_act_dir2crm(int, int, int);
39 static struct GadgetInfo *tool_gadget[NUM_TOOL_BUTTONS];
40 static int request_gadget_id = -1;
42 void SetDrawtoField(int mode)
44 if (mode == DRAW_BUFFERED && setup.soft_scrolling)
55 drawto_field = fieldbuffer;
57 else /* DRAW_DIRECT, DRAW_BACKBUFFER */
68 drawto_field = (mode == DRAW_DIRECT ? window : backbuffer);
72 void RedrawPlayfield(boolean force_redraw, int x, int y, int width, int height)
74 if (game_status == GAME_MODE_PLAYING)
80 width = gfx.sxsize + 2 * TILEX;
81 height = gfx.sysize + 2 * TILEY;
84 if (force_redraw || setup.direct_draw)
87 int x1 = (x - SX) / TILEX, y1 = (y - SY) / TILEY;
88 int x2 = (x - SX + width) / TILEX, y2 = (y - SY + height) / TILEY;
90 if (setup.direct_draw)
91 SetDrawtoField(DRAW_BACKBUFFER);
93 for(xx=BX1; xx<=BX2; xx++)
94 for(yy=BY1; yy<=BY2; yy++)
95 if (xx >= x1 && xx <= x2 && yy >= y1 && yy <= y2)
96 DrawScreenField(xx, yy);
99 if (setup.direct_draw)
100 SetDrawtoField(DRAW_DIRECT);
103 if (setup.soft_scrolling)
105 int fx = FX, fy = FY;
107 fx += (ScreenMovDir & (MV_LEFT|MV_RIGHT) ? ScreenGfxPos : 0);
108 fy += (ScreenMovDir & (MV_UP|MV_DOWN) ? ScreenGfxPos : 0);
110 BlitBitmap(fieldbuffer, backbuffer, fx,fy, SXSIZE,SYSIZE, SX,SY);
114 BlitBitmap(drawto, window, x, y, width, height, x, y);
120 DrawBuffer *buffer = (drawto_field == window ? backbuffer : drawto_field);
122 if (setup.direct_draw && game_status == GAME_MODE_PLAYING)
123 redraw_mask &= ~REDRAW_MAIN;
125 if (redraw_mask & REDRAW_TILES && redraw_tiles > REDRAWTILES_THRESHOLD)
126 redraw_mask |= REDRAW_FIELD;
128 if (redraw_mask & REDRAW_FIELD)
129 redraw_mask &= ~REDRAW_TILES;
131 if (redraw_mask == REDRAW_NONE)
134 if (global.fps_slowdown && game_status == GAME_MODE_PLAYING)
136 static boolean last_frame_skipped = FALSE;
137 boolean skip_even_when_not_scrolling = TRUE;
138 boolean just_scrolling = (ScreenMovDir != 0);
139 boolean verbose = FALSE;
141 if (global.fps_slowdown_factor > 1 &&
142 (FrameCounter % global.fps_slowdown_factor) &&
143 (just_scrolling || skip_even_when_not_scrolling))
145 redraw_mask &= ~REDRAW_MAIN;
147 last_frame_skipped = TRUE;
150 printf("FRAME SKIPPED\n");
154 if (last_frame_skipped)
155 redraw_mask |= REDRAW_FIELD;
157 last_frame_skipped = FALSE;
160 printf("frame not skipped\n");
164 /* synchronize X11 graphics at this point; if we would synchronize the
165 display immediately after the buffer switching (after the XFlush),
166 this could mean that we have to wait for the graphics to complete,
167 although we could go on doing calculations for the next frame */
171 if (redraw_mask & REDRAW_ALL)
173 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
177 if (redraw_mask & REDRAW_FIELD)
179 if (game_status != GAME_MODE_PLAYING ||
180 redraw_mask & REDRAW_FROM_BACKBUFFER)
182 BlitBitmap(backbuffer, window,
183 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE, REAL_SX, REAL_SY);
187 int fx = FX, fy = FY;
189 if (setup.soft_scrolling)
191 fx += (ScreenMovDir & (MV_LEFT | MV_RIGHT) ? ScreenGfxPos : 0);
192 fy += (ScreenMovDir & (MV_UP | MV_DOWN) ? ScreenGfxPos : 0);
195 if (setup.soft_scrolling ||
196 ABS(ScreenMovPos) + ScrollStepSize == TILEX ||
197 ABS(ScreenMovPos) == ScrollStepSize ||
198 redraw_tiles > REDRAWTILES_THRESHOLD)
200 BlitBitmap(buffer, window, fx, fy, SXSIZE, SYSIZE, SX, SY);
204 printf("redrawing all (ScreenGfxPos == %d) because %s\n",
206 (setup.soft_scrolling ?
207 "setup.soft_scrolling" :
208 ABS(ScreenGfxPos) + ScrollStepSize == TILEX ?
209 "ABS(ScreenGfxPos) + ScrollStepSize == TILEX" :
210 ABS(ScreenGfxPos) == ScrollStepSize ?
211 "ABS(ScreenGfxPos) == ScrollStepSize" :
212 "redraw_tiles > REDRAWTILES_THRESHOLD"));
218 redraw_mask &= ~REDRAW_MAIN;
221 if (redraw_mask & REDRAW_DOORS)
223 if (redraw_mask & REDRAW_DOOR_1)
224 BlitBitmap(backbuffer, window, DX, DY, DXSIZE, DYSIZE, DX, DY);
225 if (redraw_mask & REDRAW_DOOR_2)
227 if ((redraw_mask & REDRAW_DOOR_2) == REDRAW_DOOR_2)
228 BlitBitmap(backbuffer, window, VX,VY, VXSIZE,VYSIZE, VX,VY);
231 if (redraw_mask & REDRAW_VIDEO_1)
232 BlitBitmap(backbuffer, window,
233 VX+VIDEO_DISPLAY1_XPOS,VY+VIDEO_DISPLAY1_YPOS,
234 VIDEO_DISPLAY_XSIZE,VIDEO_DISPLAY_YSIZE,
235 VX+VIDEO_DISPLAY1_XPOS,VY+VIDEO_DISPLAY1_YPOS);
236 if (redraw_mask & REDRAW_VIDEO_2)
237 BlitBitmap(backbuffer, window,
238 VX+VIDEO_DISPLAY2_XPOS,VY+VIDEO_DISPLAY2_YPOS,
239 VIDEO_DISPLAY_XSIZE,VIDEO_DISPLAY_YSIZE,
240 VX+VIDEO_DISPLAY2_XPOS,VY+VIDEO_DISPLAY2_YPOS);
241 if (redraw_mask & REDRAW_VIDEO_3)
242 BlitBitmap(backbuffer, window,
243 VX+VIDEO_CONTROL_XPOS,VY+VIDEO_CONTROL_YPOS,
244 VIDEO_CONTROL_XSIZE,VIDEO_CONTROL_YSIZE,
245 VX+VIDEO_CONTROL_XPOS,VY+VIDEO_CONTROL_YPOS);
249 if (redraw_mask & REDRAW_DOOR_3)
250 BlitBitmap(backbuffer, window, EX, EY, EXSIZE, EYSIZE, EX, EY);
252 redraw_mask &= ~REDRAW_DOORS;
255 if (redraw_mask & REDRAW_MICROLEVEL)
257 BlitBitmap(backbuffer, window, SX, SY + 10 * TILEY, SXSIZE, 7 * TILEY,
258 SX, SY + 10 * TILEY);
260 redraw_mask &= ~REDRAW_MICROLEVEL;
263 if (redraw_mask & REDRAW_TILES)
265 for(x=0; x<SCR_FIELDX; x++)
266 for(y=0; y<SCR_FIELDY; y++)
267 if (redraw[redraw_x1 + x][redraw_y1 + y])
268 BlitBitmap(buffer, window,
269 FX + x * TILEX, FX + y * TILEY, TILEX, TILEY,
270 SX + x * TILEX, SY + y * TILEY);
273 if (redraw_mask & REDRAW_FPS) /* display frames per second */
278 sprintf(info1, " (only every %d. frame)", global.fps_slowdown_factor);
279 if (!global.fps_slowdown)
282 sprintf(text, "%.1f fps%s", global.frames_per_second, info1);
283 DrawTextExt(window, SX, SY, text, FONT_TEXT_2, BLIT_OPAQUE);
288 for(x=0; x<MAX_BUF_XSIZE; x++)
289 for(y=0; y<MAX_BUF_YSIZE; y++)
292 redraw_mask = REDRAW_NONE;
298 long fading_delay = 300;
300 if (setup.fading && (redraw_mask & REDRAW_FIELD))
307 ClearRectangle(window, REAL_SX,REAL_SY,FULL_SXSIZE,FULL_SYSIZE);
310 for(i=0;i<2*FULL_SYSIZE;i++)
312 for(y=0;y<FULL_SYSIZE;y++)
314 BlitBitmap(backbuffer, window,
315 REAL_SX,REAL_SY+i, FULL_SXSIZE,1, REAL_SX,REAL_SY+i);
323 for(i=1;i<FULL_SYSIZE;i+=2)
324 BlitBitmap(backbuffer, window,
325 REAL_SX,REAL_SY+i, FULL_SXSIZE,1, REAL_SX,REAL_SY+i);
331 SetClipOrigin(clip_gc[PIX_FADEMASK], 0, 0);
332 BlitBitmapMasked(backbuffer, window,
333 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
338 SetClipOrigin(clip_gc[PIX_FADEMASK], -1, -1);
339 BlitBitmapMasked(backbuffer, window,
340 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
345 SetClipOrigin(clip_gc[PIX_FADEMASK], 0, -1);
346 BlitBitmapMasked(backbuffer, window,
347 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
352 SetClipOrigin(clip_gc[PIX_FADEMASK], -1, 0);
353 BlitBitmapMasked(backbuffer, window,
354 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
359 redraw_mask &= ~REDRAW_MAIN;
366 void SetMainBackgroundImage(int graphic)
368 SetMainBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
369 graphic_info[graphic].bitmap ?
370 graphic_info[graphic].bitmap :
371 graphic_info[IMG_BACKGROUND].bitmap);
374 void SetDoorBackgroundImage(int graphic)
376 SetDoorBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
377 graphic_info[graphic].bitmap ?
378 graphic_info[graphic].bitmap :
379 graphic_info[IMG_BACKGROUND].bitmap);
382 void DrawBackground(int dest_x, int dest_y, int width, int height)
384 ClearRectangleOnBackground(backbuffer, dest_x, dest_y, width, height);
386 redraw_mask |= REDRAW_FIELD;
391 DrawBackground(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
393 if (setup.soft_scrolling && game_status == GAME_MODE_PLAYING)
395 ClearRectangle(fieldbuffer, 0, 0, FXSIZE, FYSIZE);
396 SetDrawtoField(DRAW_BUFFERED);
399 SetDrawtoField(DRAW_BACKBUFFER);
401 if (setup.direct_draw && game_status == GAME_MODE_PLAYING)
403 ClearRectangle(window, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
404 SetDrawtoField(DRAW_DIRECT);
408 void MarkTileDirty(int x, int y)
410 int xx = redraw_x1 + x;
411 int yy = redraw_y1 + y;
416 redraw[xx][yy] = TRUE;
417 redraw_mask |= REDRAW_TILES;
420 void SetBorderElement()
424 BorderElement = EL_EMPTY;
426 for(y=0; y<lev_fieldy && BorderElement == EL_EMPTY; y++)
428 for(x=0; x<lev_fieldx; x++)
430 if (!IS_INDESTRUCTIBLE(Feld[x][y]))
431 BorderElement = EL_STEELWALL;
433 if (y != 0 && y != lev_fieldy - 1 && x != lev_fieldx - 1)
439 void SetRandomAnimationValue(int x, int y)
441 gfx.anim_random_frame = GfxRandom[x][y];
444 inline int getGraphicAnimationFrame(int graphic, int sync_frame)
446 /* animation synchronized with global frame counter, not move position */
447 if (graphic_info[graphic].anim_global_sync || sync_frame < 0)
448 sync_frame = FrameCounter;
450 return getAnimationFrame(graphic_info[graphic].anim_frames,
451 graphic_info[graphic].anim_delay,
452 graphic_info[graphic].anim_mode,
453 graphic_info[graphic].anim_start_frame,
457 inline void DrawGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
458 int graphic, int sync_frame, int mask_mode)
460 int frame = getGraphicAnimationFrame(graphic, sync_frame);
462 if (mask_mode == USE_MASKING)
463 DrawGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
465 DrawGraphicExt(dst_bitmap, x, y, graphic, frame);
468 inline void DrawGraphicAnimation(int x, int y, int graphic)
470 int lx = LEVELX(x), ly = LEVELY(y);
472 if (!IN_SCR_FIELD(x, y))
475 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
476 graphic, GfxFrame[lx][ly], NO_MASKING);
480 void DrawLevelGraphicAnimation(int x, int y, int graphic)
482 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
485 void DrawLevelElementAnimation(int x, int y, int element)
488 int graphic = el_act_dir2img(element, GfxAction[x][y], MovDir[x][y]);
490 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
492 DrawGraphicAnimation(SCREENX(x), SCREENY(y), el2img(element));
496 inline void DrawLevelGraphicAnimationIfNeeded(int x, int y, int graphic)
498 int sx = SCREENX(x), sy = SCREENY(y);
500 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
503 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
506 DrawGraphicAnimation(sx, sy, graphic);
508 if (CAN_BE_CRUMBLED(Feld[x][y]))
509 DrawLevelFieldCrumbledSand(x, y);
512 void DrawLevelElementAnimationIfNeeded(int x, int y, int element)
514 int sx = SCREENX(x), sy = SCREENY(y);
517 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
520 graphic = el_act_dir2img(element, GfxAction[x][y], MovDir[x][y]);
522 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
525 DrawGraphicAnimation(sx, sy, graphic);
527 if (CAN_BE_CRUMBLED(element))
528 DrawLevelFieldCrumbledSand(x, y);
531 void DrawAllPlayers()
535 for(i=0; i<MAX_PLAYERS; i++)
536 if (stored_player[i].active)
537 DrawPlayer(&stored_player[i]);
540 void DrawPlayerField(int x, int y)
542 if (!IS_PLAYER(x, y))
545 DrawPlayer(PLAYERINFO(x, y));
548 void DrawPlayer(struct PlayerInfo *player)
551 int jx = player->jx, jy = player->jy;
552 int last_jx = player->last_jx, last_jy = player->last_jy;
553 int next_jx = jx + (jx - last_jx), next_jy = jy + (jy - last_jy);
554 int sx = SCREENX(jx), sy = SCREENY(jy);
555 int sxx = 0, syy = 0;
556 int element = Feld[jx][jy], last_element = Feld[last_jx][last_jy];
559 boolean player_is_moving = (last_jx != jx || last_jy != jy ? TRUE : FALSE);
560 int move_dir = player->MovDir;
561 int action = ACTION_DEFAULT;
563 int jx = player->jx, jy = player->jy;
564 int move_dir = player->MovDir;
565 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? +1 : 0);
566 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? +1 : 0);
567 int last_jx = (player->is_moving ? jx - dx : jx);
568 int last_jy = (player->is_moving ? jy - dy : jy);
569 int next_jx = jx + dx;
570 int next_jy = jy + dy;
571 int sx = SCREENX(jx), sy = SCREENY(jy);
572 int sxx = 0, syy = 0;
573 int element = Feld[jx][jy], last_element = Feld[last_jx][last_jy];
576 boolean player_is_moving = (player->MovPos ? TRUE : FALSE);
577 int action = ACTION_DEFAULT;
580 if (!player->active || !IN_SCR_FIELD(SCREENX(last_jx), SCREENY(last_jy)))
584 if (!IN_LEV_FIELD(jx,jy))
586 printf("DrawPlayerField(): x = %d, y = %d\n",jx,jy);
587 printf("DrawPlayerField(): sx = %d, sy = %d\n",sx,sy);
588 printf("DrawPlayerField(): This should never happen!\n");
593 if (element == EL_EXPLOSION)
596 action = (player->Pushing ? ACTION_PUSHING :
597 player->is_digging ? ACTION_DIGGING :
598 player->is_collecting ? ACTION_COLLECTING :
599 player->is_moving ? ACTION_MOVING :
600 player->snapped ? ACTION_SNAPPING : ACTION_DEFAULT);
603 printf("::: '%s'\n", element_action_info[action].suffix);
606 InitPlayerGfxAnimation(player, action, move_dir);
608 /* ----------------------------------------------------------------------- */
609 /* draw things in the field the player is leaving, if needed */
610 /* ----------------------------------------------------------------------- */
613 if (player->is_moving)
615 if (player_is_moving)
618 if (Back[last_jx][last_jy] && IS_DRAWABLE(last_element))
620 DrawLevelElement(last_jx, last_jy, Back[last_jx][last_jy]);
622 if (last_element == EL_DYNAMITE_ACTIVE ||
623 last_element == EL_SP_DISK_RED_ACTIVE)
624 DrawDynamite(last_jx, last_jy);
626 DrawLevelFieldThruMask(last_jx, last_jy);
628 else if (last_element == EL_DYNAMITE_ACTIVE ||
629 last_element == EL_SP_DISK_RED_ACTIVE)
630 DrawDynamite(last_jx, last_jy);
632 DrawLevelField(last_jx, last_jy);
634 if (player->Pushing && IN_SCR_FIELD(SCREENX(next_jx), SCREENY(next_jy)))
638 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
642 if (Feld[next_jx][next_jy] == EL_SOKOBAN_FIELD_FULL)
643 DrawLevelElement(next_jx, next_jy, EL_SOKOBAN_FIELD_EMPTY);
645 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
648 DrawLevelField(next_jx, next_jy);
654 if (!IN_SCR_FIELD(sx, sy))
657 if (setup.direct_draw)
658 SetDrawtoField(DRAW_BUFFERED);
660 /* ----------------------------------------------------------------------- */
661 /* draw things behind the player, if needed */
662 /* ----------------------------------------------------------------------- */
665 DrawLevelElement(jx, jy, Back[jx][jy]);
666 else if (IS_ACTIVE_BOMB(element))
667 DrawLevelElement(jx, jy, EL_EMPTY);
670 if (player_is_moving && GfxElement[jx][jy] != EL_UNDEFINED)
673 if (CAN_BE_CRUMBLED(GfxElement[jx][jy]))
674 DrawLevelFieldCrumbledSandDigging(jx, jy, move_dir, player->StepFrame);
676 if (GfxElement[jx][jy] == EL_SAND)
677 DrawLevelFieldCrumbledSandDigging(jx, jy, move_dir, player->StepFrame);
681 int old_element = GfxElement[jx][jy];
682 int old_graphic = el_act_dir2img(old_element, action, move_dir);
683 int frame = getGraphicAnimationFrame(old_graphic, player->StepFrame);
685 DrawGraphic(sx, sy, old_graphic, frame);
690 GfxElement[jx][jy] = EL_UNDEFINED;
692 DrawLevelField(jx, jy);
696 /* ----------------------------------------------------------------------- */
697 /* draw player himself */
698 /* ----------------------------------------------------------------------- */
700 if (player->use_murphy_graphic)
702 static int last_horizontal_dir = MV_LEFT;
705 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
706 last_horizontal_dir = move_dir;
708 direction = (player->snapped ? move_dir : last_horizontal_dir);
710 graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, direction);
713 graphic = el_act_dir2img(player->element_nr, player->GfxAction, move_dir);
715 frame = getGraphicAnimationFrame(graphic, player->Frame);
719 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
720 sxx = player->GfxPos;
722 syy = player->GfxPos;
725 if (!setup.soft_scrolling && ScreenMovPos)
728 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
730 if (SHIELD_ON(player))
732 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
733 IMG_SHIELD_NORMAL_ACTIVE);
734 int frame = getGraphicAnimationFrame(graphic, -1);
736 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
739 /* ----------------------------------------------------------------------- */
740 /* draw things the player is pushing, if needed */
741 /* ----------------------------------------------------------------------- */
744 printf("::: %d, %d [%d, %d] [%d]\n",
745 player->Pushing, player_is_moving, player->GfxAction,
746 player->is_moving, player_is_moving);
750 if (player->Pushing && player->is_moving)
752 if (player->Pushing && player_is_moving)
755 int px = SCREENX(next_jx), py = SCREENY(next_jy);
757 if (Back[next_jx][next_jy])
758 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
761 if ((sxx || syy) && element == EL_SOKOBAN_OBJECT)
762 DrawGraphicShiftedThruMask(px, py, sxx, syy, IMG_SOKOBAN_OBJECT, 0,
766 (element == EL_SOKOBAN_FIELD_EMPTY ||
767 Feld[next_jx][next_jy] == EL_SOKOBAN_FIELD_FULL))
768 DrawGraphicShiftedThruMask(px, py, sxx, syy, IMG_SOKOBAN_OBJECT, 0,
774 int element = MovingOrBlocked2Element(next_jx, next_jy);
777 int element = Feld[jx][jy];
779 int element = Feld[next_jx][next_jy];
784 int graphic = el2img(element);
788 if ((sxx || syy) && IS_PUSHABLE(element))
791 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
792 frame = getGraphicAnimationFrame(graphic, player->Frame);
796 printf("::: pushing %d: %d ...\n", sxx, frame);
799 DrawGraphicShifted(px, py, sxx, syy, graphic, frame,
800 NO_CUTTING, NO_MASKING);
805 /* ----------------------------------------------------------------------- */
806 /* draw things in front of player (active dynamite or dynabombs) */
807 /* ----------------------------------------------------------------------- */
809 if (IS_ACTIVE_BOMB(element))
811 graphic = el2img(element);
812 frame = getGraphicAnimationFrame(graphic, GfxFrame[jx][jy]);
814 if (game.emulation == EMU_SUPAPLEX)
815 DrawGraphic(sx, sy, IMG_SP_DISK_RED, frame);
817 DrawGraphicThruMask(sx, sy, graphic, frame);
820 if (player_is_moving && last_element == EL_EXPLOSION)
823 int graphic = el_act2img(GfxElement[last_jx][last_jy], ACTION_EXPLODING);
825 int stored = Store[last_jx][last_jy];
826 int graphic = (game.emulation != EMU_SUPAPLEX ? IMG_EXPLOSION :
827 stored == EL_SP_INFOTRON ? IMG_SP_EXPLOSION_INFOTRON :
830 int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
831 int phase = ExplodePhase[last_jx][last_jy] - 1;
832 int frame = getGraphicAnimationFrame(graphic, phase - delay);
835 DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy), graphic, frame);
838 /* ----------------------------------------------------------------------- */
839 /* draw elements the player is just walking/passing through/under */
840 /* ----------------------------------------------------------------------- */
842 /* handle the field the player is leaving ... */
843 if (player_is_moving && IS_ACCESSIBLE_INSIDE(last_element))
844 DrawLevelField(last_jx, last_jy);
845 else if (player_is_moving && IS_ACCESSIBLE_UNDER(last_element))
846 DrawLevelFieldThruMask(last_jx, last_jy);
848 /* ... and the field the player is entering */
849 if (IS_ACCESSIBLE_INSIDE(element))
850 DrawLevelField(jx, jy);
851 else if (IS_ACCESSIBLE_UNDER(element))
852 DrawLevelFieldThruMask(jx, jy);
854 if (setup.direct_draw)
856 int dest_x = SX + SCREENX(MIN(jx, last_jx)) * TILEX;
857 int dest_y = SY + SCREENY(MIN(jy, last_jy)) * TILEY;
858 int x_size = TILEX * (1 + ABS(jx - last_jx));
859 int y_size = TILEY * (1 + ABS(jy - last_jy));
861 BlitBitmap(drawto_field, window,
862 dest_x, dest_y, x_size, y_size, dest_x, dest_y);
863 SetDrawtoField(DRAW_DIRECT);
866 MarkTileDirty(sx,sy);
869 void getGraphicSource(int graphic, int frame, Bitmap **bitmap, int *x, int *y)
871 struct GraphicInfo *g = &graphic_info[graphic];
875 if (g->offset_y == 0) /* frames are ordered horizontally */
877 int max_width = g->anim_frames_per_line * g->width;
879 *x = (g->src_x + frame * g->offset_x) % max_width;
880 *y = g->src_y + (g->src_x + frame * g->offset_x) / max_width * g->height;
882 else if (g->offset_x == 0) /* frames are ordered vertically */
884 int max_height = g->anim_frames_per_line * g->height;
886 *x = g->src_x + (g->src_y + frame * g->offset_y) / max_height * g->width;
887 *y = (g->src_y + frame * g->offset_y) % max_height;
889 else /* frames are ordered diagonally */
891 *x = g->src_x + frame * g->offset_x;
892 *y = g->src_y + frame * g->offset_y;
896 void DrawGraphic(int x, int y, int graphic, int frame)
899 if (!IN_SCR_FIELD(x, y))
901 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
902 printf("DrawGraphic(): This should never happen!\n");
907 DrawGraphicExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic, frame);
911 void DrawGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
917 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
918 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
921 void DrawGraphicThruMask(int x, int y, int graphic, int frame)
924 if (!IN_SCR_FIELD(x, y))
926 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
927 printf("DrawGraphicThruMask(): This should never happen!\n");
932 DrawGraphicThruMaskExt(drawto_field, FX + x * TILEX, FY + y *TILEY, graphic,
937 void DrawGraphicThruMaskExt(DrawBuffer *d, int dest_x, int dest_y, int graphic,
945 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
946 drawing_gc = src_bitmap->stored_clip_gc;
948 GC drawing_gc = src_bitmap->stored_clip_gc;
949 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
950 int src_x = graphic_info[graphic].src_x;
951 int src_y = graphic_info[graphic].src_y;
952 int offset_x = graphic_info[graphic].offset_x;
953 int offset_y = graphic_info[graphic].offset_y;
955 src_x += frame * offset_x;
956 src_y += frame * offset_y;
960 SetClipOrigin(src_bitmap, drawing_gc, dest_x - src_x, dest_y - src_y);
961 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX, TILEY, dest_x, dest_y);
964 void DrawMiniGraphic(int x, int y, int graphic)
966 DrawMiniGraphicExt(drawto, SX + x * MINI_TILEX,SY + y * MINI_TILEY, graphic);
967 MarkTileDirty(x / 2, y / 2);
970 void getMiniGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
972 struct GraphicInfo *g = &graphic_info[graphic];
974 int mini_starty = g->bitmap->height * 2 / 3;
977 *x = mini_startx + g->src_x / 2;
978 *y = mini_starty + g->src_y / 2;
981 void DrawMiniGraphicExt(DrawBuffer *d, int x, int y, int graphic)
986 getMiniGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
987 BlitBitmap(src_bitmap, d, src_x, src_y, MINI_TILEX, MINI_TILEY, x, y);
990 void DrawGraphicShifted(int x,int y, int dx,int dy, int graphic, int frame,
991 int cut_mode, int mask_mode)
996 int width = TILEX, height = TILEY;
1002 DrawGraphic(x, y, graphic, frame);
1006 if (dx || dy) /* shifted graphic */
1008 if (x < BX1) /* object enters playfield from the left */
1015 else if (x > BX2) /* object enters playfield from the right */
1021 else if (x==BX1 && dx < 0) /* object leaves playfield to the left */
1027 else if (x==BX2 && dx > 0) /* object leaves playfield to the right */
1029 else if (dx) /* general horizontal movement */
1030 MarkTileDirty(x + SIGN(dx), y);
1032 if (y < BY1) /* object enters playfield from the top */
1034 if (cut_mode==CUT_BELOW) /* object completely above top border */
1042 else if (y > BY2) /* object enters playfield from the bottom */
1048 else if (y==BY1 && dy < 0) /* object leaves playfield to the top */
1054 else if (dy > 0 && cut_mode == CUT_ABOVE)
1056 if (y == BY2) /* object completely above bottom border */
1062 MarkTileDirty(x, y + 1);
1063 } /* object leaves playfield to the bottom */
1064 else if (dy > 0 && (y == BY2 || cut_mode == CUT_BELOW))
1066 else if (dy) /* general vertical movement */
1067 MarkTileDirty(x, y + SIGN(dy));
1071 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1073 src_bitmap = graphic_info[graphic].bitmap;
1074 src_x = graphic_info[graphic].src_x;
1075 src_y = graphic_info[graphic].src_y;
1076 offset_x = graphic_info[graphic].offset_x;
1077 offset_y = graphic_info[graphic].offset_y;
1079 src_x += frame * offset_x;
1080 src_y += frame * offset_y;
1083 drawing_gc = src_bitmap->stored_clip_gc;
1088 dest_x = FX + x * TILEX + dx;
1089 dest_y = FY + y * TILEY + dy;
1092 if (!IN_SCR_FIELD(x,y))
1094 printf("DrawGraphicShifted(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
1095 printf("DrawGraphicShifted(): This should never happen!\n");
1100 if (mask_mode == USE_MASKING)
1102 SetClipOrigin(src_bitmap, drawing_gc, dest_x - src_x, dest_y - src_y);
1103 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1107 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1113 void DrawGraphicShiftedThruMask(int x, int y, int dx, int dy, int graphic,
1114 int frame, int cut_mode)
1116 DrawGraphicShifted(x,y, dx,dy, graphic, frame, cut_mode, USE_MASKING);
1119 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
1120 int cut_mode, int mask_mode)
1122 int lx = LEVELX(x), ly = LEVELY(y);
1126 if (IN_LEV_FIELD(lx, ly))
1128 SetRandomAnimationValue(lx, ly);
1130 graphic = el_act_dir2img(element, GfxAction[lx][ly], MovDir[lx][ly]);
1131 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1133 else /* border element */
1135 graphic = el2img(element);
1136 frame = getGraphicAnimationFrame(graphic, -1);
1139 if (element == EL_EXPANDABLE_WALL)
1141 boolean left_stopped = FALSE, right_stopped = FALSE;
1143 if (!IN_LEV_FIELD(lx - 1, ly) || IS_WALL(Feld[lx - 1][ly]))
1144 left_stopped = TRUE;
1145 if (!IN_LEV_FIELD(lx + 1, ly) || IS_WALL(Feld[lx + 1][ly]))
1146 right_stopped = TRUE;
1148 if (left_stopped && right_stopped)
1150 else if (left_stopped)
1152 graphic = IMG_EXPANDABLE_WALL_GROWING_RIGHT;
1153 frame = graphic_info[graphic].anim_frames - 1;
1155 else if (right_stopped)
1157 graphic = IMG_EXPANDABLE_WALL_GROWING_LEFT;
1158 frame = graphic_info[graphic].anim_frames - 1;
1163 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, mask_mode);
1164 else if (mask_mode == USE_MASKING)
1165 DrawGraphicThruMask(x, y, graphic, frame);
1167 DrawGraphic(x, y, graphic, frame);
1170 void DrawLevelElementExt(int x, int y, int dx, int dy, int element,
1171 int cut_mode, int mask_mode)
1173 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1174 DrawScreenElementExt(SCREENX(x), SCREENY(y), dx, dy, element,
1175 cut_mode, mask_mode);
1178 void DrawScreenElementShifted(int x, int y, int dx, int dy, int element,
1181 DrawScreenElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1184 void DrawLevelElementShifted(int x, int y, int dx, int dy, int element,
1187 DrawLevelElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1190 void DrawLevelElementThruMask(int x, int y, int element)
1192 DrawLevelElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1195 void DrawLevelFieldThruMask(int x, int y)
1197 DrawLevelElementExt(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
1200 static void DrawLevelFieldCrumbledSandExt(int x, int y, int graphic, int frame)
1204 int sx = SCREENX(x), sy = SCREENY(y);
1206 int width, height, cx, cy, i;
1208 int crumbled_border_size = graphic_info[graphic].border_size;
1210 int snip = TILEX / 8; /* number of border pixels from "crumbled graphic" */
1212 static int xy[4][2] =
1220 if (!IN_LEV_FIELD(x, y))
1223 element = (GfxElement[x][y] != EL_UNDEFINED && Feld[x][y] != EL_EXPLOSION ?
1224 GfxElement[x][y] : Feld[x][y]);
1226 /* crumble field itself */
1227 if (CAN_BE_CRUMBLED(element) && !IS_MOVING(x, y))
1229 if (!IN_SCR_FIELD(sx, sy))
1232 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1236 int xx = x + xy[i][0];
1237 int yy = y + xy[i][1];
1239 element = (IN_LEV_FIELD(xx, yy) ? Feld[xx][yy] : BorderElement);
1241 /* check if neighbour field is of same type */
1242 if (CAN_BE_CRUMBLED(element) && !IS_MOVING(xx, yy))
1246 if (Feld[x][y] == EL_CUSTOM_START + 123)
1247 printf("::: crumble [%d] THE CHAOS ENGINE (%d, %d): %d, %d\n",
1248 i, Feld[x][y], element,
1249 CAN_BE_CRUMBLED(element), IS_MOVING(x, y));
1252 if (i == 1 || i == 2)
1254 width = crumbled_border_size;
1256 cx = (i == 2 ? TILEX - crumbled_border_size : 0);
1262 height = crumbled_border_size;
1264 cy = (i == 3 ? TILEY - crumbled_border_size : 0);
1267 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1268 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
1271 MarkTileDirty(sx, sy);
1273 else /* crumble neighbour fields */
1275 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1279 int xx = x + xy[i][0];
1280 int yy = y + xy[i][1];
1281 int sxx = sx + xy[i][0];
1282 int syy = sy + xy[i][1];
1284 if (!IN_LEV_FIELD(xx, yy) ||
1285 !IN_SCR_FIELD(sxx, syy) ||
1286 !CAN_BE_CRUMBLED(Feld[xx][yy]) ||
1290 if (i == 1 || i == 2)
1292 width = crumbled_border_size;
1294 cx = (i == 1 ? TILEX - crumbled_border_size : 0);
1300 height = crumbled_border_size;
1302 cy = (i == 0 ? TILEY - crumbled_border_size : 0);
1305 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1306 width, height, FX + sxx * TILEX + cx, FY + syy * TILEY + cy);
1308 MarkTileDirty(sxx, syy);
1313 void DrawLevelFieldCrumbledSand(int x, int y)
1315 DrawLevelFieldCrumbledSandExt(x, y, IMG_SAND_CRUMBLED, 0);
1318 void DrawLevelFieldCrumbledSandDigging(int x, int y, int direction,
1322 int graphic1 = el_act_dir2img(GfxElement[x][y], ACTION_DIGGING, direction);
1323 int graphic2 = el_act_dir2crm(GfxElement[x][y], ACTION_DIGGING, direction);
1325 int graphic1 = el_act_dir2img(EL_SAND, ACTION_DIGGING, direction);
1326 int graphic2 = el_act_dir2img(EL_SAND_CRUMBLED, ACTION_DIGGING, direction);
1328 int frame1 = getGraphicAnimationFrame(graphic1, step_frame);
1329 int frame2 = getGraphicAnimationFrame(graphic2, step_frame);
1330 int sx = SCREENX(x), sy = SCREENY(y);
1332 DrawGraphic(sx, sy, graphic1, frame1);
1333 DrawLevelFieldCrumbledSandExt(x, y, graphic2, frame2);
1336 void DrawLevelFieldCrumbledSandNeighbours(int x, int y)
1338 int sx = SCREENX(x), sy = SCREENY(y);
1339 static int xy[4][2] =
1350 int xx = x + xy[i][0];
1351 int yy = y + xy[i][1];
1352 int sxx = sx + xy[i][0];
1353 int syy = sy + xy[i][1];
1355 if (!IN_LEV_FIELD(xx, yy) ||
1356 !IN_SCR_FIELD(sxx, syy) ||
1357 !CAN_BE_CRUMBLED(Feld[xx][yy]) ||
1361 DrawLevelField(xx, yy);
1365 static int getBorderElement(int x, int y)
1369 { EL_STEELWALL_TOPLEFT, EL_INVISIBLE_STEELWALL_TOPLEFT },
1370 { EL_STEELWALL_TOPRIGHT, EL_INVISIBLE_STEELWALL_TOPRIGHT },
1371 { EL_STEELWALL_BOTTOMLEFT, EL_INVISIBLE_STEELWALL_BOTTOMLEFT },
1372 { EL_STEELWALL_BOTTOMRIGHT, EL_INVISIBLE_STEELWALL_BOTTOMRIGHT },
1373 { EL_STEELWALL_VERTICAL, EL_INVISIBLE_STEELWALL_VERTICAL },
1374 { EL_STEELWALL_HORIZONTAL, EL_INVISIBLE_STEELWALL_HORIZONTAL },
1375 { EL_STEELWALL, EL_INVISIBLE_STEELWALL }
1377 int steel_type = (BorderElement == EL_STEELWALL ? 0 : 1);
1378 int steel_position = (x == -1 && y == -1 ? 0 :
1379 x == lev_fieldx && y == -1 ? 1 :
1380 x == -1 && y == lev_fieldy ? 2 :
1381 x == lev_fieldx && y == lev_fieldy ? 3 :
1382 x == -1 || x == lev_fieldx ? 4 :
1383 y == -1 || y == lev_fieldy ? 5 : 6);
1385 return border[steel_position][steel_type];
1388 void DrawScreenElement(int x, int y, int element)
1390 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
1391 DrawLevelFieldCrumbledSand(LEVELX(x), LEVELY(y));
1394 void DrawLevelElement(int x, int y, int element)
1396 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1397 DrawScreenElement(SCREENX(x), SCREENY(y), element);
1400 void DrawScreenField(int x, int y)
1402 int lx = LEVELX(x), ly = LEVELY(y);
1403 int element, content;
1405 if (!IN_LEV_FIELD(lx, ly))
1407 if (lx < -1 || lx > lev_fieldx || ly < -1 || ly > lev_fieldy)
1410 element = getBorderElement(lx, ly);
1412 DrawScreenElement(x, y, element);
1416 element = Feld[lx][ly];
1417 content = Store[lx][ly];
1419 if (IS_MOVING(lx, ly))
1421 int horiz_move = (MovDir[lx][ly] == MV_LEFT || MovDir[lx][ly] == MV_RIGHT);
1422 boolean cut_mode = NO_CUTTING;
1424 if (element == EL_QUICKSAND_EMPTYING ||
1425 element == EL_MAGIC_WALL_EMPTYING ||
1426 element == EL_BD_MAGIC_WALL_EMPTYING ||
1427 element == EL_AMOEBA_DROPPING)
1428 cut_mode = CUT_ABOVE;
1429 else if (element == EL_QUICKSAND_FILLING ||
1430 element == EL_MAGIC_WALL_FILLING ||
1431 element == EL_BD_MAGIC_WALL_FILLING)
1432 cut_mode = CUT_BELOW;
1434 if (cut_mode == CUT_ABOVE)
1435 DrawScreenElementShifted(x, y, 0, 0, element, NO_CUTTING);
1437 DrawScreenElement(x, y, EL_EMPTY);
1440 DrawScreenElementShifted(x, y, MovPos[lx][ly], 0, element, NO_CUTTING);
1441 else if (cut_mode == NO_CUTTING)
1442 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], element, cut_mode);
1444 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], content, cut_mode);
1446 if (content == EL_ACID)
1447 DrawLevelElementThruMask(lx, ly + 1, EL_ACID);
1449 else if (IS_BLOCKED(lx, ly))
1454 boolean cut_mode = NO_CUTTING;
1455 int element_old, content_old;
1457 Blocked2Moving(lx, ly, &oldx, &oldy);
1460 horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
1461 MovDir[oldx][oldy] == MV_RIGHT);
1463 element_old = Feld[oldx][oldy];
1464 content_old = Store[oldx][oldy];
1466 if (element_old == EL_QUICKSAND_EMPTYING ||
1467 element_old == EL_MAGIC_WALL_EMPTYING ||
1468 element_old == EL_BD_MAGIC_WALL_EMPTYING ||
1469 element_old == EL_AMOEBA_DROPPING)
1470 cut_mode = CUT_ABOVE;
1472 DrawScreenElement(x, y, EL_EMPTY);
1475 DrawScreenElementShifted(sx, sy, MovPos[oldx][oldy], 0, element_old,
1477 else if (cut_mode == NO_CUTTING)
1478 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], element_old,
1481 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], content_old,
1484 else if (IS_DRAWABLE(element))
1485 DrawScreenElement(x, y, element);
1487 DrawScreenElement(x, y, EL_EMPTY);
1490 void DrawLevelField(int x, int y)
1492 if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1493 DrawScreenField(SCREENX(x), SCREENY(y));
1494 else if (IS_MOVING(x, y))
1498 Moving2Blocked(x, y, &newx, &newy);
1499 if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
1500 DrawScreenField(SCREENX(newx), SCREENY(newy));
1502 else if (IS_BLOCKED(x, y))
1506 Blocked2Moving(x, y, &oldx, &oldy);
1507 if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
1508 DrawScreenField(SCREENX(oldx), SCREENY(oldy));
1512 void DrawMiniElement(int x, int y, int element)
1516 graphic = el2edimg(element);
1517 DrawMiniGraphic(x, y, graphic);
1520 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
1522 int x = sx + scroll_x, y = sy + scroll_y;
1524 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
1525 DrawMiniElement(sx, sy, EL_EMPTY);
1526 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
1527 DrawMiniElement(sx, sy, Feld[x][y]);
1529 DrawMiniGraphic(sx, sy, el2edimg(getBorderElement(x, y)));
1532 void DrawEnvelopeBackground(int dst_x, int dst_y, int ex, int ey, int font_nr)
1535 int font_width = getFontWidth(font_nr);
1536 int font_height = getFontHeight(font_nr);
1537 int graphic = IMG_GAME_ENVELOPE_BACKGROUND;
1541 int dst_x = SX + sx * font_width;
1542 int dst_y = SY + sy * font_height;
1544 int width = graphic_info[graphic].width;
1545 int height = graphic_info[graphic].height;
1546 boolean draw_masked = graphic_info[graphic].draw_masked;
1548 getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
1550 if (src_bitmap == NULL)
1552 ClearRectangle(drawto, dst_x, dst_y, font_width, font_height);
1556 src_x += (ex == -1 ? 0 : ex == +1 ? width - font_width : font_width);
1557 src_y += (ey == -1 ? 0 : ey == +1 ? height - font_height : font_height);
1561 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1562 dst_x - src_x, dst_y - src_y);
1563 BlitBitmapMasked(src_bitmap, drawto, src_x, src_y, font_width, font_height,
1567 BlitBitmap(src_bitmap, drawto, src_x, src_y, font_width, font_height,
1572 { EL_STEELWALL_TOPLEFT, EL_INVISIBLE_STEELWALL_TOPLEFT },
1573 { EL_STEELWALL_TOPRIGHT, EL_INVISIBLE_STEELWALL_TOPRIGHT },
1574 { EL_STEELWALL_BOTTOMLEFT, EL_INVISIBLE_STEELWALL_BOTTOMLEFT },
1575 { EL_STEELWALL_BOTTOMRIGHT, EL_INVISIBLE_STEELWALL_BOTTOMRIGHT },
1576 { EL_STEELWALL_VERTICAL, EL_INVISIBLE_STEELWALL_VERTICAL },
1577 { EL_STEELWALL_HORIZONTAL, EL_INVISIBLE_STEELWALL_HORIZONTAL },
1578 { EL_STEELWALL, EL_INVISIBLE_STEELWALL },
1579 { EL_EMPTY, EL_EMPTY }
1581 int steel_type = (BorderElement == EL_STEELWALL ? 0 : 1);
1582 int steel_position = (ex == -1 && ey == -1 ? 0 :
1583 ex == +1 && ey == -1 ? 1 :
1584 ex == -1 && ey == +1 ? 2 :
1585 ex == +1 && ey == +1 ? 3 :
1586 ex == -1 || ex == +1 ? 4 :
1587 ey == -1 || ey == +1 ? 5 : 7);
1588 int element = border[steel_position][steel_type];
1590 DrawMiniGraphic(sx, sy, el2edimg(element));
1594 void getMicroGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
1596 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
1597 int mini_startx = src_bitmap->width * 3 / 4;
1598 int mini_starty = src_bitmap->height * 2 / 3;
1599 int src_x = mini_startx + graphic_info[graphic].src_x / 8;
1600 int src_y = mini_starty + graphic_info[graphic].src_y / 8;
1602 *bitmap = src_bitmap;
1607 void DrawMicroElement(int xpos, int ypos, int element)
1611 int graphic = el2preimg(element);
1613 getMicroGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
1614 BlitBitmap(src_bitmap, drawto, src_x, src_y, MICRO_TILEX, MICRO_TILEY,
1622 SetDrawBackgroundMask(REDRAW_NONE);
1625 for(x=BX1; x<=BX2; x++)
1626 for(y=BY1; y<=BY2; y++)
1627 DrawScreenField(x, y);
1629 redraw_mask |= REDRAW_FIELD;
1632 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
1636 for(x=0; x<size_x; x++)
1637 for(y=0; y<size_y; y++)
1638 DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
1640 redraw_mask |= REDRAW_FIELD;
1643 static void DrawMicroLevelExt(int xpos, int ypos, int from_x, int from_y)
1647 DrawBackground(xpos, ypos, MICROLEV_XSIZE, MICROLEV_YSIZE);
1649 if (lev_fieldx < STD_LEV_FIELDX)
1650 xpos += (STD_LEV_FIELDX - lev_fieldx) / 2 * MICRO_TILEX;
1651 if (lev_fieldy < STD_LEV_FIELDY)
1652 ypos += (STD_LEV_FIELDY - lev_fieldy) / 2 * MICRO_TILEY;
1654 xpos += MICRO_TILEX;
1655 ypos += MICRO_TILEY;
1657 for(x=-1; x<=STD_LEV_FIELDX; x++)
1659 for(y=-1; y<=STD_LEV_FIELDY; y++)
1661 int lx = from_x + x, ly = from_y + y;
1663 if (lx >= 0 && lx < lev_fieldx && ly >= 0 && ly < lev_fieldy)
1664 DrawMicroElement(xpos + x * MICRO_TILEX, ypos + y * MICRO_TILEY,
1665 level.field[lx][ly]);
1666 else if (lx >= -1 && lx < lev_fieldx+1 && ly >= -1 && ly < lev_fieldy+1
1667 && BorderElement != EL_EMPTY)
1668 DrawMicroElement(xpos + x * MICRO_TILEX, ypos + y * MICRO_TILEY,
1669 getBorderElement(lx, ly));
1673 redraw_mask |= REDRAW_MICROLEVEL;
1676 #define MICROLABEL_EMPTY 0
1677 #define MICROLABEL_LEVEL_NAME 1
1678 #define MICROLABEL_CREATED_BY 2
1679 #define MICROLABEL_LEVEL_AUTHOR 3
1680 #define MICROLABEL_IMPORTED_FROM 4
1681 #define MICROLABEL_LEVEL_IMPORT_INFO 5
1683 static void DrawMicroLevelLabelExt(int mode)
1685 char label_text[MAX_OUTPUT_LINESIZE + 1];
1686 int max_len_label_text;
1687 int font_nr = FONT_TEXT_2;
1689 if (mode == MICROLABEL_CREATED_BY || mode == MICROLABEL_IMPORTED_FROM)
1690 font_nr = FONT_TEXT_3;
1692 max_len_label_text = SXSIZE / getFontWidth(font_nr);
1694 DrawBackground(SX, MICROLABEL_YPOS, SXSIZE, getFontHeight(font_nr));
1696 strncpy(label_text, (mode == MICROLABEL_LEVEL_NAME ? level.name :
1697 mode == MICROLABEL_CREATED_BY ? "created by" :
1698 mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
1699 mode == MICROLABEL_IMPORTED_FROM ? "imported from" :
1700 mode == MICROLABEL_LEVEL_IMPORT_INFO ?
1701 leveldir_current->imported_from : ""),
1702 max_len_label_text);
1703 label_text[max_len_label_text] = '\0';
1705 if (strlen(label_text) > 0)
1707 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
1708 int lypos = MICROLABEL_YPOS;
1710 DrawText(lxpos, lypos, label_text, font_nr);
1713 redraw_mask |= REDRAW_MICROLEVEL;
1716 void DrawMicroLevel(int xpos, int ypos, boolean restart)
1718 static unsigned long scroll_delay = 0;
1719 static unsigned long label_delay = 0;
1720 static int from_x, from_y, scroll_direction;
1721 static int label_state, label_counter;
1722 int last_game_status = game_status; /* save current game status */
1724 /* force PREVIEW font on preview level */
1725 game_status = GAME_MODE_PSEUDO_PREVIEW;
1729 from_x = from_y = 0;
1730 scroll_direction = MV_RIGHT;
1734 DrawMicroLevelExt(xpos, ypos, from_x, from_y);
1735 DrawMicroLevelLabelExt(label_state);
1737 /* initialize delay counters */
1738 DelayReached(&scroll_delay, 0);
1739 DelayReached(&label_delay, 0);
1741 if (leveldir_current->name)
1743 int text_width = getTextWidth(leveldir_current->name, FONT_TEXT_1);
1744 int lxpos = SX + (SXSIZE - text_width) / 2;
1745 int lypos = SY + 352;
1747 DrawText(lxpos, lypos, leveldir_current->name, FONT_TEXT_1);
1750 game_status = last_game_status; /* restore current game status */
1755 /* scroll micro level, if needed */
1756 if ((lev_fieldx > STD_LEV_FIELDX || lev_fieldy > STD_LEV_FIELDY) &&
1757 DelayReached(&scroll_delay, MICROLEVEL_SCROLL_DELAY))
1759 switch (scroll_direction)
1765 scroll_direction = MV_UP;
1769 if (from_x < lev_fieldx - STD_LEV_FIELDX)
1772 scroll_direction = MV_DOWN;
1779 scroll_direction = MV_RIGHT;
1783 if (from_y < lev_fieldy - STD_LEV_FIELDY)
1786 scroll_direction = MV_LEFT;
1793 DrawMicroLevelExt(xpos, ypos, from_x, from_y);
1796 /* redraw micro level label, if needed */
1797 if (strcmp(level.name, NAMELESS_LEVEL_NAME) != 0 &&
1798 strcmp(level.author, ANONYMOUS_NAME) != 0 &&
1799 strcmp(level.author, leveldir_current->name) != 0 &&
1800 DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
1802 int max_label_counter = 23;
1804 if (leveldir_current->imported_from != NULL)
1805 max_label_counter += 14;
1807 label_counter = (label_counter + 1) % max_label_counter;
1808 label_state = (label_counter >= 0 && label_counter <= 7 ?
1809 MICROLABEL_LEVEL_NAME :
1810 label_counter >= 9 && label_counter <= 12 ?
1811 MICROLABEL_CREATED_BY :
1812 label_counter >= 14 && label_counter <= 21 ?
1813 MICROLABEL_LEVEL_AUTHOR :
1814 label_counter >= 23 && label_counter <= 26 ?
1815 MICROLABEL_IMPORTED_FROM :
1816 label_counter >= 28 && label_counter <= 35 ?
1817 MICROLABEL_LEVEL_IMPORT_INFO : MICROLABEL_EMPTY);
1818 DrawMicroLevelLabelExt(label_state);
1821 game_status = last_game_status; /* restore current game status */
1824 void WaitForEventToContinue()
1826 boolean still_wait = TRUE;
1828 /* simulate releasing mouse button over last gadget, if still pressed */
1830 HandleGadgets(-1, -1, 0);
1832 button_status = MB_RELEASED;
1844 case EVENT_BUTTONPRESS:
1845 case EVENT_KEYPRESS:
1849 case EVENT_KEYRELEASE:
1850 ClearPlayerAction();
1854 HandleOtherEvents(&event);
1858 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
1865 /* don't eat all CPU time */
1870 #define MAX_REQUEST_LINES 13
1871 #define MAX_REQUEST_LINE_LEN 7
1873 boolean Request(char *text, unsigned int req_state)
1875 int mx, my, ty, result = -1;
1876 unsigned int old_door_state;
1877 int last_game_status = game_status; /* save current game status */
1880 SetMouseCursor(CURSOR_DEFAULT);
1883 #if defined(PLATFORM_UNIX)
1884 /* pause network game while waiting for request to answer */
1885 if (options.network &&
1886 game_status == GAME_MODE_PLAYING &&
1887 req_state & REQUEST_WAIT_FOR)
1888 SendToServer_PausePlaying();
1891 old_door_state = GetDoorState();
1893 /* simulate releasing mouse button over last gadget, if still pressed */
1895 HandleGadgets(-1, -1, 0);
1899 CloseDoor(DOOR_CLOSE_1);
1901 /* save old door content */
1902 BlitBitmap(bitmap_db_door, bitmap_db_door,
1903 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
1904 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
1906 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
1908 /* clear door drawing field */
1909 DrawBackground(DX, DY, DXSIZE, DYSIZE);
1911 /* force DOOR font on preview level */
1912 game_status = GAME_MODE_PSEUDO_DOOR;
1914 /* write text for request */
1915 for(ty=0; ty < MAX_REQUEST_LINES; ty++)
1917 char text_line[MAX_REQUEST_LINE_LEN + 1];
1923 for(tl=0,tx=0; tx < MAX_REQUEST_LINE_LEN; tl++,tx++)
1926 if (!tc || tc == ' ')
1937 strncpy(text_line, text, tl);
1940 DrawText(DX + (DXSIZE - tl * getFontWidth(FONT_TEXT_2)) / 2,
1941 DY + 8 + ty * (getFontHeight(FONT_TEXT_2) + 2),
1942 text_line, FONT_TEXT_2);
1944 text += tl + (tc == ' ' ? 1 : 0);
1947 game_status = last_game_status; /* restore current game status */
1949 if (req_state & REQ_ASK)
1951 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
1952 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
1954 else if (req_state & REQ_CONFIRM)
1956 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
1958 else if (req_state & REQ_PLAYER)
1960 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
1961 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
1962 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
1963 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
1966 /* copy request gadgets to door backbuffer */
1967 BlitBitmap(drawto, bitmap_db_door,
1968 DX, DY, DXSIZE, DYSIZE,
1969 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
1971 OpenDoor(DOOR_OPEN_1);
1977 if (!(req_state & REQUEST_WAIT_FOR))
1979 SetDrawBackgroundMask(REDRAW_FIELD);
1984 if (game_status != GAME_MODE_MAIN)
1987 button_status = MB_RELEASED;
1989 request_gadget_id = -1;
1991 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
1994 SetMouseCursor(CURSOR_DEFAULT);
2007 case EVENT_BUTTONPRESS:
2008 case EVENT_BUTTONRELEASE:
2009 case EVENT_MOTIONNOTIFY:
2011 if (event.type == EVENT_MOTIONNOTIFY)
2013 if (!PointerInWindow(window))
2014 continue; /* window and pointer are on different screens */
2019 motion_status = TRUE;
2020 mx = ((MotionEvent *) &event)->x;
2021 my = ((MotionEvent *) &event)->y;
2025 motion_status = FALSE;
2026 mx = ((ButtonEvent *) &event)->x;
2027 my = ((ButtonEvent *) &event)->y;
2028 if (event.type == EVENT_BUTTONPRESS)
2029 button_status = ((ButtonEvent *) &event)->button;
2031 button_status = MB_RELEASED;
2034 /* this sets 'request_gadget_id' */
2035 HandleGadgets(mx, my, button_status);
2037 switch(request_gadget_id)
2039 case TOOL_CTRL_ID_YES:
2042 case TOOL_CTRL_ID_NO:
2045 case TOOL_CTRL_ID_CONFIRM:
2046 result = TRUE | FALSE;
2049 case TOOL_CTRL_ID_PLAYER_1:
2052 case TOOL_CTRL_ID_PLAYER_2:
2055 case TOOL_CTRL_ID_PLAYER_3:
2058 case TOOL_CTRL_ID_PLAYER_4:
2069 case EVENT_KEYPRESS:
2070 switch(GetEventKey((KeyEvent *)&event, TRUE))
2083 if (req_state & REQ_PLAYER)
2087 case EVENT_KEYRELEASE:
2088 ClearPlayerAction();
2092 HandleOtherEvents(&event);
2096 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
2098 int joy = AnyJoystick();
2100 if (joy & JOY_BUTTON_1)
2102 else if (joy & JOY_BUTTON_2)
2108 /* don't eat all CPU time */
2112 if (game_status != GAME_MODE_MAIN)
2117 if (!(req_state & REQ_STAY_OPEN))
2119 CloseDoor(DOOR_CLOSE_1);
2121 if (!(req_state & REQ_STAY_CLOSED) && (old_door_state & DOOR_OPEN_1))
2123 BlitBitmap(bitmap_db_door, bitmap_db_door,
2124 DOOR_GFX_PAGEX2,DOOR_GFX_PAGEY1, DXSIZE,DYSIZE,
2125 DOOR_GFX_PAGEX1,DOOR_GFX_PAGEY1);
2126 OpenDoor(DOOR_OPEN_1);
2132 SetDrawBackgroundMask(REDRAW_FIELD);
2134 #if defined(PLATFORM_UNIX)
2135 /* continue network game after request */
2136 if (options.network &&
2137 game_status == GAME_MODE_PLAYING &&
2138 req_state & REQUEST_WAIT_FOR)
2139 SendToServer_ContinuePlaying();
2145 unsigned int OpenDoor(unsigned int door_state)
2147 unsigned int new_door_state;
2149 if (door_state & DOOR_COPY_BACK)
2151 BlitBitmap(bitmap_db_door, bitmap_db_door,
2152 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE + VYSIZE,
2153 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2154 door_state &= ~DOOR_COPY_BACK;
2157 new_door_state = MoveDoor(door_state);
2159 return(new_door_state);
2162 unsigned int CloseDoor(unsigned int door_state)
2164 unsigned int new_door_state;
2166 BlitBitmap(backbuffer, bitmap_db_door,
2167 DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2168 BlitBitmap(backbuffer, bitmap_db_door,
2169 VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
2171 new_door_state = MoveDoor(door_state);
2173 return(new_door_state);
2176 unsigned int GetDoorState()
2178 return MoveDoor(DOOR_GET_STATE);
2181 unsigned int SetDoorState(unsigned int door_state)
2183 return MoveDoor(door_state | DOOR_SET_STATE);
2186 unsigned int MoveDoor(unsigned int door_state)
2188 static int door1 = DOOR_OPEN_1;
2189 static int door2 = DOOR_CLOSE_2;
2190 static unsigned long door_delay = 0;
2191 int x, start, stepsize = door.step_offset;
2192 unsigned long door_delay_value = door.step_delay;
2194 if (door_state == DOOR_GET_STATE)
2195 return(door1 | door2);
2197 if (door_state & DOOR_SET_STATE)
2199 if (door_state & DOOR_ACTION_1)
2200 door1 = door_state & DOOR_ACTION_1;
2201 if (door_state & DOOR_ACTION_2)
2202 door2 = door_state & DOOR_ACTION_2;
2204 return(door1 | door2);
2207 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
2208 door_state &= ~DOOR_OPEN_1;
2209 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
2210 door_state &= ~DOOR_CLOSE_1;
2211 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
2212 door_state &= ~DOOR_OPEN_2;
2213 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
2214 door_state &= ~DOOR_CLOSE_2;
2216 if (setup.quick_doors)
2219 door_delay_value = 0;
2221 StopSound(SND_DOOR_OPENING);
2222 StopSound(SND_DOOR_CLOSING);
2225 if (global.autoplay_leveldir)
2227 door_state |= DOOR_NO_DELAY;
2228 door_state &= ~DOOR_CLOSE_ALL;
2231 if (door_state & DOOR_ACTION)
2233 if (!(door_state & DOOR_NO_DELAY))
2235 /* opening door sound has priority over simultaneously closing door */
2236 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
2237 PlaySoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
2238 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
2239 PlaySoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
2242 start = ((door_state & DOOR_NO_DELAY) ? DXSIZE : 0);
2244 for(x=start; x<=DXSIZE; x+=stepsize)
2246 Bitmap *bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
2247 GC gc = bitmap->stored_clip_gc;
2249 if (!(door_state & DOOR_NO_DELAY))
2250 WaitUntilDelayReached(&door_delay, door_delay_value);
2252 if (door_state & DOOR_ACTION_1)
2254 int i = (door_state & DOOR_OPEN_1 ? DXSIZE-x : x);
2255 int j = (DXSIZE - i) / 3;
2257 BlitBitmap(bitmap_db_door, drawto,
2258 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + i/2,
2259 DXSIZE,DYSIZE - i/2, DX, DY);
2261 ClearRectangle(drawto, DX, DY + DYSIZE - i/2, DXSIZE,i/2);
2263 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2264 BlitBitmapMasked(bitmap, drawto,
2265 DXSIZE, DOOR_GFX_PAGEY1, i, 77,
2266 DX + DXSIZE - i, DY + j);
2267 BlitBitmapMasked(bitmap, drawto,
2268 DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63,
2269 DX + DXSIZE - i, DY + 140 + j);
2270 SetClipOrigin(bitmap, gc, DX - DXSIZE + i, DY - (DOOR_GFX_PAGEY1 + j));
2271 BlitBitmapMasked(bitmap, drawto,
2272 DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j,
2274 BlitBitmapMasked(bitmap, drawto,
2275 DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63,
2278 BlitBitmapMasked(bitmap, drawto,
2279 DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
2281 BlitBitmapMasked(bitmap, drawto,
2282 DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
2284 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2285 BlitBitmapMasked(bitmap, drawto,
2286 DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
2287 DX + DXSIZE - i, DY + 77 + j);
2288 BlitBitmapMasked(bitmap, drawto,
2289 DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
2290 DX + DXSIZE - i, DY + 203 + j);
2292 redraw_mask |= REDRAW_DOOR_1;
2295 if (door_state & DOOR_ACTION_2)
2297 int i = (door_state & DOOR_OPEN_2 ? VXSIZE - x : x);
2298 int j = (VXSIZE - i) / 3;
2300 BlitBitmap(bitmap_db_door, drawto,
2301 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + i/2,
2302 VXSIZE, VYSIZE - i/2, VX, VY);
2304 ClearRectangle(drawto, VX, VY + VYSIZE-i/2, VXSIZE, i/2);
2306 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2307 BlitBitmapMasked(bitmap, drawto,
2308 VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2,
2309 VX + VXSIZE-i, VY+j);
2310 SetClipOrigin(bitmap, gc,
2311 VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
2312 BlitBitmapMasked(bitmap, drawto,
2313 VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j,
2316 BlitBitmapMasked(bitmap, drawto,
2317 VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2,
2318 i, VYSIZE / 2, VX, VY + VYSIZE / 2 - j);
2319 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2320 BlitBitmapMasked(bitmap, drawto,
2321 VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2,
2323 VX + VXSIZE - i, VY + VYSIZE / 2 + j);
2325 redraw_mask |= REDRAW_DOOR_2;
2330 if (game_status == GAME_MODE_MAIN)
2335 if (setup.quick_doors)
2337 StopSound(SND_DOOR_OPENING);
2338 StopSound(SND_DOOR_CLOSING);
2341 if (door_state & DOOR_ACTION_1)
2342 door1 = door_state & DOOR_ACTION_1;
2343 if (door_state & DOOR_ACTION_2)
2344 door2 = door_state & DOOR_ACTION_2;
2346 return (door1 | door2);
2349 void DrawSpecialEditorDoor()
2351 /* draw bigger toolbox window */
2352 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
2353 DOOR_GFX_PAGEX7, 0, EXSIZE + 8, 8,
2355 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
2356 EX - 4, VY - 4, EXSIZE + 8, EYSIZE - VYSIZE + 4,
2359 redraw_mask |= REDRAW_ALL;
2362 void UndrawSpecialEditorDoor()
2364 /* draw normal tape recorder window */
2365 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
2366 EX - 4, EY - 12, EXSIZE + 8, EYSIZE - VYSIZE + 12,
2369 redraw_mask |= REDRAW_ALL;
2373 /* ---------- new tool button stuff ---------------------------------------- */
2375 /* graphic position values for tool buttons */
2376 #define TOOL_BUTTON_YES_XPOS 2
2377 #define TOOL_BUTTON_YES_YPOS 250
2378 #define TOOL_BUTTON_YES_GFX_YPOS 0
2379 #define TOOL_BUTTON_YES_XSIZE 46
2380 #define TOOL_BUTTON_YES_YSIZE 28
2381 #define TOOL_BUTTON_NO_XPOS 52
2382 #define TOOL_BUTTON_NO_YPOS TOOL_BUTTON_YES_YPOS
2383 #define TOOL_BUTTON_NO_GFX_YPOS TOOL_BUTTON_YES_GFX_YPOS
2384 #define TOOL_BUTTON_NO_XSIZE TOOL_BUTTON_YES_XSIZE
2385 #define TOOL_BUTTON_NO_YSIZE TOOL_BUTTON_YES_YSIZE
2386 #define TOOL_BUTTON_CONFIRM_XPOS TOOL_BUTTON_YES_XPOS
2387 #define TOOL_BUTTON_CONFIRM_YPOS TOOL_BUTTON_YES_YPOS
2388 #define TOOL_BUTTON_CONFIRM_GFX_YPOS 30
2389 #define TOOL_BUTTON_CONFIRM_XSIZE 96
2390 #define TOOL_BUTTON_CONFIRM_YSIZE TOOL_BUTTON_YES_YSIZE
2391 #define TOOL_BUTTON_PLAYER_XSIZE 30
2392 #define TOOL_BUTTON_PLAYER_YSIZE 30
2393 #define TOOL_BUTTON_PLAYER_GFX_XPOS 5
2394 #define TOOL_BUTTON_PLAYER_GFX_YPOS 185
2395 #define TOOL_BUTTON_PLAYER_XPOS (5 + TOOL_BUTTON_PLAYER_XSIZE / 2)
2396 #define TOOL_BUTTON_PLAYER_YPOS (215 - TOOL_BUTTON_PLAYER_YSIZE / 2)
2397 #define TOOL_BUTTON_PLAYER1_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2398 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2399 #define TOOL_BUTTON_PLAYER2_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2400 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2401 #define TOOL_BUTTON_PLAYER3_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2402 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2403 #define TOOL_BUTTON_PLAYER4_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2404 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2405 #define TOOL_BUTTON_PLAYER1_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2406 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2407 #define TOOL_BUTTON_PLAYER2_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2408 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2409 #define TOOL_BUTTON_PLAYER3_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2410 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2411 #define TOOL_BUTTON_PLAYER4_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2412 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2421 } toolbutton_info[NUM_TOOL_BUTTONS] =
2424 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_GFX_YPOS,
2425 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_YPOS,
2426 TOOL_BUTTON_YES_XSIZE, TOOL_BUTTON_YES_YSIZE,
2431 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_GFX_YPOS,
2432 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_YPOS,
2433 TOOL_BUTTON_NO_XSIZE, TOOL_BUTTON_NO_YSIZE,
2438 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_GFX_YPOS,
2439 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_YPOS,
2440 TOOL_BUTTON_CONFIRM_XSIZE, TOOL_BUTTON_CONFIRM_YSIZE,
2441 TOOL_CTRL_ID_CONFIRM,
2445 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2446 TOOL_BUTTON_PLAYER1_XPOS, TOOL_BUTTON_PLAYER1_YPOS,
2447 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2448 TOOL_CTRL_ID_PLAYER_1,
2452 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2453 TOOL_BUTTON_PLAYER2_XPOS, TOOL_BUTTON_PLAYER2_YPOS,
2454 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2455 TOOL_CTRL_ID_PLAYER_2,
2459 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2460 TOOL_BUTTON_PLAYER3_XPOS, TOOL_BUTTON_PLAYER3_YPOS,
2461 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2462 TOOL_CTRL_ID_PLAYER_3,
2466 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2467 TOOL_BUTTON_PLAYER4_XPOS, TOOL_BUTTON_PLAYER4_YPOS,
2468 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2469 TOOL_CTRL_ID_PLAYER_4,
2474 void CreateToolButtons()
2478 for (i=0; i<NUM_TOOL_BUTTONS; i++)
2480 Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
2481 Bitmap *deco_bitmap = None;
2482 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
2483 struct GadgetInfo *gi;
2484 unsigned long event_mask;
2485 int gd_xoffset, gd_yoffset;
2486 int gd_x1, gd_x2, gd_y;
2489 event_mask = GD_EVENT_RELEASED;
2491 gd_xoffset = toolbutton_info[i].xpos;
2492 gd_yoffset = toolbutton_info[i].ypos;
2493 gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
2494 gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
2495 gd_y = DOOR_GFX_PAGEY1 + gd_yoffset;
2497 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
2499 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
2501 getMiniGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr),
2502 &deco_bitmap, &deco_x, &deco_y);
2503 deco_xpos = (toolbutton_info[i].width - MINI_TILEX) / 2;
2504 deco_ypos = (toolbutton_info[i].height - MINI_TILEY) / 2;
2507 gi = CreateGadget(GDI_CUSTOM_ID, id,
2508 GDI_INFO_TEXT, toolbutton_info[i].infotext,
2509 GDI_X, DX + toolbutton_info[i].x,
2510 GDI_Y, DY + toolbutton_info[i].y,
2511 GDI_WIDTH, toolbutton_info[i].width,
2512 GDI_HEIGHT, toolbutton_info[i].height,
2513 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
2514 GDI_STATE, GD_BUTTON_UNPRESSED,
2515 GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
2516 GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
2517 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
2518 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
2519 GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
2520 GDI_DECORATION_SHIFTING, 1, 1,
2521 GDI_EVENT_MASK, event_mask,
2522 GDI_CALLBACK_ACTION, HandleToolButtons,
2526 Error(ERR_EXIT, "cannot create gadget");
2528 tool_gadget[id] = gi;
2532 void FreeToolButtons()
2536 for (i=0; i<NUM_TOOL_BUTTONS; i++)
2537 FreeGadget(tool_gadget[i]);
2540 static void UnmapToolButtons()
2544 for (i=0; i<NUM_TOOL_BUTTONS; i++)
2545 UnmapGadget(tool_gadget[i]);
2548 static void HandleToolButtons(struct GadgetInfo *gi)
2550 request_gadget_id = gi->custom_id;
2553 int get_next_element(int element)
2557 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
2558 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
2559 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
2560 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
2561 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
2562 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
2563 case EL_AMOEBA_DROPPING: return EL_AMOEBA_WET;
2565 default: return element;
2569 int el_act_dir2img(int element, int action, int direction)
2571 element = GFX_ELEMENT(element);
2572 direction = MV_DIR_BIT(direction);
2574 return element_info[element].direction_graphic[action][direction];
2577 static int el_act_dir2crm(int element, int action, int direction)
2579 element = GFX_ELEMENT(element);
2580 direction = MV_DIR_BIT(direction);
2582 return element_info[element].direction_crumbled[action][direction];
2585 int el_act2img(int element, int action)
2587 element = GFX_ELEMENT(element);
2589 return element_info[element].graphic[action];
2592 int el_dir2img(int element, int direction)
2594 element = GFX_ELEMENT(element);
2596 return el_act_dir2img(element, ACTION_DEFAULT, direction);
2599 int el2img(int element)
2601 element = GFX_ELEMENT(element);
2603 return element_info[element].graphic[ACTION_DEFAULT];
2606 int el2edimg(int element)
2608 element = GFX_ELEMENT(element);
2610 return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
2613 int el2preimg(int element)
2615 element = GFX_ELEMENT(element);
2617 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];