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);
38 static int el_act2crm(int, int);
40 static struct GadgetInfo *tool_gadget[NUM_TOOL_BUTTONS];
41 static int request_gadget_id = -1;
43 void DumpTile(int x, int y)
49 printf("Field Info: SCREEN(%d, %d), LEVEL(%d, %d)\n", sx, sy, x, y);
52 if (!IN_LEV_FIELD(x, y))
54 printf("(not in level field)\n");
60 printf(" Feld: %d ['%s']\n", Feld[x][y],
61 element_info[Feld[x][y]].token_name);
62 printf(" Back: %d\n", Back[x][y]);
63 printf(" Store: %d\n", Store[x][y]);
64 printf(" Store2: %d\n", Store2[x][y]);
65 printf(" StorePlayer: %d\n", StorePlayer[x][y]);
66 printf(" MovPos: %d\n", MovPos[x][y]);
67 printf(" MovDir: %d\n", MovDir[x][y]);
68 printf(" MovDelay: %d\n", MovDelay[x][y]);
69 printf(" ChangeDelay: %d\n", ChangeDelay[x][y]);
70 printf(" GfxElement: %d\n", GfxElement[x][y]);
71 printf(" GfxAction: %d\n", GfxAction[x][y]);
72 printf(" GfxFrame: %d\n", GfxFrame[x][y]);
76 void SetDrawtoField(int mode)
78 if (mode == DRAW_BUFFERED && setup.soft_scrolling)
89 drawto_field = fieldbuffer;
91 else /* DRAW_DIRECT, DRAW_BACKBUFFER */
102 drawto_field = (mode == DRAW_DIRECT ? window : backbuffer);
106 void RedrawPlayfield(boolean force_redraw, int x, int y, int width, int height)
108 if (game_status == GAME_MODE_PLAYING && !game.envelope_active)
114 width = gfx.sxsize + 2 * TILEX;
115 height = gfx.sysize + 2 * TILEY;
118 if (force_redraw || setup.direct_draw)
121 int x1 = (x - SX) / TILEX, y1 = (y - SY) / TILEY;
122 int x2 = (x - SX + width) / TILEX, y2 = (y - SY + height) / TILEY;
124 if (setup.direct_draw)
125 SetDrawtoField(DRAW_BACKBUFFER);
127 for (xx = BX1; xx <= BX2; xx++)
128 for (yy = BY1; yy <= BY2; yy++)
129 if (xx >= x1 && xx <= x2 && yy >= y1 && yy <= y2)
130 DrawScreenField(xx, yy);
133 if (setup.direct_draw)
134 SetDrawtoField(DRAW_DIRECT);
137 if (setup.soft_scrolling)
139 int fx = FX, fy = FY;
141 fx += (ScreenMovDir & (MV_LEFT|MV_RIGHT) ? ScreenGfxPos : 0);
142 fy += (ScreenMovDir & (MV_UP|MV_DOWN) ? ScreenGfxPos : 0);
144 BlitBitmap(fieldbuffer, backbuffer, fx,fy, SXSIZE,SYSIZE, SX,SY);
148 BlitBitmap(drawto, window, x, y, width, height, x, y);
154 DrawBuffer *buffer = (drawto_field == window ? backbuffer : drawto_field);
156 if (setup.direct_draw && game_status == GAME_MODE_PLAYING)
157 redraw_mask &= ~REDRAW_MAIN;
159 if (redraw_mask & REDRAW_TILES && redraw_tiles > REDRAWTILES_THRESHOLD)
160 redraw_mask |= REDRAW_FIELD;
162 if (redraw_mask & REDRAW_FIELD)
163 redraw_mask &= ~REDRAW_TILES;
165 if (redraw_mask == REDRAW_NONE)
168 if (global.fps_slowdown && game_status == GAME_MODE_PLAYING)
170 static boolean last_frame_skipped = FALSE;
171 boolean skip_even_when_not_scrolling = TRUE;
172 boolean just_scrolling = (ScreenMovDir != 0);
173 boolean verbose = FALSE;
175 if (global.fps_slowdown_factor > 1 &&
176 (FrameCounter % global.fps_slowdown_factor) &&
177 (just_scrolling || skip_even_when_not_scrolling))
179 redraw_mask &= ~REDRAW_MAIN;
181 last_frame_skipped = TRUE;
184 printf("FRAME SKIPPED\n");
188 if (last_frame_skipped)
189 redraw_mask |= REDRAW_FIELD;
191 last_frame_skipped = FALSE;
194 printf("frame not skipped\n");
198 /* synchronize X11 graphics at this point; if we would synchronize the
199 display immediately after the buffer switching (after the XFlush),
200 this could mean that we have to wait for the graphics to complete,
201 although we could go on doing calculations for the next frame */
205 if (redraw_mask & REDRAW_ALL)
207 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
211 if (redraw_mask & REDRAW_FIELD)
213 if (game_status != GAME_MODE_PLAYING ||
214 redraw_mask & REDRAW_FROM_BACKBUFFER)
216 BlitBitmap(backbuffer, window,
217 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE, REAL_SX, REAL_SY);
221 int fx = FX, fy = FY;
223 if (setup.soft_scrolling)
225 fx += (ScreenMovDir & (MV_LEFT | MV_RIGHT) ? ScreenGfxPos : 0);
226 fy += (ScreenMovDir & (MV_UP | MV_DOWN) ? ScreenGfxPos : 0);
229 if (setup.soft_scrolling ||
230 ABS(ScreenMovPos) + ScrollStepSize == TILEX ||
231 ABS(ScreenMovPos) == ScrollStepSize ||
232 redraw_tiles > REDRAWTILES_THRESHOLD)
234 BlitBitmap(buffer, window, fx, fy, SXSIZE, SYSIZE, SX, SY);
238 printf("redrawing all (ScreenGfxPos == %d) because %s\n",
240 (setup.soft_scrolling ?
241 "setup.soft_scrolling" :
242 ABS(ScreenGfxPos) + ScrollStepSize == TILEX ?
243 "ABS(ScreenGfxPos) + ScrollStepSize == TILEX" :
244 ABS(ScreenGfxPos) == ScrollStepSize ?
245 "ABS(ScreenGfxPos) == ScrollStepSize" :
246 "redraw_tiles > REDRAWTILES_THRESHOLD"));
252 redraw_mask &= ~REDRAW_MAIN;
255 if (redraw_mask & REDRAW_DOORS)
257 if (redraw_mask & REDRAW_DOOR_1)
258 BlitBitmap(backbuffer, window, DX, DY, DXSIZE, DYSIZE, DX, DY);
259 if (redraw_mask & REDRAW_DOOR_2)
261 if ((redraw_mask & REDRAW_DOOR_2) == REDRAW_DOOR_2)
262 BlitBitmap(backbuffer, window, VX,VY, VXSIZE,VYSIZE, VX,VY);
265 if (redraw_mask & REDRAW_VIDEO_1)
266 BlitBitmap(backbuffer, window,
267 VX+VIDEO_DISPLAY1_XPOS,VY+VIDEO_DISPLAY1_YPOS,
268 VIDEO_DISPLAY_XSIZE,VIDEO_DISPLAY_YSIZE,
269 VX+VIDEO_DISPLAY1_XPOS,VY+VIDEO_DISPLAY1_YPOS);
270 if (redraw_mask & REDRAW_VIDEO_2)
271 BlitBitmap(backbuffer, window,
272 VX+VIDEO_DISPLAY2_XPOS,VY+VIDEO_DISPLAY2_YPOS,
273 VIDEO_DISPLAY_XSIZE,VIDEO_DISPLAY_YSIZE,
274 VX+VIDEO_DISPLAY2_XPOS,VY+VIDEO_DISPLAY2_YPOS);
275 if (redraw_mask & REDRAW_VIDEO_3)
276 BlitBitmap(backbuffer, window,
277 VX+VIDEO_CONTROL_XPOS,VY+VIDEO_CONTROL_YPOS,
278 VIDEO_CONTROL_XSIZE,VIDEO_CONTROL_YSIZE,
279 VX+VIDEO_CONTROL_XPOS,VY+VIDEO_CONTROL_YPOS);
283 if (redraw_mask & REDRAW_DOOR_3)
284 BlitBitmap(backbuffer, window, EX, EY, EXSIZE, EYSIZE, EX, EY);
286 redraw_mask &= ~REDRAW_DOORS;
289 if (redraw_mask & REDRAW_MICROLEVEL)
291 BlitBitmap(backbuffer, window, SX, SY + 10 * TILEY, SXSIZE, 7 * TILEY,
292 SX, SY + 10 * TILEY);
294 redraw_mask &= ~REDRAW_MICROLEVEL;
297 if (redraw_mask & REDRAW_TILES)
299 for (x = 0; x < SCR_FIELDX; x++)
300 for (y =0 ; y < SCR_FIELDY; y++)
301 if (redraw[redraw_x1 + x][redraw_y1 + y])
302 BlitBitmap(buffer, window,
303 FX + x * TILEX, FX + y * TILEY, TILEX, TILEY,
304 SX + x * TILEX, SY + y * TILEY);
307 if (redraw_mask & REDRAW_FPS) /* display frames per second */
312 sprintf(info1, " (only every %d. frame)", global.fps_slowdown_factor);
313 if (!global.fps_slowdown)
316 sprintf(text, "%.1f fps%s", global.frames_per_second, info1);
317 DrawTextExt(window, SX, SY, text, FONT_TEXT_2, BLIT_OPAQUE);
322 for (x = 0; x < MAX_BUF_XSIZE; x++)
323 for (y = 0; y < MAX_BUF_YSIZE; y++)
326 redraw_mask = REDRAW_NONE;
332 long fading_delay = 300;
334 if (setup.fading && (redraw_mask & REDRAW_FIELD))
341 ClearRectangle(window, REAL_SX,REAL_SY,FULL_SXSIZE,FULL_SYSIZE);
344 for (i = 0; i < 2 * FULL_SYSIZE; i++)
346 for (y = 0; y < FULL_SYSIZE; y++)
348 BlitBitmap(backbuffer, window,
349 REAL_SX,REAL_SY+i, FULL_SXSIZE,1, REAL_SX,REAL_SY+i);
357 for (i = 1; i < FULL_SYSIZE; i+=2)
358 BlitBitmap(backbuffer, window,
359 REAL_SX,REAL_SY+i, FULL_SXSIZE,1, REAL_SX,REAL_SY+i);
365 SetClipOrigin(clip_gc[PIX_FADEMASK], 0, 0);
366 BlitBitmapMasked(backbuffer, window,
367 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
372 SetClipOrigin(clip_gc[PIX_FADEMASK], -1, -1);
373 BlitBitmapMasked(backbuffer, window,
374 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
379 SetClipOrigin(clip_gc[PIX_FADEMASK], 0, -1);
380 BlitBitmapMasked(backbuffer, window,
381 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
386 SetClipOrigin(clip_gc[PIX_FADEMASK], -1, 0);
387 BlitBitmapMasked(backbuffer, window,
388 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
393 redraw_mask &= ~REDRAW_MAIN;
400 void SetMainBackgroundImage(int graphic)
402 SetMainBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
403 graphic_info[graphic].bitmap ?
404 graphic_info[graphic].bitmap :
405 graphic_info[IMG_BACKGROUND].bitmap);
408 void SetDoorBackgroundImage(int graphic)
410 SetDoorBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
411 graphic_info[graphic].bitmap ?
412 graphic_info[graphic].bitmap :
413 graphic_info[IMG_BACKGROUND].bitmap);
416 void DrawBackground(int dest_x, int dest_y, int width, int height)
418 ClearRectangleOnBackground(backbuffer, dest_x, dest_y, width, height);
420 redraw_mask |= REDRAW_FIELD;
425 DrawBackground(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
427 if (setup.soft_scrolling && game_status == GAME_MODE_PLAYING)
429 ClearRectangle(fieldbuffer, 0, 0, FXSIZE, FYSIZE);
430 SetDrawtoField(DRAW_BUFFERED);
433 SetDrawtoField(DRAW_BACKBUFFER);
435 if (setup.direct_draw && game_status == GAME_MODE_PLAYING)
437 ClearRectangle(window, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
438 SetDrawtoField(DRAW_DIRECT);
442 void MarkTileDirty(int x, int y)
444 int xx = redraw_x1 + x;
445 int yy = redraw_y1 + y;
450 redraw[xx][yy] = TRUE;
451 redraw_mask |= REDRAW_TILES;
454 void SetBorderElement()
458 BorderElement = EL_EMPTY;
460 for (y = 0; y < lev_fieldy && BorderElement == EL_EMPTY; y++)
462 for (x = 0; x < lev_fieldx; x++)
464 if (!IS_INDESTRUCTIBLE(Feld[x][y]))
465 BorderElement = EL_STEELWALL;
467 if (y != 0 && y != lev_fieldy - 1 && x != lev_fieldx - 1)
473 void SetRandomAnimationValue(int x, int y)
475 gfx.anim_random_frame = GfxRandom[x][y];
478 inline int getGraphicAnimationFrame(int graphic, int sync_frame)
480 /* animation synchronized with global frame counter, not move position */
481 if (graphic_info[graphic].anim_global_sync || sync_frame < 0)
482 sync_frame = FrameCounter;
484 return getAnimationFrame(graphic_info[graphic].anim_frames,
485 graphic_info[graphic].anim_delay,
486 graphic_info[graphic].anim_mode,
487 graphic_info[graphic].anim_start_frame,
491 inline void DrawGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
492 int graphic, int sync_frame, int mask_mode)
494 int frame = getGraphicAnimationFrame(graphic, sync_frame);
496 if (mask_mode == USE_MASKING)
497 DrawGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
499 DrawGraphicExt(dst_bitmap, x, y, graphic, frame);
502 inline void DrawGraphicAnimation(int x, int y, int graphic)
504 int lx = LEVELX(x), ly = LEVELY(y);
506 if (!IN_SCR_FIELD(x, y))
509 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
510 graphic, GfxFrame[lx][ly], NO_MASKING);
514 void DrawLevelGraphicAnimation(int x, int y, int graphic)
516 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
519 void DrawLevelElementAnimation(int x, int y, int element)
522 int graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
524 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
526 DrawGraphicAnimation(SCREENX(x), SCREENY(y), el2img(element));
530 inline void DrawLevelGraphicAnimationIfNeeded(int x, int y, int graphic)
532 int sx = SCREENX(x), sy = SCREENY(y);
534 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
537 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
540 DrawGraphicAnimation(sx, sy, graphic);
542 if (GFX_CRUMBLED(Feld[x][y]))
543 DrawLevelFieldCrumbledSand(x, y);
546 void DrawLevelElementAnimationIfNeeded(int x, int y, int element)
548 int sx = SCREENX(x), sy = SCREENY(y);
551 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
554 graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
556 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
559 DrawGraphicAnimation(sx, sy, graphic);
561 if (GFX_CRUMBLED(element))
562 DrawLevelFieldCrumbledSand(x, y);
565 static int getPlayerGraphic(struct PlayerInfo *player, int move_dir)
567 if (player->use_murphy_graphic)
569 /* this works only because currently only one player can be "murphy" ... */
570 static int last_horizontal_dir = MV_LEFT;
571 int graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, move_dir);
573 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
574 last_horizontal_dir = move_dir;
576 if (graphic == IMG_SP_MURPHY) /* undefined => use special graphic */
578 int direction = (player->is_snapping ? move_dir : last_horizontal_dir);
580 graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, direction);
586 return el_act_dir2img(player->element_nr, player->GfxAction, move_dir);
589 static boolean equalGraphics(int graphic1, int graphic2)
591 struct GraphicInfo *g1 = &graphic_info[graphic1];
592 struct GraphicInfo *g2 = &graphic_info[graphic2];
594 return (g1->bitmap == g2->bitmap &&
595 g1->src_x == g2->src_x &&
596 g1->src_y == g2->src_y &&
597 g1->anim_frames == g2->anim_frames &&
598 g1->anim_delay == g2->anim_delay &&
599 g1->anim_mode == g2->anim_mode);
602 void DrawAllPlayers()
606 for (i = 0; i < MAX_PLAYERS; i++)
607 if (stored_player[i].active)
608 DrawPlayer(&stored_player[i]);
611 void DrawPlayerField(int x, int y)
613 if (!IS_PLAYER(x, y))
616 DrawPlayer(PLAYERINFO(x, y));
619 void DrawPlayer(struct PlayerInfo *player)
623 int move_dir = player->MovDir;
625 int last_jx = player->last_jx;
626 int last_jy = player->last_jy;
627 int next_jx = jx + (jx - last_jx);
628 int next_jy = jy + (jy - last_jy);
629 boolean player_is_moving = (last_jx != jx || last_jy != jy ? TRUE : FALSE);
631 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? +1 : 0);
632 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? +1 : 0);
633 int last_jx = (player->is_moving ? jx - dx : jx);
634 int last_jy = (player->is_moving ? jy - dy : jy);
635 int next_jx = jx + dx;
636 int next_jy = jy + dy;
637 boolean player_is_moving = (player->MovPos ? TRUE : FALSE);
639 int sx = SCREENX(jx), sy = SCREENY(jy);
640 int sxx = 0, syy = 0;
641 int element = Feld[jx][jy], last_element = Feld[last_jx][last_jy];
643 int action = ACTION_DEFAULT;
644 int last_player_graphic = getPlayerGraphic(player, move_dir);
645 int last_player_frame = player->Frame;
648 if (!player->active || !IN_SCR_FIELD(SCREENX(last_jx), SCREENY(last_jy)))
652 if (!IN_LEV_FIELD(jx, jy))
654 printf("DrawPlayerField(): x = %d, y = %d\n",jx,jy);
655 printf("DrawPlayerField(): sx = %d, sy = %d\n",sx,sy);
656 printf("DrawPlayerField(): This should never happen!\n");
661 if (element == EL_EXPLOSION)
664 action = (player->is_pushing ? ACTION_PUSHING :
665 player->is_digging ? ACTION_DIGGING :
666 player->is_collecting ? ACTION_COLLECTING :
667 player->is_moving ? ACTION_MOVING :
668 player->is_snapping ? ACTION_SNAPPING :
669 player->is_dropping ? ACTION_DROPPING :
670 player->is_waiting ? player->action_waiting : ACTION_DEFAULT);
672 InitPlayerGfxAnimation(player, action, move_dir);
674 /* ----------------------------------------------------------------------- */
675 /* draw things in the field the player is leaving, if needed */
676 /* ----------------------------------------------------------------------- */
679 if (player->is_moving)
681 if (player_is_moving)
684 if (Back[last_jx][last_jy] && IS_DRAWABLE(last_element))
686 DrawLevelElement(last_jx, last_jy, Back[last_jx][last_jy]);
688 if (last_element == EL_DYNAMITE_ACTIVE ||
689 last_element == EL_SP_DISK_RED_ACTIVE)
690 DrawDynamite(last_jx, last_jy);
692 DrawLevelFieldThruMask(last_jx, last_jy);
694 else if (last_element == EL_DYNAMITE_ACTIVE ||
695 last_element == EL_SP_DISK_RED_ACTIVE)
696 DrawDynamite(last_jx, last_jy);
698 DrawLevelField(last_jx, last_jy);
700 if (player->is_pushing && IN_SCR_FIELD(SCREENX(next_jx), SCREENY(next_jy)))
701 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
704 if (!IN_SCR_FIELD(sx, sy))
707 if (setup.direct_draw)
708 SetDrawtoField(DRAW_BUFFERED);
710 /* ----------------------------------------------------------------------- */
711 /* draw things behind the player, if needed */
712 /* ----------------------------------------------------------------------- */
715 DrawLevelElement(jx, jy, Back[jx][jy]);
716 else if (IS_ACTIVE_BOMB(element))
717 DrawLevelElement(jx, jy, EL_EMPTY);
720 if (player_is_moving && GfxElement[jx][jy] != EL_UNDEFINED)
722 if (GFX_CRUMBLED(GfxElement[jx][jy]))
723 DrawLevelFieldCrumbledSandDigging(jx, jy, move_dir, player->StepFrame);
726 int old_element = GfxElement[jx][jy];
727 int old_graphic = el_act_dir2img(old_element, action, move_dir);
728 int frame = getGraphicAnimationFrame(old_graphic, player->StepFrame);
730 DrawGraphic(sx, sy, old_graphic, frame);
735 GfxElement[jx][jy] = EL_UNDEFINED;
737 DrawLevelField(jx, jy);
741 /* ----------------------------------------------------------------------- */
742 /* draw player himself */
743 /* ----------------------------------------------------------------------- */
747 graphic = getPlayerGraphic(player, move_dir);
749 /* in the case of changed player action or direction, prevent the current
750 animation frame from being restarted for identical animations */
751 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
752 player->Frame = last_player_frame;
756 if (player->use_murphy_graphic)
758 static int last_horizontal_dir = MV_LEFT;
760 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
761 last_horizontal_dir = move_dir;
763 graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, move_dir);
765 if (graphic == IMG_SP_MURPHY) /* undefined => use special graphic */
767 int direction = (player->is_snapping ? move_dir : last_horizontal_dir);
769 graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, direction);
773 graphic = el_act_dir2img(player->element_nr, player->GfxAction, move_dir);
777 frame = getGraphicAnimationFrame(graphic, player->Frame);
781 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
782 sxx = player->GfxPos;
784 syy = player->GfxPos;
787 if (!setup.soft_scrolling && ScreenMovPos)
790 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
792 if (SHIELD_ON(player))
794 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
795 IMG_SHIELD_NORMAL_ACTIVE);
796 int frame = getGraphicAnimationFrame(graphic, -1);
798 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
801 /* ----------------------------------------------------------------------- */
802 /* draw things the player is pushing, if needed */
803 /* ----------------------------------------------------------------------- */
806 printf("::: %d, %d [%d, %d] [%d]\n",
807 player->is_pushing, player_is_moving, player->GfxAction,
808 player->is_moving, player_is_moving);
812 if (player->is_pushing && player->is_moving)
814 if (player->is_pushing && player_is_moving)
817 int px = SCREENX(next_jx), py = SCREENY(next_jy);
819 if (Back[next_jx][next_jy])
820 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
822 if ((sxx || syy) && element == EL_SOKOBAN_OBJECT)
823 DrawGraphicShiftedThruMask(px, py, sxx, syy, IMG_SOKOBAN_OBJECT, 0,
827 int element = MovingOrBlocked2Element(next_jx, next_jy);
828 int graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
830 int frame = getGraphicAnimationFrame(graphic, player->StepFrame);
832 int frame = getGraphicAnimationFrame(graphic, player->Frame);
835 DrawGraphicShifted(px, py, sxx, syy, graphic, frame,
836 NO_CUTTING, NO_MASKING);
840 /* ----------------------------------------------------------------------- */
841 /* draw things in front of player (active dynamite or dynabombs) */
842 /* ----------------------------------------------------------------------- */
844 if (IS_ACTIVE_BOMB(element))
846 graphic = el2img(element);
847 frame = getGraphicAnimationFrame(graphic, GfxFrame[jx][jy]);
849 if (game.emulation == EMU_SUPAPLEX)
850 DrawGraphic(sx, sy, IMG_SP_DISK_RED, frame);
852 DrawGraphicThruMask(sx, sy, graphic, frame);
855 if (player_is_moving && last_element == EL_EXPLOSION)
857 int graphic = el_act2img(GfxElement[last_jx][last_jy], ACTION_EXPLODING);
858 int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
859 int phase = ExplodePhase[last_jx][last_jy] - 1;
860 int frame = getGraphicAnimationFrame(graphic, phase - delay);
863 DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy), graphic, frame);
866 /* ----------------------------------------------------------------------- */
867 /* draw elements the player is just walking/passing through/under */
868 /* ----------------------------------------------------------------------- */
870 /* handle the field the player is leaving ... */
871 if (player_is_moving && IS_ACCESSIBLE_INSIDE(last_element))
872 DrawLevelField(last_jx, last_jy);
873 else if (player_is_moving && IS_ACCESSIBLE_UNDER(last_element))
874 DrawLevelFieldThruMask(last_jx, last_jy);
876 /* ... and the field the player is entering */
877 if (IS_ACCESSIBLE_INSIDE(element))
878 DrawLevelField(jx, jy);
879 else if (IS_ACCESSIBLE_UNDER(element))
880 DrawLevelFieldThruMask(jx, jy);
882 if (setup.direct_draw)
884 int dest_x = SX + SCREENX(MIN(jx, last_jx)) * TILEX;
885 int dest_y = SY + SCREENY(MIN(jy, last_jy)) * TILEY;
886 int x_size = TILEX * (1 + ABS(jx - last_jx));
887 int y_size = TILEY * (1 + ABS(jy - last_jy));
889 BlitBitmap(drawto_field, window,
890 dest_x, dest_y, x_size, y_size, dest_x, dest_y);
891 SetDrawtoField(DRAW_DIRECT);
894 MarkTileDirty(sx, sy);
897 void getGraphicSource(int graphic, int frame, Bitmap **bitmap, int *x, int *y)
899 struct GraphicInfo *g = &graphic_info[graphic];
903 if (g->offset_y == 0) /* frames are ordered horizontally */
905 int max_width = g->anim_frames_per_line * g->width;
907 *x = (g->src_x + frame * g->offset_x) % max_width;
908 *y = g->src_y + (g->src_x + frame * g->offset_x) / max_width * g->height;
910 else if (g->offset_x == 0) /* frames are ordered vertically */
912 int max_height = g->anim_frames_per_line * g->height;
914 *x = g->src_x + (g->src_y + frame * g->offset_y) / max_height * g->width;
915 *y = (g->src_y + frame * g->offset_y) % max_height;
917 else /* frames are ordered diagonally */
919 *x = g->src_x + frame * g->offset_x;
920 *y = g->src_y + frame * g->offset_y;
924 void DrawGraphic(int x, int y, int graphic, int frame)
927 if (!IN_SCR_FIELD(x, y))
929 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
930 printf("DrawGraphic(): This should never happen!\n");
935 DrawGraphicExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic, frame);
939 void DrawGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
945 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
946 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
949 void DrawGraphicThruMask(int x, int y, int graphic, int frame)
952 if (!IN_SCR_FIELD(x, y))
954 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
955 printf("DrawGraphicThruMask(): This should never happen!\n");
960 DrawGraphicThruMaskExt(drawto_field, FX + x * TILEX, FY + y *TILEY, graphic,
965 void DrawGraphicThruMaskExt(DrawBuffer *d, int dest_x, int dest_y, int graphic,
973 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
974 drawing_gc = src_bitmap->stored_clip_gc;
976 GC drawing_gc = src_bitmap->stored_clip_gc;
977 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
978 int src_x = graphic_info[graphic].src_x;
979 int src_y = graphic_info[graphic].src_y;
980 int offset_x = graphic_info[graphic].offset_x;
981 int offset_y = graphic_info[graphic].offset_y;
983 src_x += frame * offset_x;
984 src_y += frame * offset_y;
988 SetClipOrigin(src_bitmap, drawing_gc, dest_x - src_x, dest_y - src_y);
989 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX, TILEY, dest_x, dest_y);
992 void DrawMiniGraphic(int x, int y, int graphic)
994 DrawMiniGraphicExt(drawto, SX + x * MINI_TILEX,SY + y * MINI_TILEY, graphic);
995 MarkTileDirty(x / 2, y / 2);
998 void getMiniGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
1000 struct GraphicInfo *g = &graphic_info[graphic];
1001 int mini_startx = 0;
1002 int mini_starty = g->bitmap->height * 2 / 3;
1004 *bitmap = g->bitmap;
1005 *x = mini_startx + g->src_x / 2;
1006 *y = mini_starty + g->src_y / 2;
1009 void DrawMiniGraphicExt(DrawBuffer *d, int x, int y, int graphic)
1014 getMiniGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
1015 BlitBitmap(src_bitmap, d, src_x, src_y, MINI_TILEX, MINI_TILEY, x, y);
1018 void DrawGraphicShifted(int x, int y, int dx, int dy, int graphic, int frame,
1019 int cut_mode, int mask_mode)
1024 int width = TILEX, height = TILEY;
1030 DrawGraphic(x, y, graphic, frame);
1034 if (dx || dy) /* shifted graphic */
1036 if (x < BX1) /* object enters playfield from the left */
1043 else if (x > BX2) /* object enters playfield from the right */
1049 else if (x==BX1 && dx < 0) /* object leaves playfield to the left */
1055 else if (x==BX2 && dx > 0) /* object leaves playfield to the right */
1057 else if (dx) /* general horizontal movement */
1058 MarkTileDirty(x + SIGN(dx), y);
1060 if (y < BY1) /* object enters playfield from the top */
1062 if (cut_mode==CUT_BELOW) /* object completely above top border */
1070 else if (y > BY2) /* object enters playfield from the bottom */
1076 else if (y==BY1 && dy < 0) /* object leaves playfield to the top */
1082 else if (dy > 0 && cut_mode == CUT_ABOVE)
1084 if (y == BY2) /* object completely above bottom border */
1090 MarkTileDirty(x, y + 1);
1091 } /* object leaves playfield to the bottom */
1092 else if (dy > 0 && (y == BY2 || cut_mode == CUT_BELOW))
1094 else if (dy) /* general vertical movement */
1095 MarkTileDirty(x, y + SIGN(dy));
1099 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1101 src_bitmap = graphic_info[graphic].bitmap;
1102 src_x = graphic_info[graphic].src_x;
1103 src_y = graphic_info[graphic].src_y;
1104 offset_x = graphic_info[graphic].offset_x;
1105 offset_y = graphic_info[graphic].offset_y;
1107 src_x += frame * offset_x;
1108 src_y += frame * offset_y;
1111 drawing_gc = src_bitmap->stored_clip_gc;
1116 dest_x = FX + x * TILEX + dx;
1117 dest_y = FY + y * TILEY + dy;
1120 if (!IN_SCR_FIELD(x,y))
1122 printf("DrawGraphicShifted(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
1123 printf("DrawGraphicShifted(): This should never happen!\n");
1128 if (mask_mode == USE_MASKING)
1130 SetClipOrigin(src_bitmap, drawing_gc, dest_x - src_x, dest_y - src_y);
1131 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1135 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1138 MarkTileDirty(x, y);
1141 void DrawGraphicShiftedThruMask(int x, int y, int dx, int dy, int graphic,
1142 int frame, int cut_mode)
1144 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, USE_MASKING);
1147 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
1148 int cut_mode, int mask_mode)
1150 int lx = LEVELX(x), ly = LEVELY(y);
1154 if (IN_LEV_FIELD(lx, ly))
1156 SetRandomAnimationValue(lx, ly);
1158 graphic = el_act_dir2img(element, GfxAction[lx][ly], GfxDir[lx][ly]);
1159 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1161 else /* border element */
1163 graphic = el2img(element);
1164 frame = getGraphicAnimationFrame(graphic, -1);
1167 if (element == EL_EXPANDABLE_WALL)
1169 boolean left_stopped = FALSE, right_stopped = FALSE;
1171 if (!IN_LEV_FIELD(lx - 1, ly) || IS_WALL(Feld[lx - 1][ly]))
1172 left_stopped = TRUE;
1173 if (!IN_LEV_FIELD(lx + 1, ly) || IS_WALL(Feld[lx + 1][ly]))
1174 right_stopped = TRUE;
1176 if (left_stopped && right_stopped)
1178 else if (left_stopped)
1180 graphic = IMG_EXPANDABLE_WALL_GROWING_RIGHT;
1181 frame = graphic_info[graphic].anim_frames - 1;
1183 else if (right_stopped)
1185 graphic = IMG_EXPANDABLE_WALL_GROWING_LEFT;
1186 frame = graphic_info[graphic].anim_frames - 1;
1191 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, mask_mode);
1192 else if (mask_mode == USE_MASKING)
1193 DrawGraphicThruMask(x, y, graphic, frame);
1195 DrawGraphic(x, y, graphic, frame);
1198 void DrawLevelElementExt(int x, int y, int dx, int dy, int element,
1199 int cut_mode, int mask_mode)
1201 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1202 DrawScreenElementExt(SCREENX(x), SCREENY(y), dx, dy, element,
1203 cut_mode, mask_mode);
1206 void DrawScreenElementShifted(int x, int y, int dx, int dy, int element,
1209 DrawScreenElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1212 void DrawLevelElementShifted(int x, int y, int dx, int dy, int element,
1215 DrawLevelElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1218 void DrawLevelElementThruMask(int x, int y, int element)
1220 DrawLevelElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1223 void DrawLevelFieldThruMask(int x, int y)
1225 DrawLevelElementExt(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
1228 #define TILE_GFX_ELEMENT(x, y) \
1229 (GfxElement[x][y] != EL_UNDEFINED && Feld[x][y] != EL_EXPLOSION ? \
1230 GfxElement[x][y] : Feld[x][y])
1232 static void DrawLevelFieldCrumbledSandExt(int x, int y, int graphic, int frame)
1236 int sx = SCREENX(x), sy = SCREENY(y);
1238 int width, height, cx, cy, i;
1240 int crumbled_border_size = graphic_info[graphic].border_size;
1242 int snip = TILEX / 8; /* number of border pixels from "crumbled graphic" */
1244 static int xy[4][2] =
1253 if (x == 0 && y == 7)
1254 printf("::: %d, %d [%d]\n", GfxElement[x][y], Feld[x][y],
1255 crumbled_border_size);
1258 if (!IN_LEV_FIELD(x, y))
1261 element = TILE_GFX_ELEMENT(x, y);
1263 /* crumble field itself */
1264 if (GFX_CRUMBLED(element) && !IS_MOVING(x, y))
1266 if (!IN_SCR_FIELD(sx, sy))
1269 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1271 for (i = 0; i < 4; i++)
1273 int xx = x + xy[i][0];
1274 int yy = y + xy[i][1];
1277 element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1280 element = (IN_LEV_FIELD(xx, yy) ? Feld[xx][yy] : BorderElement);
1283 /* check if neighbour field is of same type */
1284 if (GFX_CRUMBLED(element) && !IS_MOVING(xx, yy))
1288 if (Feld[x][y] == EL_CUSTOM_START + 123)
1289 printf("::: crumble [%d] THE CHAOS ENGINE (%d, %d): %d, %d\n",
1290 i, Feld[x][y], element,
1291 GFX_CRUMBLED(element), IS_MOVING(x, y));
1294 if (i == 1 || i == 2)
1296 width = crumbled_border_size;
1298 cx = (i == 2 ? TILEX - crumbled_border_size : 0);
1304 height = crumbled_border_size;
1306 cy = (i == 3 ? TILEY - crumbled_border_size : 0);
1309 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1310 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
1313 MarkTileDirty(sx, sy);
1315 else /* crumble neighbour fields */
1318 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1321 for (i = 0; i < 4; i++)
1323 int xx = x + xy[i][0];
1324 int yy = y + xy[i][1];
1325 int sxx = sx + xy[i][0];
1326 int syy = sy + xy[i][1];
1329 if (!IN_LEV_FIELD(xx, yy) ||
1330 !IN_SCR_FIELD(sxx, syy) ||
1334 element = TILE_GFX_ELEMENT(xx, yy);
1336 if (!GFX_CRUMBLED(element))
1339 if (!IN_LEV_FIELD(xx, yy) ||
1340 !IN_SCR_FIELD(sxx, syy) ||
1341 !GFX_CRUMBLED(Feld[xx][yy]) ||
1347 graphic = el_act2crm(Feld[xx][yy], ACTION_DEFAULT);
1348 crumbled_border_size = graphic_info[graphic].border_size;
1350 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1353 if (i == 1 || i == 2)
1355 width = crumbled_border_size;
1357 cx = (i == 1 ? TILEX - crumbled_border_size : 0);
1363 height = crumbled_border_size;
1365 cy = (i == 0 ? TILEY - crumbled_border_size : 0);
1368 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1369 width, height, FX + sxx * TILEX + cx, FY + syy * TILEY + cy);
1371 MarkTileDirty(sxx, syy);
1376 void DrawLevelFieldCrumbledSand(int x, int y)
1381 if (!IN_LEV_FIELD(x, y))
1384 graphic = el_act2crm(Feld[x][y], ACTION_DEFAULT);
1386 DrawLevelFieldCrumbledSandExt(x, y, graphic, 0);
1388 DrawLevelFieldCrumbledSandExt(x, y, IMG_SAND_CRUMBLED, 0);
1392 void DrawLevelFieldCrumbledSandDigging(int x, int y, int direction,
1396 int graphic1 = el_act_dir2img(GfxElement[x][y], ACTION_DIGGING, direction);
1397 int graphic2 = el_act_dir2crm(GfxElement[x][y], ACTION_DIGGING, direction);
1399 int graphic1 = el_act_dir2img(EL_SAND, ACTION_DIGGING, direction);
1400 int graphic2 = el_act_dir2img(EL_SAND_CRUMBLED, ACTION_DIGGING, direction);
1402 int frame1 = getGraphicAnimationFrame(graphic1, step_frame);
1403 int frame2 = getGraphicAnimationFrame(graphic2, step_frame);
1404 int sx = SCREENX(x), sy = SCREENY(y);
1406 DrawGraphic(sx, sy, graphic1, frame1);
1407 DrawLevelFieldCrumbledSandExt(x, y, graphic2, frame2);
1410 void DrawLevelFieldCrumbledSandNeighbours(int x, int y)
1412 int sx = SCREENX(x), sy = SCREENY(y);
1413 static int xy[4][2] =
1422 for (i = 0; i < 4; i++)
1424 int xx = x + xy[i][0];
1425 int yy = y + xy[i][1];
1426 int sxx = sx + xy[i][0];
1427 int syy = sy + xy[i][1];
1429 if (!IN_LEV_FIELD(xx, yy) ||
1430 !IN_SCR_FIELD(sxx, syy) ||
1431 !GFX_CRUMBLED(Feld[xx][yy]) ||
1435 DrawLevelField(xx, yy);
1439 static int getBorderElement(int x, int y)
1443 { EL_STEELWALL_TOPLEFT, EL_INVISIBLE_STEELWALL_TOPLEFT },
1444 { EL_STEELWALL_TOPRIGHT, EL_INVISIBLE_STEELWALL_TOPRIGHT },
1445 { EL_STEELWALL_BOTTOMLEFT, EL_INVISIBLE_STEELWALL_BOTTOMLEFT },
1446 { EL_STEELWALL_BOTTOMRIGHT, EL_INVISIBLE_STEELWALL_BOTTOMRIGHT },
1447 { EL_STEELWALL_VERTICAL, EL_INVISIBLE_STEELWALL_VERTICAL },
1448 { EL_STEELWALL_HORIZONTAL, EL_INVISIBLE_STEELWALL_HORIZONTAL },
1449 { EL_STEELWALL, EL_INVISIBLE_STEELWALL }
1451 int steel_type = (BorderElement == EL_STEELWALL ? 0 : 1);
1452 int steel_position = (x == -1 && y == -1 ? 0 :
1453 x == lev_fieldx && y == -1 ? 1 :
1454 x == -1 && y == lev_fieldy ? 2 :
1455 x == lev_fieldx && y == lev_fieldy ? 3 :
1456 x == -1 || x == lev_fieldx ? 4 :
1457 y == -1 || y == lev_fieldy ? 5 : 6);
1459 return border[steel_position][steel_type];
1462 void DrawScreenElement(int x, int y, int element)
1464 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
1465 DrawLevelFieldCrumbledSand(LEVELX(x), LEVELY(y));
1468 void DrawLevelElement(int x, int y, int element)
1470 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1471 DrawScreenElement(SCREENX(x), SCREENY(y), element);
1474 void DrawScreenField(int x, int y)
1476 int lx = LEVELX(x), ly = LEVELY(y);
1477 int element, content;
1479 if (!IN_LEV_FIELD(lx, ly))
1481 if (lx < -1 || lx > lev_fieldx || ly < -1 || ly > lev_fieldy)
1484 element = getBorderElement(lx, ly);
1486 DrawScreenElement(x, y, element);
1490 element = Feld[lx][ly];
1491 content = Store[lx][ly];
1493 if (IS_MOVING(lx, ly))
1495 int horiz_move = (MovDir[lx][ly] == MV_LEFT || MovDir[lx][ly] == MV_RIGHT);
1496 boolean cut_mode = NO_CUTTING;
1498 if (element == EL_QUICKSAND_EMPTYING ||
1499 element == EL_MAGIC_WALL_EMPTYING ||
1500 element == EL_BD_MAGIC_WALL_EMPTYING ||
1501 element == EL_AMOEBA_DROPPING)
1502 cut_mode = CUT_ABOVE;
1503 else if (element == EL_QUICKSAND_FILLING ||
1504 element == EL_MAGIC_WALL_FILLING ||
1505 element == EL_BD_MAGIC_WALL_FILLING)
1506 cut_mode = CUT_BELOW;
1508 if (cut_mode == CUT_ABOVE)
1509 DrawScreenElementShifted(x, y, 0, 0, element, NO_CUTTING);
1511 DrawScreenElement(x, y, EL_EMPTY);
1514 DrawScreenElementShifted(x, y, MovPos[lx][ly], 0, element, NO_CUTTING);
1515 else if (cut_mode == NO_CUTTING)
1516 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], element, cut_mode);
1518 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], content, cut_mode);
1520 if (content == EL_ACID)
1522 int dir = MovDir[lx][ly];
1523 int newlx = lx + (dir == MV_LEFT ? -1 : dir == MV_RIGHT ? +1 : 0);
1524 int newly = ly + (dir == MV_UP ? -1 : dir == MV_DOWN ? +1 : 0);
1526 DrawLevelElementThruMask(newlx, newly, EL_ACID);
1529 else if (IS_BLOCKED(lx, ly))
1534 boolean cut_mode = NO_CUTTING;
1535 int element_old, content_old;
1537 Blocked2Moving(lx, ly, &oldx, &oldy);
1540 horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
1541 MovDir[oldx][oldy] == MV_RIGHT);
1543 element_old = Feld[oldx][oldy];
1544 content_old = Store[oldx][oldy];
1546 if (element_old == EL_QUICKSAND_EMPTYING ||
1547 element_old == EL_MAGIC_WALL_EMPTYING ||
1548 element_old == EL_BD_MAGIC_WALL_EMPTYING ||
1549 element_old == EL_AMOEBA_DROPPING)
1550 cut_mode = CUT_ABOVE;
1552 DrawScreenElement(x, y, EL_EMPTY);
1555 DrawScreenElementShifted(sx, sy, MovPos[oldx][oldy], 0, element_old,
1557 else if (cut_mode == NO_CUTTING)
1558 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], element_old,
1561 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], content_old,
1564 else if (IS_DRAWABLE(element))
1565 DrawScreenElement(x, y, element);
1567 DrawScreenElement(x, y, EL_EMPTY);
1570 void DrawLevelField(int x, int y)
1572 if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1573 DrawScreenField(SCREENX(x), SCREENY(y));
1574 else if (IS_MOVING(x, y))
1578 Moving2Blocked(x, y, &newx, &newy);
1579 if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
1580 DrawScreenField(SCREENX(newx), SCREENY(newy));
1582 else if (IS_BLOCKED(x, y))
1586 Blocked2Moving(x, y, &oldx, &oldy);
1587 if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
1588 DrawScreenField(SCREENX(oldx), SCREENY(oldy));
1592 void DrawMiniElement(int x, int y, int element)
1596 graphic = el2edimg(element);
1597 DrawMiniGraphic(x, y, graphic);
1600 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
1602 int x = sx + scroll_x, y = sy + scroll_y;
1604 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
1605 DrawMiniElement(sx, sy, EL_EMPTY);
1606 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
1607 DrawMiniElement(sx, sy, Feld[x][y]);
1609 DrawMiniGraphic(sx, sy, el2edimg(getBorderElement(x, y)));
1612 void DrawEnvelopeBackground(int envelope_nr, int startx, int starty,
1613 int x, int y, int xsize, int ysize, int font_nr)
1615 int font_width = getFontWidth(font_nr);
1616 int font_height = getFontHeight(font_nr);
1617 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1620 int dst_x = SX + startx + x * font_width;
1621 int dst_y = SY + starty + y * font_height;
1622 int width = graphic_info[graphic].width;
1623 int height = graphic_info[graphic].height;
1624 int inner_width = MAX(width - 2 * font_width, font_width);
1625 int inner_height = MAX(height - 2 * font_height, font_height);
1626 int inner_sx = (width >= 3 * font_width ? font_width : 0);
1627 int inner_sy = (height >= 3 * font_height ? font_height : 0);
1628 boolean draw_masked = graphic_info[graphic].draw_masked;
1630 getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
1632 if (src_bitmap == NULL || width < font_width || height < font_height)
1634 ClearRectangle(drawto, dst_x, dst_y, font_width, font_height);
1638 src_x += (x == 0 ? 0 : x == xsize - 1 ? width - font_width :
1639 inner_sx + (x - 1) * font_width % inner_width);
1640 src_y += (y == 0 ? 0 : y == ysize - 1 ? height - font_height :
1641 inner_sy + (y - 1) * font_height % inner_height);
1645 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1646 dst_x - src_x, dst_y - src_y);
1647 BlitBitmapMasked(src_bitmap, drawto, src_x, src_y, font_width, font_height,
1651 BlitBitmap(src_bitmap, drawto, src_x, src_y, font_width, font_height,
1655 void AnimateEnvelope(int envelope_nr, int anim_mode, int action)
1657 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1658 boolean draw_masked = graphic_info[graphic].draw_masked;
1659 int mask_mode = (draw_masked ? BLIT_MASKED : BLIT_ON_BACKGROUND);
1660 boolean ffwd_delay = (tape.playing && tape.fast_forward);
1661 boolean no_delay = (tape.index_search);
1662 unsigned long anim_delay = 0;
1663 int frame_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
1664 int anim_delay_value = (no_delay ? 0 : frame_delay_value);
1665 int font_nr = FONT_ENVELOPE_1 + envelope_nr;
1666 int font_width = getFontWidth(font_nr);
1667 int font_height = getFontHeight(font_nr);
1668 int max_xsize = level.envelope_xsize[envelope_nr];
1669 int max_ysize = level.envelope_ysize[envelope_nr];
1670 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize : 0);
1671 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize : 0);
1672 int xend = max_xsize;
1673 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize : 0);
1674 int xstep = (xstart < xend ? 1 : 0);
1675 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
1678 for (x = xstart, y = ystart; x <= xend && y <= yend; x += xstep, y += ystep)
1680 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
1681 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
1682 int sx = (SXSIZE - xsize * font_width) / 2;
1683 int sy = (SYSIZE - ysize * font_height) / 2;
1686 SetDrawtoField(DRAW_BUFFERED);
1688 BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
1690 SetDrawtoField(DRAW_BACKBUFFER);
1692 for (yy = 0; yy < ysize; yy++) for (xx = 0; xx < xsize; xx++)
1693 DrawEnvelopeBackground(envelope_nr, sx,sy, xx,yy, xsize, ysize, font_nr);
1695 DrawTextToTextArea(SX + sx + font_width, SY + sy + font_height,
1696 level.envelope_text[envelope_nr], font_nr, max_xsize,
1697 xsize - 2, ysize - 2, mask_mode);
1699 redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
1702 WaitUntilDelayReached(&anim_delay, anim_delay_value / 2);
1706 void ShowEnvelope(int envelope_nr)
1708 int element = EL_ENVELOPE_1 + envelope_nr;
1709 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1710 int sound_opening = element_info[element].sound[ACTION_OPENING];
1711 int sound_closing = element_info[element].sound[ACTION_CLOSING];
1712 boolean ffwd_delay = (tape.playing && tape.fast_forward);
1713 boolean no_delay = (tape.index_search);
1714 int normal_delay_value = ONE_SECOND_DELAY / (ffwd_delay ? 2 : 1);
1715 int wait_delay_value = (no_delay ? 0 : normal_delay_value);
1716 int anim_mode = graphic_info[graphic].anim_mode;
1717 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
1718 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
1720 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
1722 PlaySoundStereo(sound_opening, SOUND_MIDDLE);
1724 if (anim_mode == ANIM_DEFAULT)
1725 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_OPENING);
1727 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_OPENING);
1730 Delay(wait_delay_value);
1732 WaitForEventToContinue();
1734 PlaySoundStereo(sound_closing, SOUND_MIDDLE);
1736 if (anim_mode != ANIM_NONE)
1737 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_CLOSING);
1739 if (anim_mode == ANIM_DEFAULT)
1740 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_CLOSING);
1742 game.envelope_active = FALSE;
1744 SetDrawtoField(DRAW_BUFFERED);
1746 redraw_mask |= REDRAW_FIELD;
1750 void getMicroGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
1752 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
1753 int mini_startx = src_bitmap->width * 3 / 4;
1754 int mini_starty = src_bitmap->height * 2 / 3;
1755 int src_x = mini_startx + graphic_info[graphic].src_x / 8;
1756 int src_y = mini_starty + graphic_info[graphic].src_y / 8;
1758 *bitmap = src_bitmap;
1763 void DrawMicroElement(int xpos, int ypos, int element)
1767 int graphic = el2preimg(element);
1769 getMicroGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
1770 BlitBitmap(src_bitmap, drawto, src_x, src_y, MICRO_TILEX, MICRO_TILEY,
1778 SetDrawBackgroundMask(REDRAW_NONE);
1781 for (x = BX1; x <= BX2; x++)
1782 for (y = BY1; y <= BY2; y++)
1783 DrawScreenField(x, y);
1785 redraw_mask |= REDRAW_FIELD;
1788 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
1792 for (x = 0; x < size_x; x++)
1793 for (y = 0; y < size_y; y++)
1794 DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
1796 redraw_mask |= REDRAW_FIELD;
1799 static void DrawMicroLevelExt(int xpos, int ypos, int from_x, int from_y)
1803 DrawBackground(xpos, ypos, MICROLEV_XSIZE, MICROLEV_YSIZE);
1805 if (lev_fieldx < STD_LEV_FIELDX)
1806 xpos += (STD_LEV_FIELDX - lev_fieldx) / 2 * MICRO_TILEX;
1807 if (lev_fieldy < STD_LEV_FIELDY)
1808 ypos += (STD_LEV_FIELDY - lev_fieldy) / 2 * MICRO_TILEY;
1810 xpos += MICRO_TILEX;
1811 ypos += MICRO_TILEY;
1813 for (x = -1; x <= STD_LEV_FIELDX; x++)
1815 for (y = -1; y <= STD_LEV_FIELDY; y++)
1817 int lx = from_x + x, ly = from_y + y;
1819 if (lx >= 0 && lx < lev_fieldx && ly >= 0 && ly < lev_fieldy)
1820 DrawMicroElement(xpos + x * MICRO_TILEX, ypos + y * MICRO_TILEY,
1821 level.field[lx][ly]);
1822 else if (lx >= -1 && lx < lev_fieldx+1 && ly >= -1 && ly < lev_fieldy+1
1823 && BorderElement != EL_EMPTY)
1824 DrawMicroElement(xpos + x * MICRO_TILEX, ypos + y * MICRO_TILEY,
1825 getBorderElement(lx, ly));
1829 redraw_mask |= REDRAW_MICROLEVEL;
1832 #define MICROLABEL_EMPTY 0
1833 #define MICROLABEL_LEVEL_NAME 1
1834 #define MICROLABEL_CREATED_BY 2
1835 #define MICROLABEL_LEVEL_AUTHOR 3
1836 #define MICROLABEL_IMPORTED_FROM 4
1837 #define MICROLABEL_LEVEL_IMPORT_INFO 5
1839 static void DrawMicroLevelLabelExt(int mode)
1841 char label_text[MAX_OUTPUT_LINESIZE + 1];
1842 int max_len_label_text;
1843 int font_nr = FONT_TEXT_2;
1845 if (mode == MICROLABEL_CREATED_BY || mode == MICROLABEL_IMPORTED_FROM)
1846 font_nr = FONT_TEXT_3;
1848 max_len_label_text = SXSIZE / getFontWidth(font_nr);
1850 DrawBackground(SX, MICROLABEL_YPOS, SXSIZE, getFontHeight(font_nr));
1852 strncpy(label_text, (mode == MICROLABEL_LEVEL_NAME ? level.name :
1853 mode == MICROLABEL_CREATED_BY ? "created by" :
1854 mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
1855 mode == MICROLABEL_IMPORTED_FROM ? "imported from" :
1856 mode == MICROLABEL_LEVEL_IMPORT_INFO ?
1857 leveldir_current->imported_from : ""),
1858 max_len_label_text);
1859 label_text[max_len_label_text] = '\0';
1861 if (strlen(label_text) > 0)
1863 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
1864 int lypos = MICROLABEL_YPOS;
1866 DrawText(lxpos, lypos, label_text, font_nr);
1869 redraw_mask |= REDRAW_MICROLEVEL;
1872 void DrawMicroLevel(int xpos, int ypos, boolean restart)
1874 static unsigned long scroll_delay = 0;
1875 static unsigned long label_delay = 0;
1876 static int from_x, from_y, scroll_direction;
1877 static int label_state, label_counter;
1878 int last_game_status = game_status; /* save current game status */
1880 /* force PREVIEW font on preview level */
1881 game_status = GAME_MODE_PSEUDO_PREVIEW;
1885 from_x = from_y = 0;
1886 scroll_direction = MV_RIGHT;
1890 DrawMicroLevelExt(xpos, ypos, from_x, from_y);
1891 DrawMicroLevelLabelExt(label_state);
1893 /* initialize delay counters */
1894 DelayReached(&scroll_delay, 0);
1895 DelayReached(&label_delay, 0);
1897 if (leveldir_current->name)
1899 int text_width = getTextWidth(leveldir_current->name, FONT_TEXT_1);
1900 int lxpos = SX + (SXSIZE - text_width) / 2;
1901 int lypos = SY + 352;
1903 DrawText(lxpos, lypos, leveldir_current->name, FONT_TEXT_1);
1906 game_status = last_game_status; /* restore current game status */
1911 /* scroll micro level, if needed */
1912 if ((lev_fieldx > STD_LEV_FIELDX || lev_fieldy > STD_LEV_FIELDY) &&
1913 DelayReached(&scroll_delay, MICROLEVEL_SCROLL_DELAY))
1915 switch (scroll_direction)
1921 scroll_direction = MV_UP;
1925 if (from_x < lev_fieldx - STD_LEV_FIELDX)
1928 scroll_direction = MV_DOWN;
1935 scroll_direction = MV_RIGHT;
1939 if (from_y < lev_fieldy - STD_LEV_FIELDY)
1942 scroll_direction = MV_LEFT;
1949 DrawMicroLevelExt(xpos, ypos, from_x, from_y);
1952 /* redraw micro level label, if needed */
1953 if (strcmp(level.name, NAMELESS_LEVEL_NAME) != 0 &&
1954 strcmp(level.author, ANONYMOUS_NAME) != 0 &&
1955 strcmp(level.author, leveldir_current->name) != 0 &&
1956 DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
1958 int max_label_counter = 23;
1960 if (leveldir_current->imported_from != NULL)
1961 max_label_counter += 14;
1963 label_counter = (label_counter + 1) % max_label_counter;
1964 label_state = (label_counter >= 0 && label_counter <= 7 ?
1965 MICROLABEL_LEVEL_NAME :
1966 label_counter >= 9 && label_counter <= 12 ?
1967 MICROLABEL_CREATED_BY :
1968 label_counter >= 14 && label_counter <= 21 ?
1969 MICROLABEL_LEVEL_AUTHOR :
1970 label_counter >= 23 && label_counter <= 26 ?
1971 MICROLABEL_IMPORTED_FROM :
1972 label_counter >= 28 && label_counter <= 35 ?
1973 MICROLABEL_LEVEL_IMPORT_INFO : MICROLABEL_EMPTY);
1974 DrawMicroLevelLabelExt(label_state);
1977 game_status = last_game_status; /* restore current game status */
1980 void WaitForEventToContinue()
1982 boolean still_wait = TRUE;
1984 /* simulate releasing mouse button over last gadget, if still pressed */
1986 HandleGadgets(-1, -1, 0);
1988 button_status = MB_RELEASED;
2000 case EVENT_BUTTONPRESS:
2001 case EVENT_KEYPRESS:
2005 case EVENT_KEYRELEASE:
2006 ClearPlayerAction();
2010 HandleOtherEvents(&event);
2014 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
2021 /* don't eat all CPU time */
2026 #define MAX_REQUEST_LINES 13
2027 #define MAX_REQUEST_LINE_FONT1_LEN 7
2028 #define MAX_REQUEST_LINE_FONT2_LEN 10
2030 boolean Request(char *text, unsigned int req_state)
2032 int mx, my, ty, result = -1;
2033 unsigned int old_door_state;
2034 int last_game_status = game_status; /* save current game status */
2035 int max_request_line_len = MAX_REQUEST_LINE_FONT1_LEN;
2036 int font_nr = FONT_TEXT_2;
2037 int max_word_len = 0;
2040 for (text_ptr = text; *text_ptr; text_ptr++)
2042 max_word_len = (*text_ptr != ' ' ? max_word_len + 1 : 0);
2044 if (max_word_len > MAX_REQUEST_LINE_FONT1_LEN)
2046 max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
2047 font_nr = FONT_LEVEL_NUMBER;
2054 SetMouseCursor(CURSOR_DEFAULT);
2057 #if defined(PLATFORM_UNIX)
2058 /* pause network game while waiting for request to answer */
2059 if (options.network &&
2060 game_status == GAME_MODE_PLAYING &&
2061 req_state & REQUEST_WAIT_FOR)
2062 SendToServer_PausePlaying();
2065 old_door_state = GetDoorState();
2067 /* simulate releasing mouse button over last gadget, if still pressed */
2069 HandleGadgets(-1, -1, 0);
2073 CloseDoor(DOOR_CLOSE_1);
2075 /* save old door content */
2076 BlitBitmap(bitmap_db_door, bitmap_db_door,
2077 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
2078 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
2080 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
2082 /* clear door drawing field */
2083 DrawBackground(DX, DY, DXSIZE, DYSIZE);
2085 /* force DOOR font on preview level */
2086 game_status = GAME_MODE_PSEUDO_DOOR;
2088 /* write text for request */
2089 for (ty = 0; ty < MAX_REQUEST_LINES; ty++)
2091 char text_line[max_request_line_len + 1];
2097 for (tl = 0, tx = 0; tx < max_request_line_len; tl++, tx++)
2100 if (!tc || tc == ' ')
2111 strncpy(text_line, text, tl);
2114 DrawText(DX + (DXSIZE - tl * getFontWidth(font_nr)) / 2,
2115 DY + 8 + ty * (getFontHeight(font_nr) + 2),
2116 text_line, font_nr);
2118 text += tl + (tc == ' ' ? 1 : 0);
2121 game_status = last_game_status; /* restore current game status */
2123 if (req_state & REQ_ASK)
2125 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
2126 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
2128 else if (req_state & REQ_CONFIRM)
2130 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
2132 else if (req_state & REQ_PLAYER)
2134 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
2135 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
2136 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
2137 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
2140 /* copy request gadgets to door backbuffer */
2141 BlitBitmap(drawto, bitmap_db_door,
2142 DX, DY, DXSIZE, DYSIZE,
2143 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2145 OpenDoor(DOOR_OPEN_1);
2151 if (!(req_state & REQUEST_WAIT_FOR))
2153 SetDrawBackgroundMask(REDRAW_FIELD);
2158 if (game_status != GAME_MODE_MAIN)
2161 button_status = MB_RELEASED;
2163 request_gadget_id = -1;
2165 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
2168 SetMouseCursor(CURSOR_DEFAULT);
2181 case EVENT_BUTTONPRESS:
2182 case EVENT_BUTTONRELEASE:
2183 case EVENT_MOTIONNOTIFY:
2185 if (event.type == EVENT_MOTIONNOTIFY)
2187 if (!PointerInWindow(window))
2188 continue; /* window and pointer are on different screens */
2193 motion_status = TRUE;
2194 mx = ((MotionEvent *) &event)->x;
2195 my = ((MotionEvent *) &event)->y;
2199 motion_status = FALSE;
2200 mx = ((ButtonEvent *) &event)->x;
2201 my = ((ButtonEvent *) &event)->y;
2202 if (event.type == EVENT_BUTTONPRESS)
2203 button_status = ((ButtonEvent *) &event)->button;
2205 button_status = MB_RELEASED;
2208 /* this sets 'request_gadget_id' */
2209 HandleGadgets(mx, my, button_status);
2211 switch(request_gadget_id)
2213 case TOOL_CTRL_ID_YES:
2216 case TOOL_CTRL_ID_NO:
2219 case TOOL_CTRL_ID_CONFIRM:
2220 result = TRUE | FALSE;
2223 case TOOL_CTRL_ID_PLAYER_1:
2226 case TOOL_CTRL_ID_PLAYER_2:
2229 case TOOL_CTRL_ID_PLAYER_3:
2232 case TOOL_CTRL_ID_PLAYER_4:
2243 case EVENT_KEYPRESS:
2244 switch(GetEventKey((KeyEvent *)&event, TRUE))
2257 if (req_state & REQ_PLAYER)
2261 case EVENT_KEYRELEASE:
2262 ClearPlayerAction();
2266 HandleOtherEvents(&event);
2270 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
2272 int joy = AnyJoystick();
2274 if (joy & JOY_BUTTON_1)
2276 else if (joy & JOY_BUTTON_2)
2282 /* don't eat all CPU time */
2286 if (game_status != GAME_MODE_MAIN)
2291 if (!(req_state & REQ_STAY_OPEN))
2293 CloseDoor(DOOR_CLOSE_1);
2295 if (!(req_state & REQ_STAY_CLOSED) && (old_door_state & DOOR_OPEN_1))
2297 BlitBitmap(bitmap_db_door, bitmap_db_door,
2298 DOOR_GFX_PAGEX2,DOOR_GFX_PAGEY1, DXSIZE,DYSIZE,
2299 DOOR_GFX_PAGEX1,DOOR_GFX_PAGEY1);
2300 OpenDoor(DOOR_OPEN_1);
2306 SetDrawBackgroundMask(REDRAW_FIELD);
2308 #if defined(PLATFORM_UNIX)
2309 /* continue network game after request */
2310 if (options.network &&
2311 game_status == GAME_MODE_PLAYING &&
2312 req_state & REQUEST_WAIT_FOR)
2313 SendToServer_ContinuePlaying();
2319 unsigned int OpenDoor(unsigned int door_state)
2321 unsigned int new_door_state;
2323 if (door_state & DOOR_COPY_BACK)
2325 BlitBitmap(bitmap_db_door, bitmap_db_door,
2326 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE + VYSIZE,
2327 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2328 door_state &= ~DOOR_COPY_BACK;
2331 new_door_state = MoveDoor(door_state);
2333 return(new_door_state);
2336 unsigned int CloseDoor(unsigned int door_state)
2338 unsigned int new_door_state;
2340 BlitBitmap(backbuffer, bitmap_db_door,
2341 DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2342 BlitBitmap(backbuffer, bitmap_db_door,
2343 VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
2345 new_door_state = MoveDoor(door_state);
2347 return(new_door_state);
2350 unsigned int GetDoorState()
2352 return MoveDoor(DOOR_GET_STATE);
2355 unsigned int SetDoorState(unsigned int door_state)
2357 return MoveDoor(door_state | DOOR_SET_STATE);
2360 unsigned int MoveDoor(unsigned int door_state)
2362 static int door1 = DOOR_OPEN_1;
2363 static int door2 = DOOR_CLOSE_2;
2364 unsigned long door_delay = 0;
2365 unsigned long door_delay_value;
2368 if (door_state == DOOR_GET_STATE)
2369 return(door1 | door2);
2371 if (door_state & DOOR_SET_STATE)
2373 if (door_state & DOOR_ACTION_1)
2374 door1 = door_state & DOOR_ACTION_1;
2375 if (door_state & DOOR_ACTION_2)
2376 door2 = door_state & DOOR_ACTION_2;
2378 return(door1 | door2);
2381 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
2382 door_state &= ~DOOR_OPEN_1;
2383 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
2384 door_state &= ~DOOR_CLOSE_1;
2385 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
2386 door_state &= ~DOOR_OPEN_2;
2387 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
2388 door_state &= ~DOOR_CLOSE_2;
2390 door_delay_value = (door_state & DOOR_ACTION_1 ? door_1.step_delay :
2393 if (setup.quick_doors)
2395 stepsize = 20; /* must be choosen to always draw last frame */
2396 door_delay_value = 0;
2399 StopSound(SND_DOOR_OPENING);
2400 StopSound(SND_DOOR_CLOSING);
2404 if (global.autoplay_leveldir)
2406 door_state |= DOOR_NO_DELAY;
2407 door_state &= ~DOOR_CLOSE_ALL;
2410 if (door_state & DOOR_ACTION)
2412 boolean door_1_done = !(door_state & DOOR_ACTION_1);
2413 boolean door_2_done = !(door_state & DOOR_ACTION_2);
2414 int start = ((door_state & DOOR_NO_DELAY) ? DXSIZE : 0);
2415 int end = (door_state & DOOR_ACTION_1 &&
2416 door_1.anim_mode == ANIM_VERTICAL ? DYSIZE : DXSIZE);
2419 if (!(door_state & DOOR_NO_DELAY) && !setup.quick_doors)
2421 /* opening door sound has priority over simultaneously closing door */
2422 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
2423 PlaySoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
2424 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
2425 PlaySoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
2428 for (x = start; x <= end && !(door_1_done && door_2_done); x += stepsize)
2430 Bitmap *bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
2431 GC gc = bitmap->stored_clip_gc;
2433 if (door_state & DOOR_ACTION_1)
2435 int a = MIN(x * door_1.step_offset, end);
2436 int i = (door_state & DOOR_OPEN_1 ? end - a : a);
2440 BlitBitmap(bitmap_db_door, drawto,
2441 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + i / 2,
2442 DXSIZE,DYSIZE - i / 2, DX, DY);
2444 ClearRectangle(drawto, DX, DY + DYSIZE - i / 2, DXSIZE, i / 2);
2447 if (door_1.anim_mode == ANIM_HORIZONTAL && x <= DXSIZE)
2449 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
2450 int dst1_x = DX + DXSIZE - i, dst1_y = DY;
2451 int src2_x = DXSIZE - i, src2_y = DOOR_GFX_PAGEY1;
2452 int dst2_x = DX, dst2_y = DY;
2453 int width = i, height = DYSIZE;
2455 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2456 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2459 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2460 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2463 else if (door_1.anim_mode == ANIM_VERTICAL && x <= DYSIZE)
2465 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
2466 int dst1_x = DX, dst1_y = DY + DYSIZE - i;
2467 int src2_x = 0, src2_y = DOOR_GFX_PAGEY1 + DYSIZE - i;
2468 int dst2_x = DX, dst2_y = DY;
2469 int width = DXSIZE, height = i;
2471 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2472 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2475 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2476 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2479 else if (x <= DXSIZE) /* ANIM_DEFAULT */
2481 int j = (door_1.anim_mode == ANIM_DEFAULT ? (DXSIZE - i) / 3 : 0);
2483 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2484 BlitBitmapMasked(bitmap, drawto,
2485 DXSIZE, DOOR_GFX_PAGEY1, i, 77,
2486 DX + DXSIZE - i, DY + j);
2487 BlitBitmapMasked(bitmap, drawto,
2488 DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63,
2489 DX + DXSIZE - i, DY + 140 + j);
2490 SetClipOrigin(bitmap, gc, DX - DXSIZE + i,
2491 DY - (DOOR_GFX_PAGEY1 + j));
2492 BlitBitmapMasked(bitmap, drawto,
2493 DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j,
2495 BlitBitmapMasked(bitmap, drawto,
2496 DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63,
2499 BlitBitmapMasked(bitmap, drawto,
2500 DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
2502 BlitBitmapMasked(bitmap, drawto,
2503 DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
2505 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2506 BlitBitmapMasked(bitmap, drawto,
2507 DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
2508 DX + DXSIZE - i, DY + 77 + j);
2509 BlitBitmapMasked(bitmap, drawto,
2510 DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
2511 DX + DXSIZE - i, DY + 203 + j);
2514 redraw_mask |= REDRAW_DOOR_1;
2515 door_1_done = (a == end);
2518 if (door_state & DOOR_ACTION_2)
2520 int a = MIN(x * door_2.step_offset, VXSIZE);
2521 int i = (door_state & DOOR_OPEN_2 ? VXSIZE - a : a);
2525 BlitBitmap(bitmap_db_door, drawto,
2526 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + i / 2,
2527 VXSIZE, VYSIZE - i / 2, VX, VY);
2529 ClearRectangle(drawto, VX, VY + VYSIZE - i / 2, VXSIZE, i / 2);
2532 if (door_2.anim_mode == ANIM_HORIZONTAL && x <= VXSIZE)
2534 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
2535 int dst1_x = VX + VXSIZE - i, dst1_y = VY;
2536 int src2_x = VXSIZE - i, src2_y = DOOR_GFX_PAGEY2;
2537 int dst2_x = VX, dst2_y = VY;
2538 int width = i, height = VYSIZE;
2540 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2541 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2544 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2545 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2548 else if (door_2.anim_mode == ANIM_VERTICAL && x <= VYSIZE)
2550 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
2551 int dst1_x = VX, dst1_y = VY + VYSIZE - i;
2552 int src2_x = 0, src2_y = DOOR_GFX_PAGEY2 + VYSIZE - i;
2553 int dst2_x = VX, dst2_y = VY;
2554 int width = VXSIZE, height = i;
2556 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2557 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2560 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2561 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2564 else if (x <= VXSIZE) /* ANIM_DEFAULT */
2566 int j = (door_2.anim_mode == ANIM_DEFAULT ? (VXSIZE - i) / 3 : 0);
2568 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2569 BlitBitmapMasked(bitmap, drawto,
2570 VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2,
2571 VX + VXSIZE - i, VY + j);
2572 SetClipOrigin(bitmap, gc,
2573 VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
2574 BlitBitmapMasked(bitmap, drawto,
2575 VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j,
2578 BlitBitmapMasked(bitmap, drawto,
2579 VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2,
2580 i, VYSIZE / 2, VX, VY + VYSIZE / 2 - j);
2581 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2582 BlitBitmapMasked(bitmap, drawto,
2583 VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2,
2585 VX + VXSIZE - i, VY + VYSIZE / 2 + j);
2588 redraw_mask |= REDRAW_DOOR_2;
2589 door_2_done = (a == VXSIZE);
2594 if (game_status == GAME_MODE_MAIN)
2597 if (!(door_state & DOOR_NO_DELAY))
2598 WaitUntilDelayReached(&door_delay, door_delay_value);
2603 if (setup.quick_doors)
2605 StopSound(SND_DOOR_OPENING);
2606 StopSound(SND_DOOR_CLOSING);
2610 if (door_state & DOOR_ACTION_1)
2611 door1 = door_state & DOOR_ACTION_1;
2612 if (door_state & DOOR_ACTION_2)
2613 door2 = door_state & DOOR_ACTION_2;
2615 return (door1 | door2);
2618 void DrawSpecialEditorDoor()
2620 /* draw bigger toolbox window */
2621 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
2622 DOOR_GFX_PAGEX7, 0, EXSIZE + 8, 8,
2624 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
2625 EX - 4, VY - 4, EXSIZE + 8, EYSIZE - VYSIZE + 4,
2628 redraw_mask |= REDRAW_ALL;
2631 void UndrawSpecialEditorDoor()
2633 /* draw normal tape recorder window */
2634 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
2635 EX - 4, EY - 12, EXSIZE + 8, EYSIZE - VYSIZE + 12,
2638 redraw_mask |= REDRAW_ALL;
2642 /* ---------- new tool button stuff ---------------------------------------- */
2644 /* graphic position values for tool buttons */
2645 #define TOOL_BUTTON_YES_XPOS 2
2646 #define TOOL_BUTTON_YES_YPOS 250
2647 #define TOOL_BUTTON_YES_GFX_YPOS 0
2648 #define TOOL_BUTTON_YES_XSIZE 46
2649 #define TOOL_BUTTON_YES_YSIZE 28
2650 #define TOOL_BUTTON_NO_XPOS 52
2651 #define TOOL_BUTTON_NO_YPOS TOOL_BUTTON_YES_YPOS
2652 #define TOOL_BUTTON_NO_GFX_YPOS TOOL_BUTTON_YES_GFX_YPOS
2653 #define TOOL_BUTTON_NO_XSIZE TOOL_BUTTON_YES_XSIZE
2654 #define TOOL_BUTTON_NO_YSIZE TOOL_BUTTON_YES_YSIZE
2655 #define TOOL_BUTTON_CONFIRM_XPOS TOOL_BUTTON_YES_XPOS
2656 #define TOOL_BUTTON_CONFIRM_YPOS TOOL_BUTTON_YES_YPOS
2657 #define TOOL_BUTTON_CONFIRM_GFX_YPOS 30
2658 #define TOOL_BUTTON_CONFIRM_XSIZE 96
2659 #define TOOL_BUTTON_CONFIRM_YSIZE TOOL_BUTTON_YES_YSIZE
2660 #define TOOL_BUTTON_PLAYER_XSIZE 30
2661 #define TOOL_BUTTON_PLAYER_YSIZE 30
2662 #define TOOL_BUTTON_PLAYER_GFX_XPOS 5
2663 #define TOOL_BUTTON_PLAYER_GFX_YPOS 185
2664 #define TOOL_BUTTON_PLAYER_XPOS (5 + TOOL_BUTTON_PLAYER_XSIZE / 2)
2665 #define TOOL_BUTTON_PLAYER_YPOS (215 - TOOL_BUTTON_PLAYER_YSIZE / 2)
2666 #define TOOL_BUTTON_PLAYER1_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2667 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2668 #define TOOL_BUTTON_PLAYER2_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2669 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2670 #define TOOL_BUTTON_PLAYER3_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2671 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2672 #define TOOL_BUTTON_PLAYER4_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2673 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2674 #define TOOL_BUTTON_PLAYER1_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2675 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2676 #define TOOL_BUTTON_PLAYER2_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2677 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2678 #define TOOL_BUTTON_PLAYER3_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2679 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2680 #define TOOL_BUTTON_PLAYER4_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2681 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2690 } toolbutton_info[NUM_TOOL_BUTTONS] =
2693 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_GFX_YPOS,
2694 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_YPOS,
2695 TOOL_BUTTON_YES_XSIZE, TOOL_BUTTON_YES_YSIZE,
2700 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_GFX_YPOS,
2701 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_YPOS,
2702 TOOL_BUTTON_NO_XSIZE, TOOL_BUTTON_NO_YSIZE,
2707 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_GFX_YPOS,
2708 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_YPOS,
2709 TOOL_BUTTON_CONFIRM_XSIZE, TOOL_BUTTON_CONFIRM_YSIZE,
2710 TOOL_CTRL_ID_CONFIRM,
2714 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2715 TOOL_BUTTON_PLAYER1_XPOS, TOOL_BUTTON_PLAYER1_YPOS,
2716 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2717 TOOL_CTRL_ID_PLAYER_1,
2721 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2722 TOOL_BUTTON_PLAYER2_XPOS, TOOL_BUTTON_PLAYER2_YPOS,
2723 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2724 TOOL_CTRL_ID_PLAYER_2,
2728 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2729 TOOL_BUTTON_PLAYER3_XPOS, TOOL_BUTTON_PLAYER3_YPOS,
2730 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2731 TOOL_CTRL_ID_PLAYER_3,
2735 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2736 TOOL_BUTTON_PLAYER4_XPOS, TOOL_BUTTON_PLAYER4_YPOS,
2737 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2738 TOOL_CTRL_ID_PLAYER_4,
2743 void CreateToolButtons()
2747 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
2749 Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
2750 Bitmap *deco_bitmap = None;
2751 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
2752 struct GadgetInfo *gi;
2753 unsigned long event_mask;
2754 int gd_xoffset, gd_yoffset;
2755 int gd_x1, gd_x2, gd_y;
2758 event_mask = GD_EVENT_RELEASED;
2760 gd_xoffset = toolbutton_info[i].xpos;
2761 gd_yoffset = toolbutton_info[i].ypos;
2762 gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
2763 gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
2764 gd_y = DOOR_GFX_PAGEY1 + gd_yoffset;
2766 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
2768 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
2770 getMiniGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr),
2771 &deco_bitmap, &deco_x, &deco_y);
2772 deco_xpos = (toolbutton_info[i].width - MINI_TILEX) / 2;
2773 deco_ypos = (toolbutton_info[i].height - MINI_TILEY) / 2;
2776 gi = CreateGadget(GDI_CUSTOM_ID, id,
2777 GDI_INFO_TEXT, toolbutton_info[i].infotext,
2778 GDI_X, DX + toolbutton_info[i].x,
2779 GDI_Y, DY + toolbutton_info[i].y,
2780 GDI_WIDTH, toolbutton_info[i].width,
2781 GDI_HEIGHT, toolbutton_info[i].height,
2782 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
2783 GDI_STATE, GD_BUTTON_UNPRESSED,
2784 GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
2785 GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
2786 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
2787 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
2788 GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
2789 GDI_DECORATION_SHIFTING, 1, 1,
2790 GDI_EVENT_MASK, event_mask,
2791 GDI_CALLBACK_ACTION, HandleToolButtons,
2795 Error(ERR_EXIT, "cannot create gadget");
2797 tool_gadget[id] = gi;
2801 void FreeToolButtons()
2805 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
2806 FreeGadget(tool_gadget[i]);
2809 static void UnmapToolButtons()
2813 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
2814 UnmapGadget(tool_gadget[i]);
2817 static void HandleToolButtons(struct GadgetInfo *gi)
2819 request_gadget_id = gi->custom_id;
2822 int get_next_element(int element)
2826 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
2827 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
2828 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
2829 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
2830 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
2831 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
2832 case EL_AMOEBA_DROPPING: return EL_AMOEBA_WET;
2834 default: return element;
2838 int el_act_dir2img(int element, int action, int direction)
2840 element = GFX_ELEMENT(element);
2841 direction = MV_DIR_BIT(direction);
2843 return element_info[element].direction_graphic[action][direction];
2846 static int el_act_dir2crm(int element, int action, int direction)
2848 element = GFX_ELEMENT(element);
2849 direction = MV_DIR_BIT(direction);
2851 return element_info[element].direction_crumbled[action][direction];
2854 int el_act2img(int element, int action)
2856 element = GFX_ELEMENT(element);
2858 return element_info[element].graphic[action];
2861 int el_act2crm(int element, int action)
2863 element = GFX_ELEMENT(element);
2865 return element_info[element].crumbled[action];
2868 int el_dir2img(int element, int direction)
2870 element = GFX_ELEMENT(element);
2872 return el_act_dir2img(element, ACTION_DEFAULT, direction);
2875 int el2img(int element)
2877 element = GFX_ELEMENT(element);
2879 return element_info[element].graphic[ACTION_DEFAULT];
2882 int el2edimg(int element)
2884 element = GFX_ELEMENT(element);
2886 return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
2889 int el2preimg(int element)
2891 element = GFX_ELEMENT(element);
2893 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];