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 static char *print_if_not_empty(int element)
45 static char *s = NULL;
46 char *token_name = element_info[element].token_name;
51 s = checked_malloc(strlen(token_name) + 10 + 1);
53 if (element != EL_EMPTY)
54 sprintf(s, "%d\t['%s']", element, token_name);
56 sprintf(s, "%d", element);
61 void DumpTile(int x, int y)
67 printf("Field Info: SCREEN(%d, %d), LEVEL(%d, %d)\n", sx, sy, x, y);
70 if (!IN_LEV_FIELD(x, y))
72 printf("(not in level field)\n");
78 printf(" Feld: %d\t['%s']\n", Feld[x][y],
79 element_info[Feld[x][y]].token_name);
80 printf(" Back: %s\n", print_if_not_empty(Back[x][y]));
81 printf(" Store: %s\n", print_if_not_empty(Store[x][y]));
82 printf(" Store2: %s\n", print_if_not_empty(Store2[x][y]));
83 printf(" StorePlayer: %s\n", print_if_not_empty(StorePlayer[x][y]));
84 printf(" MovPos: %d\n", MovPos[x][y]);
85 printf(" MovDir: %d\n", MovDir[x][y]);
86 printf(" MovDelay: %d\n", MovDelay[x][y]);
87 printf(" ChangeDelay: %d\n", ChangeDelay[x][y]);
88 printf(" GfxElement: %d\n", GfxElement[x][y]);
89 printf(" GfxAction: %d\n", GfxAction[x][y]);
90 printf(" GfxFrame: %d\n", GfxFrame[x][y]);
94 void SetDrawtoField(int mode)
96 if (mode == DRAW_BUFFERED && setup.soft_scrolling)
107 drawto_field = fieldbuffer;
109 else /* DRAW_DIRECT, DRAW_BACKBUFFER */
115 BX2 = SCR_FIELDX - 1;
116 BY2 = SCR_FIELDY - 1;
120 drawto_field = (mode == DRAW_DIRECT ? window : backbuffer);
124 void RedrawPlayfield(boolean force_redraw, int x, int y, int width, int height)
126 if (game_status == GAME_MODE_PLAYING && !game.envelope_active)
132 width = gfx.sxsize + 2 * TILEX;
133 height = gfx.sysize + 2 * TILEY;
136 if (force_redraw || setup.direct_draw)
139 int x1 = (x - SX) / TILEX, y1 = (y - SY) / TILEY;
140 int x2 = (x - SX + width) / TILEX, y2 = (y - SY + height) / TILEY;
142 if (setup.direct_draw)
143 SetDrawtoField(DRAW_BACKBUFFER);
145 for (xx = BX1; xx <= BX2; xx++)
146 for (yy = BY1; yy <= BY2; yy++)
147 if (xx >= x1 && xx <= x2 && yy >= y1 && yy <= y2)
148 DrawScreenField(xx, yy);
151 if (setup.direct_draw)
152 SetDrawtoField(DRAW_DIRECT);
155 if (setup.soft_scrolling)
157 int fx = FX, fy = FY;
159 fx += (ScreenMovDir & (MV_LEFT|MV_RIGHT) ? ScreenGfxPos : 0);
160 fy += (ScreenMovDir & (MV_UP|MV_DOWN) ? ScreenGfxPos : 0);
162 BlitBitmap(fieldbuffer, backbuffer, fx,fy, SXSIZE,SYSIZE, SX,SY);
166 BlitBitmap(drawto, window, x, y, width, height, x, y);
172 DrawBuffer *buffer = (drawto_field == window ? backbuffer : drawto_field);
174 if (setup.direct_draw && game_status == GAME_MODE_PLAYING)
175 redraw_mask &= ~REDRAW_MAIN;
177 if (redraw_mask & REDRAW_TILES && redraw_tiles > REDRAWTILES_THRESHOLD)
178 redraw_mask |= REDRAW_FIELD;
180 if (redraw_mask & REDRAW_FIELD)
181 redraw_mask &= ~REDRAW_TILES;
183 if (redraw_mask == REDRAW_NONE)
186 if (global.fps_slowdown && game_status == GAME_MODE_PLAYING)
188 static boolean last_frame_skipped = FALSE;
189 boolean skip_even_when_not_scrolling = TRUE;
190 boolean just_scrolling = (ScreenMovDir != 0);
191 boolean verbose = FALSE;
193 if (global.fps_slowdown_factor > 1 &&
194 (FrameCounter % global.fps_slowdown_factor) &&
195 (just_scrolling || skip_even_when_not_scrolling))
197 redraw_mask &= ~REDRAW_MAIN;
199 last_frame_skipped = TRUE;
202 printf("FRAME SKIPPED\n");
206 if (last_frame_skipped)
207 redraw_mask |= REDRAW_FIELD;
209 last_frame_skipped = FALSE;
212 printf("frame not skipped\n");
216 /* synchronize X11 graphics at this point; if we would synchronize the
217 display immediately after the buffer switching (after the XFlush),
218 this could mean that we have to wait for the graphics to complete,
219 although we could go on doing calculations for the next frame */
223 if (redraw_mask & REDRAW_ALL)
225 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
229 if (redraw_mask & REDRAW_FIELD)
231 if (game_status != GAME_MODE_PLAYING ||
232 redraw_mask & REDRAW_FROM_BACKBUFFER)
234 BlitBitmap(backbuffer, window,
235 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE, REAL_SX, REAL_SY);
239 int fx = FX, fy = FY;
241 if (setup.soft_scrolling)
243 fx += (ScreenMovDir & (MV_LEFT | MV_RIGHT) ? ScreenGfxPos : 0);
244 fy += (ScreenMovDir & (MV_UP | MV_DOWN) ? ScreenGfxPos : 0);
247 if (setup.soft_scrolling ||
248 ABS(ScreenMovPos) + ScrollStepSize == TILEX ||
249 ABS(ScreenMovPos) == ScrollStepSize ||
250 redraw_tiles > REDRAWTILES_THRESHOLD)
252 BlitBitmap(buffer, window, fx, fy, SXSIZE, SYSIZE, SX, SY);
256 printf("redrawing all (ScreenGfxPos == %d) because %s\n",
258 (setup.soft_scrolling ?
259 "setup.soft_scrolling" :
260 ABS(ScreenGfxPos) + ScrollStepSize == TILEX ?
261 "ABS(ScreenGfxPos) + ScrollStepSize == TILEX" :
262 ABS(ScreenGfxPos) == ScrollStepSize ?
263 "ABS(ScreenGfxPos) == ScrollStepSize" :
264 "redraw_tiles > REDRAWTILES_THRESHOLD"));
270 redraw_mask &= ~REDRAW_MAIN;
273 if (redraw_mask & REDRAW_DOORS)
275 if (redraw_mask & REDRAW_DOOR_1)
276 BlitBitmap(backbuffer, window, DX, DY, DXSIZE, DYSIZE, DX, DY);
278 if (redraw_mask & REDRAW_DOOR_2)
281 if ((redraw_mask & REDRAW_DOOR_2) == REDRAW_DOOR_2)
283 BlitBitmap(backbuffer, window, VX, VY, VXSIZE, VYSIZE, VX, VY);
287 if (redraw_mask & REDRAW_VIDEO_1)
288 BlitBitmap(backbuffer, window,
289 VX + VIDEO_DISPLAY1_XPOS, VY + VIDEO_DISPLAY1_YPOS,
290 VIDEO_DISPLAY_XSIZE, VIDEO_DISPLAY_YSIZE,
291 VX + VIDEO_DISPLAY1_XPOS, VY + VIDEO_DISPLAY1_YPOS);
292 if (redraw_mask & REDRAW_VIDEO_2)
293 BlitBitmap(backbuffer, window,
294 VX + VIDEO_DISPLAY2_XPOS, VY + VIDEO_DISPLAY2_YPOS,
295 VIDEO_DISPLAY_XSIZE, VIDEO_DISPLAY_YSIZE,
296 VX + VIDEO_DISPLAY2_XPOS, VY + VIDEO_DISPLAY2_YPOS);
297 if (redraw_mask & REDRAW_VIDEO_3)
298 BlitBitmap(backbuffer, window,
299 VX + VIDEO_CONTROL_XPOS, VY + VIDEO_CONTROL_YPOS,
300 VIDEO_CONTROL_XSIZE, VIDEO_CONTROL_YSIZE,
301 VX + VIDEO_CONTROL_XPOS, VY + VIDEO_CONTROL_YPOS);
306 if (redraw_mask & REDRAW_DOOR_3)
307 BlitBitmap(backbuffer, window, EX, EY, EXSIZE, EYSIZE, EX, EY);
309 redraw_mask &= ~REDRAW_DOORS;
312 if (redraw_mask & REDRAW_MICROLEVEL)
314 BlitBitmap(backbuffer, window, SX, SY + 10 * TILEY, SXSIZE, 7 * TILEY,
315 SX, SY + 10 * TILEY);
317 redraw_mask &= ~REDRAW_MICROLEVEL;
320 if (redraw_mask & REDRAW_TILES)
322 for (x = 0; x < SCR_FIELDX; x++)
323 for (y = 0 ; y < SCR_FIELDY; y++)
324 if (redraw[redraw_x1 + x][redraw_y1 + y])
325 BlitBitmap(buffer, window,
326 FX + x * TILEX, FY + y * TILEY, TILEX, TILEY,
327 SX + x * TILEX, SY + y * TILEY);
330 if (redraw_mask & REDRAW_FPS) /* display frames per second */
335 sprintf(info1, " (only every %d. frame)", global.fps_slowdown_factor);
336 if (!global.fps_slowdown)
339 sprintf(text, "%.1f fps%s", global.frames_per_second, info1);
340 DrawTextExt(window, SX, SY, text, FONT_TEXT_2, BLIT_OPAQUE);
345 for (x = 0; x < MAX_BUF_XSIZE; x++)
346 for (y = 0; y < MAX_BUF_YSIZE; y++)
349 redraw_mask = REDRAW_NONE;
355 long fading_delay = 300;
357 if (setup.fading && (redraw_mask & REDRAW_FIELD))
364 ClearRectangle(window, REAL_SX,REAL_SY,FULL_SXSIZE,FULL_SYSIZE);
367 for (i = 0; i < 2 * FULL_SYSIZE; i++)
369 for (y = 0; y < FULL_SYSIZE; y++)
371 BlitBitmap(backbuffer, window,
372 REAL_SX,REAL_SY+i, FULL_SXSIZE,1, REAL_SX,REAL_SY+i);
380 for (i = 1; i < FULL_SYSIZE; i+=2)
381 BlitBitmap(backbuffer, window,
382 REAL_SX,REAL_SY+i, FULL_SXSIZE,1, REAL_SX,REAL_SY+i);
388 SetClipOrigin(clip_gc[PIX_FADEMASK], 0, 0);
389 BlitBitmapMasked(backbuffer, window,
390 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
395 SetClipOrigin(clip_gc[PIX_FADEMASK], -1, -1);
396 BlitBitmapMasked(backbuffer, window,
397 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
402 SetClipOrigin(clip_gc[PIX_FADEMASK], 0, -1);
403 BlitBitmapMasked(backbuffer, window,
404 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
409 SetClipOrigin(clip_gc[PIX_FADEMASK], -1, 0);
410 BlitBitmapMasked(backbuffer, window,
411 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
416 redraw_mask &= ~REDRAW_MAIN;
423 void SetMainBackgroundImage(int graphic)
425 SetMainBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
426 graphic_info[graphic].bitmap ?
427 graphic_info[graphic].bitmap :
428 graphic_info[IMG_BACKGROUND].bitmap);
431 void SetDoorBackgroundImage(int graphic)
433 SetDoorBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
434 graphic_info[graphic].bitmap ?
435 graphic_info[graphic].bitmap :
436 graphic_info[IMG_BACKGROUND].bitmap);
439 void DrawBackground(int dest_x, int dest_y, int width, int height)
441 ClearRectangleOnBackground(backbuffer, dest_x, dest_y, width, height);
443 redraw_mask |= REDRAW_FIELD;
448 DrawBackground(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
450 if (setup.soft_scrolling && game_status == GAME_MODE_PLAYING)
452 ClearRectangle(fieldbuffer, 0, 0, FXSIZE, FYSIZE);
453 SetDrawtoField(DRAW_BUFFERED);
456 SetDrawtoField(DRAW_BACKBUFFER);
458 if (setup.direct_draw && game_status == GAME_MODE_PLAYING)
460 ClearRectangle(window, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
461 SetDrawtoField(DRAW_DIRECT);
465 void MarkTileDirty(int x, int y)
467 int xx = redraw_x1 + x;
468 int yy = redraw_y1 + y;
473 redraw[xx][yy] = TRUE;
474 redraw_mask |= REDRAW_TILES;
477 void SetBorderElement()
481 BorderElement = EL_EMPTY;
483 for (y = 0; y < lev_fieldy && BorderElement == EL_EMPTY; y++)
485 for (x = 0; x < lev_fieldx; x++)
487 if (!IS_INDESTRUCTIBLE(Feld[x][y]))
488 BorderElement = EL_STEELWALL;
490 if (y != 0 && y != lev_fieldy - 1 && x != lev_fieldx - 1)
496 void SetRandomAnimationValue(int x, int y)
498 gfx.anim_random_frame = GfxRandom[x][y];
501 inline int getGraphicAnimationFrame(int graphic, int sync_frame)
503 /* animation synchronized with global frame counter, not move position */
504 if (graphic_info[graphic].anim_global_sync || sync_frame < 0)
505 sync_frame = FrameCounter;
507 return getAnimationFrame(graphic_info[graphic].anim_frames,
508 graphic_info[graphic].anim_delay,
509 graphic_info[graphic].anim_mode,
510 graphic_info[graphic].anim_start_frame,
514 inline void DrawGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
515 int graphic, int sync_frame, int mask_mode)
517 int frame = getGraphicAnimationFrame(graphic, sync_frame);
519 if (mask_mode == USE_MASKING)
520 DrawGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
522 DrawGraphicExt(dst_bitmap, x, y, graphic, frame);
525 inline void DrawGraphicAnimation(int x, int y, int graphic)
527 int lx = LEVELX(x), ly = LEVELY(y);
529 if (!IN_SCR_FIELD(x, y))
532 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
533 graphic, GfxFrame[lx][ly], NO_MASKING);
537 void DrawLevelGraphicAnimation(int x, int y, int graphic)
539 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
542 void DrawLevelElementAnimation(int x, int y, int element)
545 int graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
547 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
549 DrawGraphicAnimation(SCREENX(x), SCREENY(y), el2img(element));
553 inline void DrawLevelGraphicAnimationIfNeeded(int x, int y, int graphic)
555 int sx = SCREENX(x), sy = SCREENY(y);
557 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
560 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
563 DrawGraphicAnimation(sx, sy, graphic);
565 if (GFX_CRUMBLED(Feld[x][y]))
566 DrawLevelFieldCrumbledSand(x, y);
569 void DrawLevelElementAnimationIfNeeded(int x, int y, int element)
571 int sx = SCREENX(x), sy = SCREENY(y);
574 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
577 graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
579 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
582 DrawGraphicAnimation(sx, sy, graphic);
584 if (GFX_CRUMBLED(element))
585 DrawLevelFieldCrumbledSand(x, y);
588 static int getPlayerGraphic(struct PlayerInfo *player, int move_dir)
590 if (player->use_murphy_graphic)
592 /* this works only because currently only one player can be "murphy" ... */
593 static int last_horizontal_dir = MV_LEFT;
594 int graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, move_dir);
596 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
597 last_horizontal_dir = move_dir;
599 if (graphic == IMG_SP_MURPHY) /* undefined => use special graphic */
601 int direction = (player->is_snapping ? move_dir : last_horizontal_dir);
603 graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, direction);
609 return el_act_dir2img(player->element_nr, player->GfxAction, move_dir);
612 static boolean equalGraphics(int graphic1, int graphic2)
614 struct GraphicInfo *g1 = &graphic_info[graphic1];
615 struct GraphicInfo *g2 = &graphic_info[graphic2];
617 return (g1->bitmap == g2->bitmap &&
618 g1->src_x == g2->src_x &&
619 g1->src_y == g2->src_y &&
620 g1->anim_frames == g2->anim_frames &&
621 g1->anim_delay == g2->anim_delay &&
622 g1->anim_mode == g2->anim_mode);
625 void DrawAllPlayers()
629 for (i = 0; i < MAX_PLAYERS; i++)
630 if (stored_player[i].active)
631 DrawPlayer(&stored_player[i]);
634 void DrawPlayerField(int x, int y)
636 if (!IS_PLAYER(x, y))
639 DrawPlayer(PLAYERINFO(x, y));
642 void DrawPlayer(struct PlayerInfo *player)
646 int move_dir = player->MovDir;
648 int last_jx = player->last_jx;
649 int last_jy = player->last_jy;
650 int next_jx = jx + (jx - last_jx);
651 int next_jy = jy + (jy - last_jy);
652 boolean player_is_moving = (last_jx != jx || last_jy != jy ? TRUE : FALSE);
654 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? +1 : 0);
655 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? +1 : 0);
656 int last_jx = (player->is_moving ? jx - dx : jx);
657 int last_jy = (player->is_moving ? jy - dy : jy);
658 int next_jx = jx + dx;
659 int next_jy = jy + dy;
660 boolean player_is_moving = (player->MovPos ? TRUE : FALSE);
662 int sx = SCREENX(jx), sy = SCREENY(jy);
663 int sxx = 0, syy = 0;
664 int element = Feld[jx][jy], last_element = Feld[last_jx][last_jy];
666 int action = ACTION_DEFAULT;
667 int last_player_graphic = getPlayerGraphic(player, move_dir);
668 int last_player_frame = player->Frame;
671 if (!player->active || !IN_SCR_FIELD(SCREENX(last_jx), SCREENY(last_jy)))
675 if (!IN_LEV_FIELD(jx, jy))
677 printf("DrawPlayerField(): x = %d, y = %d\n",jx,jy);
678 printf("DrawPlayerField(): sx = %d, sy = %d\n",sx,sy);
679 printf("DrawPlayerField(): This should never happen!\n");
684 if (element == EL_EXPLOSION)
687 action = (player->is_pushing ? ACTION_PUSHING :
688 player->is_digging ? ACTION_DIGGING :
689 player->is_collecting ? ACTION_COLLECTING :
690 player->is_moving ? ACTION_MOVING :
691 player->is_snapping ? ACTION_SNAPPING :
692 player->is_dropping ? ACTION_DROPPING :
693 player->is_waiting ? player->action_waiting : ACTION_DEFAULT);
695 InitPlayerGfxAnimation(player, action, move_dir);
697 /* ----------------------------------------------------------------------- */
698 /* draw things in the field the player is leaving, if needed */
699 /* ----------------------------------------------------------------------- */
702 if (player->is_moving)
704 if (player_is_moving)
707 if (Back[last_jx][last_jy] && IS_DRAWABLE(last_element))
709 DrawLevelElement(last_jx, last_jy, Back[last_jx][last_jy]);
711 if (last_element == EL_DYNAMITE_ACTIVE ||
712 last_element == EL_SP_DISK_RED_ACTIVE)
713 DrawDynamite(last_jx, last_jy);
715 DrawLevelFieldThruMask(last_jx, last_jy);
717 else if (last_element == EL_DYNAMITE_ACTIVE ||
718 last_element == EL_SP_DISK_RED_ACTIVE)
719 DrawDynamite(last_jx, last_jy);
721 DrawLevelField(last_jx, last_jy);
723 if (player->is_pushing && IN_SCR_FIELD(SCREENX(next_jx), SCREENY(next_jy)))
724 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
727 if (!IN_SCR_FIELD(sx, sy))
730 if (setup.direct_draw)
731 SetDrawtoField(DRAW_BUFFERED);
733 /* ----------------------------------------------------------------------- */
734 /* draw things behind the player, if needed */
735 /* ----------------------------------------------------------------------- */
738 DrawLevelElement(jx, jy, Back[jx][jy]);
739 else if (IS_ACTIVE_BOMB(element))
740 DrawLevelElement(jx, jy, EL_EMPTY);
743 if (player_is_moving && GfxElement[jx][jy] != EL_UNDEFINED)
745 if (GFX_CRUMBLED(GfxElement[jx][jy]))
746 DrawLevelFieldCrumbledSandDigging(jx, jy, move_dir, player->StepFrame);
749 int old_element = GfxElement[jx][jy];
750 int old_graphic = el_act_dir2img(old_element, action, move_dir);
751 int frame = getGraphicAnimationFrame(old_graphic, player->StepFrame);
753 DrawGraphic(sx, sy, old_graphic, frame);
758 GfxElement[jx][jy] = EL_UNDEFINED;
760 DrawLevelField(jx, jy);
764 /* ----------------------------------------------------------------------- */
765 /* draw player himself */
766 /* ----------------------------------------------------------------------- */
770 graphic = getPlayerGraphic(player, move_dir);
772 /* in the case of changed player action or direction, prevent the current
773 animation frame from being restarted for identical animations */
774 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
775 player->Frame = last_player_frame;
779 if (player->use_murphy_graphic)
781 static int last_horizontal_dir = MV_LEFT;
783 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
784 last_horizontal_dir = move_dir;
786 graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, move_dir);
788 if (graphic == IMG_SP_MURPHY) /* undefined => use special graphic */
790 int direction = (player->is_snapping ? move_dir : last_horizontal_dir);
792 graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, direction);
796 graphic = el_act_dir2img(player->element_nr, player->GfxAction, move_dir);
800 frame = getGraphicAnimationFrame(graphic, player->Frame);
804 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
805 sxx = player->GfxPos;
807 syy = player->GfxPos;
810 if (!setup.soft_scrolling && ScreenMovPos)
813 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
815 if (SHIELD_ON(player))
817 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
818 IMG_SHIELD_NORMAL_ACTIVE);
819 int frame = getGraphicAnimationFrame(graphic, -1);
821 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
824 /* ----------------------------------------------------------------------- */
825 /* draw things the player is pushing, if needed */
826 /* ----------------------------------------------------------------------- */
829 printf("::: %d, %d [%d, %d] [%d]\n",
830 player->is_pushing, player_is_moving, player->GfxAction,
831 player->is_moving, player_is_moving);
835 if (player->is_pushing && player->is_moving)
837 if (player->is_pushing && player_is_moving)
840 int px = SCREENX(next_jx), py = SCREENY(next_jy);
842 if (Back[next_jx][next_jy])
843 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
845 if ((sxx || syy) && element == EL_SOKOBAN_OBJECT)
846 DrawGraphicShiftedThruMask(px, py, sxx, syy, IMG_SOKOBAN_OBJECT, 0,
850 int element = MovingOrBlocked2Element(next_jx, next_jy);
851 int graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
853 int frame = getGraphicAnimationFrame(graphic, player->StepFrame);
855 int frame = getGraphicAnimationFrame(graphic, player->Frame);
858 DrawGraphicShifted(px, py, sxx, syy, graphic, frame,
859 NO_CUTTING, NO_MASKING);
863 /* ----------------------------------------------------------------------- */
864 /* draw things in front of player (active dynamite or dynabombs) */
865 /* ----------------------------------------------------------------------- */
867 if (IS_ACTIVE_BOMB(element))
869 graphic = el2img(element);
870 frame = getGraphicAnimationFrame(graphic, GfxFrame[jx][jy]);
872 if (game.emulation == EMU_SUPAPLEX)
873 DrawGraphic(sx, sy, IMG_SP_DISK_RED, frame);
875 DrawGraphicThruMask(sx, sy, graphic, frame);
878 if (player_is_moving && last_element == EL_EXPLOSION)
880 int graphic = el_act2img(GfxElement[last_jx][last_jy], ACTION_EXPLODING);
881 int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
882 int phase = ExplodePhase[last_jx][last_jy] - 1;
883 int frame = getGraphicAnimationFrame(graphic, phase - delay);
886 DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy), graphic, frame);
889 /* ----------------------------------------------------------------------- */
890 /* draw elements the player is just walking/passing through/under */
891 /* ----------------------------------------------------------------------- */
893 if (player_is_moving)
895 /* handle the field the player is leaving ... */
896 if (IS_ACCESSIBLE_INSIDE(last_element))
897 DrawLevelField(last_jx, last_jy);
898 else if (IS_ACCESSIBLE_UNDER(last_element))
899 DrawLevelFieldThruMask(last_jx, last_jy);
903 /* do not redraw accessible elements if the player is just pushing them */
904 if (!player_is_moving || !player->is_pushing)
906 /* ... and the field the player is entering */
907 if (IS_ACCESSIBLE_INSIDE(element))
908 DrawLevelField(jx, jy);
909 else if (IS_ACCESSIBLE_UNDER(element))
910 DrawLevelFieldThruMask(jx, jy);
916 /* !!! I have forgotton what this should be good for !!! */
917 /* !!! causes player being visible when pushing from within tubes !!! */
918 if (!player->is_pushing)
921 /* ... and the field the player is entering */
922 if (IS_ACCESSIBLE_INSIDE(element))
923 DrawLevelField(jx, jy);
924 else if (IS_ACCESSIBLE_UNDER(element))
925 DrawLevelFieldThruMask(jx, jy);
929 if (setup.direct_draw)
931 int dest_x = SX + SCREENX(MIN(jx, last_jx)) * TILEX;
932 int dest_y = SY + SCREENY(MIN(jy, last_jy)) * TILEY;
933 int x_size = TILEX * (1 + ABS(jx - last_jx));
934 int y_size = TILEY * (1 + ABS(jy - last_jy));
936 BlitBitmap(drawto_field, window,
937 dest_x, dest_y, x_size, y_size, dest_x, dest_y);
938 SetDrawtoField(DRAW_DIRECT);
941 MarkTileDirty(sx, sy);
944 void getGraphicSource(int graphic, int frame, Bitmap **bitmap, int *x, int *y)
946 struct GraphicInfo *g = &graphic_info[graphic];
950 if (g->offset_y == 0) /* frames are ordered horizontally */
952 int max_width = g->anim_frames_per_line * g->width;
954 *x = (g->src_x + frame * g->offset_x) % max_width;
955 *y = g->src_y + (g->src_x + frame * g->offset_x) / max_width * g->height;
957 else if (g->offset_x == 0) /* frames are ordered vertically */
959 int max_height = g->anim_frames_per_line * g->height;
961 *x = g->src_x + (g->src_y + frame * g->offset_y) / max_height * g->width;
962 *y = (g->src_y + frame * g->offset_y) % max_height;
964 else /* frames are ordered diagonally */
966 *x = g->src_x + frame * g->offset_x;
967 *y = g->src_y + frame * g->offset_y;
971 void DrawGraphic(int x, int y, int graphic, int frame)
974 if (!IN_SCR_FIELD(x, y))
976 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
977 printf("DrawGraphic(): This should never happen!\n");
982 DrawGraphicExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic, frame);
986 void DrawGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
992 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
993 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
996 void DrawGraphicThruMask(int x, int y, int graphic, int frame)
999 if (!IN_SCR_FIELD(x, y))
1001 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
1002 printf("DrawGraphicThruMask(): This should never happen!\n");
1007 DrawGraphicThruMaskExt(drawto_field, FX + x * TILEX, FY + y *TILEY, graphic,
1009 MarkTileDirty(x, y);
1012 void DrawGraphicThruMaskExt(DrawBuffer *d, int dest_x, int dest_y, int graphic,
1020 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1021 drawing_gc = src_bitmap->stored_clip_gc;
1023 GC drawing_gc = src_bitmap->stored_clip_gc;
1024 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
1025 int src_x = graphic_info[graphic].src_x;
1026 int src_y = graphic_info[graphic].src_y;
1027 int offset_x = graphic_info[graphic].offset_x;
1028 int offset_y = graphic_info[graphic].offset_y;
1030 src_x += frame * offset_x;
1031 src_y += frame * offset_y;
1035 SetClipOrigin(src_bitmap, drawing_gc, dest_x - src_x, dest_y - src_y);
1036 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX, TILEY, dest_x, dest_y);
1039 void DrawMiniGraphic(int x, int y, int graphic)
1041 DrawMiniGraphicExt(drawto, SX + x * MINI_TILEX,SY + y * MINI_TILEY, graphic);
1042 MarkTileDirty(x / 2, y / 2);
1045 void getMiniGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
1047 struct GraphicInfo *g = &graphic_info[graphic];
1048 int mini_startx = 0;
1049 int mini_starty = g->bitmap->height * 2 / 3;
1051 *bitmap = g->bitmap;
1052 *x = mini_startx + g->src_x / 2;
1053 *y = mini_starty + g->src_y / 2;
1056 void DrawMiniGraphicExt(DrawBuffer *d, int x, int y, int graphic)
1061 getMiniGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
1062 BlitBitmap(src_bitmap, d, src_x, src_y, MINI_TILEX, MINI_TILEY, x, y);
1065 void DrawGraphicShifted(int x, int y, int dx, int dy, int graphic, int frame,
1066 int cut_mode, int mask_mode)
1071 int width = TILEX, height = TILEY;
1077 DrawGraphic(x, y, graphic, frame);
1081 if (dx || dy) /* shifted graphic */
1083 if (x < BX1) /* object enters playfield from the left */
1090 else if (x > BX2) /* object enters playfield from the right */
1096 else if (x==BX1 && dx < 0) /* object leaves playfield to the left */
1102 else if (x==BX2 && dx > 0) /* object leaves playfield to the right */
1104 else if (dx) /* general horizontal movement */
1105 MarkTileDirty(x + SIGN(dx), y);
1107 if (y < BY1) /* object enters playfield from the top */
1109 if (cut_mode==CUT_BELOW) /* object completely above top border */
1117 else if (y > BY2) /* object enters playfield from the bottom */
1123 else if (y==BY1 && dy < 0) /* object leaves playfield to the top */
1129 else if (dy > 0 && cut_mode == CUT_ABOVE)
1131 if (y == BY2) /* object completely above bottom border */
1137 MarkTileDirty(x, y + 1);
1138 } /* object leaves playfield to the bottom */
1139 else if (dy > 0 && (y == BY2 || cut_mode == CUT_BELOW))
1141 else if (dy) /* general vertical movement */
1142 MarkTileDirty(x, y + SIGN(dy));
1146 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1148 src_bitmap = graphic_info[graphic].bitmap;
1149 src_x = graphic_info[graphic].src_x;
1150 src_y = graphic_info[graphic].src_y;
1151 offset_x = graphic_info[graphic].offset_x;
1152 offset_y = graphic_info[graphic].offset_y;
1154 src_x += frame * offset_x;
1155 src_y += frame * offset_y;
1158 drawing_gc = src_bitmap->stored_clip_gc;
1163 dest_x = FX + x * TILEX + dx;
1164 dest_y = FY + y * TILEY + dy;
1167 if (!IN_SCR_FIELD(x,y))
1169 printf("DrawGraphicShifted(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
1170 printf("DrawGraphicShifted(): This should never happen!\n");
1175 if (mask_mode == USE_MASKING)
1177 SetClipOrigin(src_bitmap, drawing_gc, dest_x - src_x, dest_y - src_y);
1178 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1182 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1185 MarkTileDirty(x, y);
1188 void DrawGraphicShiftedThruMask(int x, int y, int dx, int dy, int graphic,
1189 int frame, int cut_mode)
1191 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, USE_MASKING);
1194 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
1195 int cut_mode, int mask_mode)
1197 int lx = LEVELX(x), ly = LEVELY(y);
1201 if (IN_LEV_FIELD(lx, ly))
1203 SetRandomAnimationValue(lx, ly);
1205 graphic = el_act_dir2img(element, GfxAction[lx][ly], GfxDir[lx][ly]);
1206 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1208 else /* border element */
1210 graphic = el2img(element);
1211 frame = getGraphicAnimationFrame(graphic, -1);
1214 if (element == EL_EXPANDABLE_WALL)
1216 boolean left_stopped = FALSE, right_stopped = FALSE;
1218 if (!IN_LEV_FIELD(lx - 1, ly) || IS_WALL(Feld[lx - 1][ly]))
1219 left_stopped = TRUE;
1220 if (!IN_LEV_FIELD(lx + 1, ly) || IS_WALL(Feld[lx + 1][ly]))
1221 right_stopped = TRUE;
1223 if (left_stopped && right_stopped)
1225 else if (left_stopped)
1227 graphic = IMG_EXPANDABLE_WALL_GROWING_RIGHT;
1228 frame = graphic_info[graphic].anim_frames - 1;
1230 else if (right_stopped)
1232 graphic = IMG_EXPANDABLE_WALL_GROWING_LEFT;
1233 frame = graphic_info[graphic].anim_frames - 1;
1238 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, mask_mode);
1239 else if (mask_mode == USE_MASKING)
1240 DrawGraphicThruMask(x, y, graphic, frame);
1242 DrawGraphic(x, y, graphic, frame);
1245 void DrawLevelElementExt(int x, int y, int dx, int dy, int element,
1246 int cut_mode, int mask_mode)
1248 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1249 DrawScreenElementExt(SCREENX(x), SCREENY(y), dx, dy, element,
1250 cut_mode, mask_mode);
1253 void DrawScreenElementShifted(int x, int y, int dx, int dy, int element,
1256 DrawScreenElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1259 void DrawLevelElementShifted(int x, int y, int dx, int dy, int element,
1262 DrawLevelElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1265 void DrawLevelElementThruMask(int x, int y, int element)
1267 DrawLevelElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1270 void DrawLevelFieldThruMask(int x, int y)
1272 DrawLevelElementExt(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
1275 #define TILE_GFX_ELEMENT(x, y) \
1276 (GfxElement[x][y] != EL_UNDEFINED && Feld[x][y] != EL_EXPLOSION ? \
1277 GfxElement[x][y] : Feld[x][y])
1279 static void DrawLevelFieldCrumbledSandExt(int x, int y, int graphic, int frame)
1283 int sx = SCREENX(x), sy = SCREENY(y);
1285 int width, height, cx, cy, i;
1287 int crumbled_border_size = graphic_info[graphic].border_size;
1289 int snip = TILEX / 8; /* number of border pixels from "crumbled graphic" */
1291 static int xy[4][2] =
1300 if (x == 0 && y == 7)
1301 printf("::: %d, %d [%d]\n", GfxElement[x][y], Feld[x][y],
1302 crumbled_border_size);
1305 if (!IN_LEV_FIELD(x, y))
1308 element = TILE_GFX_ELEMENT(x, y);
1310 /* crumble field itself */
1311 if (GFX_CRUMBLED(element) && !IS_MOVING(x, y))
1313 if (!IN_SCR_FIELD(sx, sy))
1316 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1318 for (i = 0; i < 4; i++)
1320 int xx = x + xy[i][0];
1321 int yy = y + xy[i][1];
1324 element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1327 element = (IN_LEV_FIELD(xx, yy) ? Feld[xx][yy] : BorderElement);
1330 /* check if neighbour field is of same type */
1331 if (GFX_CRUMBLED(element) && !IS_MOVING(xx, yy))
1335 if (Feld[x][y] == EL_CUSTOM_START + 123)
1336 printf("::: crumble [%d] THE CHAOS ENGINE (%d, %d): %d, %d\n",
1337 i, Feld[x][y], element,
1338 GFX_CRUMBLED(element), IS_MOVING(x, y));
1341 if (i == 1 || i == 2)
1343 width = crumbled_border_size;
1345 cx = (i == 2 ? TILEX - crumbled_border_size : 0);
1351 height = crumbled_border_size;
1353 cy = (i == 3 ? TILEY - crumbled_border_size : 0);
1356 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1357 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
1360 MarkTileDirty(sx, sy);
1362 else /* crumble neighbour fields */
1365 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1368 for (i = 0; i < 4; i++)
1370 int xx = x + xy[i][0];
1371 int yy = y + xy[i][1];
1372 int sxx = sx + xy[i][0];
1373 int syy = sy + xy[i][1];
1376 if (!IN_LEV_FIELD(xx, yy) ||
1377 !IN_SCR_FIELD(sxx, syy) ||
1381 element = TILE_GFX_ELEMENT(xx, yy);
1383 if (!GFX_CRUMBLED(element))
1386 if (!IN_LEV_FIELD(xx, yy) ||
1387 !IN_SCR_FIELD(sxx, syy) ||
1388 !GFX_CRUMBLED(Feld[xx][yy]) ||
1394 graphic = el_act2crm(Feld[xx][yy], ACTION_DEFAULT);
1395 crumbled_border_size = graphic_info[graphic].border_size;
1397 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1400 if (i == 1 || i == 2)
1402 width = crumbled_border_size;
1404 cx = (i == 1 ? TILEX - crumbled_border_size : 0);
1410 height = crumbled_border_size;
1412 cy = (i == 0 ? TILEY - crumbled_border_size : 0);
1415 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1416 width, height, FX + sxx * TILEX + cx, FY + syy * TILEY + cy);
1418 MarkTileDirty(sxx, syy);
1423 void DrawLevelFieldCrumbledSand(int x, int y)
1428 if (!IN_LEV_FIELD(x, y))
1431 graphic = el_act2crm(Feld[x][y], ACTION_DEFAULT);
1433 DrawLevelFieldCrumbledSandExt(x, y, graphic, 0);
1435 DrawLevelFieldCrumbledSandExt(x, y, IMG_SAND_CRUMBLED, 0);
1439 void DrawLevelFieldCrumbledSandDigging(int x, int y, int direction,
1443 int graphic1 = el_act_dir2img(GfxElement[x][y], ACTION_DIGGING, direction);
1444 int graphic2 = el_act_dir2crm(GfxElement[x][y], ACTION_DIGGING, direction);
1446 int graphic1 = el_act_dir2img(EL_SAND, ACTION_DIGGING, direction);
1447 int graphic2 = el_act_dir2img(EL_SAND_CRUMBLED, ACTION_DIGGING, direction);
1449 int frame1 = getGraphicAnimationFrame(graphic1, step_frame);
1450 int frame2 = getGraphicAnimationFrame(graphic2, step_frame);
1451 int sx = SCREENX(x), sy = SCREENY(y);
1453 DrawGraphic(sx, sy, graphic1, frame1);
1454 DrawLevelFieldCrumbledSandExt(x, y, graphic2, frame2);
1457 void DrawLevelFieldCrumbledSandNeighbours(int x, int y)
1459 int sx = SCREENX(x), sy = SCREENY(y);
1460 static int xy[4][2] =
1469 for (i = 0; i < 4; i++)
1471 int xx = x + xy[i][0];
1472 int yy = y + xy[i][1];
1473 int sxx = sx + xy[i][0];
1474 int syy = sy + xy[i][1];
1476 if (!IN_LEV_FIELD(xx, yy) ||
1477 !IN_SCR_FIELD(sxx, syy) ||
1478 !GFX_CRUMBLED(Feld[xx][yy]) ||
1482 DrawLevelField(xx, yy);
1486 static int getBorderElement(int x, int y)
1490 { EL_STEELWALL_TOPLEFT, EL_INVISIBLE_STEELWALL_TOPLEFT },
1491 { EL_STEELWALL_TOPRIGHT, EL_INVISIBLE_STEELWALL_TOPRIGHT },
1492 { EL_STEELWALL_BOTTOMLEFT, EL_INVISIBLE_STEELWALL_BOTTOMLEFT },
1493 { EL_STEELWALL_BOTTOMRIGHT, EL_INVISIBLE_STEELWALL_BOTTOMRIGHT },
1494 { EL_STEELWALL_VERTICAL, EL_INVISIBLE_STEELWALL_VERTICAL },
1495 { EL_STEELWALL_HORIZONTAL, EL_INVISIBLE_STEELWALL_HORIZONTAL },
1496 { EL_STEELWALL, EL_INVISIBLE_STEELWALL }
1498 int steel_type = (BorderElement == EL_STEELWALL ? 0 : 1);
1499 int steel_position = (x == -1 && y == -1 ? 0 :
1500 x == lev_fieldx && y == -1 ? 1 :
1501 x == -1 && y == lev_fieldy ? 2 :
1502 x == lev_fieldx && y == lev_fieldy ? 3 :
1503 x == -1 || x == lev_fieldx ? 4 :
1504 y == -1 || y == lev_fieldy ? 5 : 6);
1506 return border[steel_position][steel_type];
1509 void DrawScreenElement(int x, int y, int element)
1511 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
1512 DrawLevelFieldCrumbledSand(LEVELX(x), LEVELY(y));
1515 void DrawLevelElement(int x, int y, int element)
1517 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1518 DrawScreenElement(SCREENX(x), SCREENY(y), element);
1521 void DrawScreenField(int x, int y)
1523 int lx = LEVELX(x), ly = LEVELY(y);
1524 int element, content;
1526 if (!IN_LEV_FIELD(lx, ly))
1528 if (lx < -1 || lx > lev_fieldx || ly < -1 || ly > lev_fieldy)
1531 element = getBorderElement(lx, ly);
1533 DrawScreenElement(x, y, element);
1537 element = Feld[lx][ly];
1538 content = Store[lx][ly];
1540 if (IS_MOVING(lx, ly))
1542 int horiz_move = (MovDir[lx][ly] == MV_LEFT || MovDir[lx][ly] == MV_RIGHT);
1543 boolean cut_mode = NO_CUTTING;
1545 if (element == EL_QUICKSAND_EMPTYING ||
1546 element == EL_MAGIC_WALL_EMPTYING ||
1547 element == EL_BD_MAGIC_WALL_EMPTYING ||
1548 element == EL_AMOEBA_DROPPING)
1549 cut_mode = CUT_ABOVE;
1550 else if (element == EL_QUICKSAND_FILLING ||
1551 element == EL_MAGIC_WALL_FILLING ||
1552 element == EL_BD_MAGIC_WALL_FILLING)
1553 cut_mode = CUT_BELOW;
1555 if (cut_mode == CUT_ABOVE)
1556 DrawScreenElementShifted(x, y, 0, 0, element, NO_CUTTING);
1558 DrawScreenElement(x, y, EL_EMPTY);
1561 DrawScreenElementShifted(x, y, MovPos[lx][ly], 0, element, NO_CUTTING);
1562 else if (cut_mode == NO_CUTTING)
1563 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], element, cut_mode);
1565 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], content, cut_mode);
1567 if (content == EL_ACID)
1569 int dir = MovDir[lx][ly];
1570 int newlx = lx + (dir == MV_LEFT ? -1 : dir == MV_RIGHT ? +1 : 0);
1571 int newly = ly + (dir == MV_UP ? -1 : dir == MV_DOWN ? +1 : 0);
1573 DrawLevelElementThruMask(newlx, newly, EL_ACID);
1576 else if (IS_BLOCKED(lx, ly))
1581 boolean cut_mode = NO_CUTTING;
1582 int element_old, content_old;
1584 Blocked2Moving(lx, ly, &oldx, &oldy);
1587 horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
1588 MovDir[oldx][oldy] == MV_RIGHT);
1590 element_old = Feld[oldx][oldy];
1591 content_old = Store[oldx][oldy];
1593 if (element_old == EL_QUICKSAND_EMPTYING ||
1594 element_old == EL_MAGIC_WALL_EMPTYING ||
1595 element_old == EL_BD_MAGIC_WALL_EMPTYING ||
1596 element_old == EL_AMOEBA_DROPPING)
1597 cut_mode = CUT_ABOVE;
1599 DrawScreenElement(x, y, EL_EMPTY);
1602 DrawScreenElementShifted(sx, sy, MovPos[oldx][oldy], 0, element_old,
1604 else if (cut_mode == NO_CUTTING)
1605 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], element_old,
1608 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], content_old,
1611 else if (IS_DRAWABLE(element))
1612 DrawScreenElement(x, y, element);
1614 DrawScreenElement(x, y, EL_EMPTY);
1617 void DrawLevelField(int x, int y)
1619 if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1620 DrawScreenField(SCREENX(x), SCREENY(y));
1621 else if (IS_MOVING(x, y))
1625 Moving2Blocked(x, y, &newx, &newy);
1626 if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
1627 DrawScreenField(SCREENX(newx), SCREENY(newy));
1629 else if (IS_BLOCKED(x, y))
1633 Blocked2Moving(x, y, &oldx, &oldy);
1634 if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
1635 DrawScreenField(SCREENX(oldx), SCREENY(oldy));
1639 void DrawMiniElement(int x, int y, int element)
1643 graphic = el2edimg(element);
1644 DrawMiniGraphic(x, y, graphic);
1647 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
1649 int x = sx + scroll_x, y = sy + scroll_y;
1651 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
1652 DrawMiniElement(sx, sy, EL_EMPTY);
1653 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
1654 DrawMiniElement(sx, sy, Feld[x][y]);
1656 DrawMiniGraphic(sx, sy, el2edimg(getBorderElement(x, y)));
1659 void DrawEnvelopeBackground(int envelope_nr, int startx, int starty,
1660 int x, int y, int xsize, int ysize, int font_nr)
1662 int font_width = getFontWidth(font_nr);
1663 int font_height = getFontHeight(font_nr);
1664 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1667 int dst_x = SX + startx + x * font_width;
1668 int dst_y = SY + starty + y * font_height;
1669 int width = graphic_info[graphic].width;
1670 int height = graphic_info[graphic].height;
1671 int inner_width = MAX(width - 2 * font_width, font_width);
1672 int inner_height = MAX(height - 2 * font_height, font_height);
1673 int inner_sx = (width >= 3 * font_width ? font_width : 0);
1674 int inner_sy = (height >= 3 * font_height ? font_height : 0);
1675 boolean draw_masked = graphic_info[graphic].draw_masked;
1677 getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
1679 if (src_bitmap == NULL || width < font_width || height < font_height)
1681 ClearRectangle(drawto, dst_x, dst_y, font_width, font_height);
1685 src_x += (x == 0 ? 0 : x == xsize - 1 ? width - font_width :
1686 inner_sx + (x - 1) * font_width % inner_width);
1687 src_y += (y == 0 ? 0 : y == ysize - 1 ? height - font_height :
1688 inner_sy + (y - 1) * font_height % inner_height);
1692 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1693 dst_x - src_x, dst_y - src_y);
1694 BlitBitmapMasked(src_bitmap, drawto, src_x, src_y, font_width, font_height,
1698 BlitBitmap(src_bitmap, drawto, src_x, src_y, font_width, font_height,
1702 void AnimateEnvelope(int envelope_nr, int anim_mode, int action)
1704 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1706 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
1707 int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
1709 boolean draw_masked = graphic_info[graphic].draw_masked;
1710 int mask_mode = (draw_masked ? BLIT_MASKED : BLIT_ON_BACKGROUND);
1712 boolean ffwd_delay = (tape.playing && tape.fast_forward);
1713 boolean no_delay = (tape.warp_forward);
1714 unsigned long anim_delay = 0;
1715 int frame_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
1716 int anim_delay_value = (no_delay ? 0 : frame_delay_value);
1717 int font_nr = FONT_ENVELOPE_1 + envelope_nr;
1718 int font_width = getFontWidth(font_nr);
1719 int font_height = getFontHeight(font_nr);
1720 int max_xsize = level.envelope_xsize[envelope_nr];
1721 int max_ysize = level.envelope_ysize[envelope_nr];
1722 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize : 0);
1723 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize : 0);
1724 int xend = max_xsize;
1725 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize : 0);
1726 int xstep = (xstart < xend ? 1 : 0);
1727 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
1730 for (x = xstart, y = ystart; x <= xend && y <= yend; x += xstep, y += ystep)
1732 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
1733 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
1734 int sx = (SXSIZE - xsize * font_width) / 2;
1735 int sy = (SYSIZE - ysize * font_height) / 2;
1738 SetDrawtoField(DRAW_BUFFERED);
1740 BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
1742 SetDrawtoField(DRAW_BACKBUFFER);
1744 for (yy = 0; yy < ysize; yy++) for (xx = 0; xx < xsize; xx++)
1745 DrawEnvelopeBackground(envelope_nr, sx,sy, xx,yy, xsize, ysize, font_nr);
1747 DrawTextToTextArea(SX + sx + font_width, SY + sy + font_height,
1748 level.envelope_text[envelope_nr], font_nr, max_xsize,
1749 xsize - 2, ysize - 2, mask_mode);
1751 redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
1754 WaitUntilDelayReached(&anim_delay, anim_delay_value / 2);
1758 void ShowEnvelope(int envelope_nr)
1760 int element = EL_ENVELOPE_1 + envelope_nr;
1761 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1762 int sound_opening = element_info[element].sound[ACTION_OPENING];
1763 int sound_closing = element_info[element].sound[ACTION_CLOSING];
1764 boolean ffwd_delay = (tape.playing && tape.fast_forward);
1765 boolean no_delay = (tape.warp_forward);
1766 int normal_delay_value = ONE_SECOND_DELAY / (ffwd_delay ? 2 : 1);
1767 int wait_delay_value = (no_delay ? 0 : normal_delay_value);
1768 int anim_mode = graphic_info[graphic].anim_mode;
1769 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
1770 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
1772 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
1774 PlaySoundStereo(sound_opening, SOUND_MIDDLE);
1776 if (anim_mode == ANIM_DEFAULT)
1777 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_OPENING);
1779 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_OPENING);
1782 Delay(wait_delay_value);
1784 WaitForEventToContinue();
1786 PlaySoundStereo(sound_closing, SOUND_MIDDLE);
1788 if (anim_mode != ANIM_NONE)
1789 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_CLOSING);
1791 if (anim_mode == ANIM_DEFAULT)
1792 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_CLOSING);
1794 game.envelope_active = FALSE;
1796 SetDrawtoField(DRAW_BUFFERED);
1798 redraw_mask |= REDRAW_FIELD;
1802 void getMicroGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
1804 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
1805 int mini_startx = src_bitmap->width * 3 / 4;
1806 int mini_starty = src_bitmap->height * 2 / 3;
1807 int src_x = mini_startx + graphic_info[graphic].src_x / 8;
1808 int src_y = mini_starty + graphic_info[graphic].src_y / 8;
1810 *bitmap = src_bitmap;
1815 void DrawMicroElement(int xpos, int ypos, int element)
1819 int graphic = el2preimg(element);
1821 getMicroGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
1822 BlitBitmap(src_bitmap, drawto, src_x, src_y, MICRO_TILEX, MICRO_TILEY,
1830 SetDrawBackgroundMask(REDRAW_NONE);
1833 for (x = BX1; x <= BX2; x++)
1834 for (y = BY1; y <= BY2; y++)
1835 DrawScreenField(x, y);
1837 redraw_mask |= REDRAW_FIELD;
1840 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
1844 for (x = 0; x < size_x; x++)
1845 for (y = 0; y < size_y; y++)
1846 DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
1848 redraw_mask |= REDRAW_FIELD;
1851 static void DrawMicroLevelExt(int xpos, int ypos, int from_x, int from_y)
1855 DrawBackground(xpos, ypos, MICROLEV_XSIZE, MICROLEV_YSIZE);
1857 if (lev_fieldx < STD_LEV_FIELDX)
1858 xpos += (STD_LEV_FIELDX - lev_fieldx) / 2 * MICRO_TILEX;
1859 if (lev_fieldy < STD_LEV_FIELDY)
1860 ypos += (STD_LEV_FIELDY - lev_fieldy) / 2 * MICRO_TILEY;
1862 xpos += MICRO_TILEX;
1863 ypos += MICRO_TILEY;
1865 for (x = -1; x <= STD_LEV_FIELDX; x++)
1867 for (y = -1; y <= STD_LEV_FIELDY; y++)
1869 int lx = from_x + x, ly = from_y + y;
1871 if (lx >= 0 && lx < lev_fieldx && ly >= 0 && ly < lev_fieldy)
1872 DrawMicroElement(xpos + x * MICRO_TILEX, ypos + y * MICRO_TILEY,
1873 level.field[lx][ly]);
1874 else if (lx >= -1 && lx < lev_fieldx+1 && ly >= -1 && ly < lev_fieldy+1
1875 && BorderElement != EL_EMPTY)
1876 DrawMicroElement(xpos + x * MICRO_TILEX, ypos + y * MICRO_TILEY,
1877 getBorderElement(lx, ly));
1881 redraw_mask |= REDRAW_MICROLEVEL;
1884 #define MICROLABEL_EMPTY 0
1885 #define MICROLABEL_LEVEL_NAME 1
1886 #define MICROLABEL_CREATED_BY 2
1887 #define MICROLABEL_LEVEL_AUTHOR 3
1888 #define MICROLABEL_IMPORTED_FROM 4
1889 #define MICROLABEL_LEVEL_IMPORT_INFO 5
1891 static void DrawMicroLevelLabelExt(int mode)
1893 char label_text[MAX_OUTPUT_LINESIZE + 1];
1894 int max_len_label_text;
1895 int font_nr = FONT_TEXT_2;
1897 if (mode == MICROLABEL_CREATED_BY || mode == MICROLABEL_IMPORTED_FROM)
1898 font_nr = FONT_TEXT_3;
1900 max_len_label_text = SXSIZE / getFontWidth(font_nr);
1902 DrawBackground(SX, MICROLABEL_YPOS, SXSIZE, getFontHeight(font_nr));
1904 strncpy(label_text, (mode == MICROLABEL_LEVEL_NAME ? level.name :
1905 mode == MICROLABEL_CREATED_BY ? "created by" :
1906 mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
1907 mode == MICROLABEL_IMPORTED_FROM ? "imported from" :
1908 mode == MICROLABEL_LEVEL_IMPORT_INFO ?
1909 leveldir_current->imported_from : ""),
1910 max_len_label_text);
1911 label_text[max_len_label_text] = '\0';
1913 if (strlen(label_text) > 0)
1915 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
1916 int lypos = MICROLABEL_YPOS;
1918 DrawText(lxpos, lypos, label_text, font_nr);
1921 redraw_mask |= REDRAW_MICROLEVEL;
1924 void DrawMicroLevel(int xpos, int ypos, boolean restart)
1926 static unsigned long scroll_delay = 0;
1927 static unsigned long label_delay = 0;
1928 static int from_x, from_y, scroll_direction;
1929 static int label_state, label_counter;
1930 int last_game_status = game_status; /* save current game status */
1932 /* force PREVIEW font on preview level */
1933 game_status = GAME_MODE_PSEUDO_PREVIEW;
1937 from_x = from_y = 0;
1938 scroll_direction = MV_RIGHT;
1942 DrawMicroLevelExt(xpos, ypos, from_x, from_y);
1943 DrawMicroLevelLabelExt(label_state);
1945 /* initialize delay counters */
1946 DelayReached(&scroll_delay, 0);
1947 DelayReached(&label_delay, 0);
1949 if (leveldir_current->name)
1951 int text_width = getTextWidth(leveldir_current->name, FONT_TEXT_1);
1952 int lxpos = SX + (SXSIZE - text_width) / 2;
1953 int lypos = SY + 352;
1955 DrawText(lxpos, lypos, leveldir_current->name, FONT_TEXT_1);
1958 game_status = last_game_status; /* restore current game status */
1963 /* scroll micro level, if needed */
1964 if ((lev_fieldx > STD_LEV_FIELDX || lev_fieldy > STD_LEV_FIELDY) &&
1965 DelayReached(&scroll_delay, MICROLEVEL_SCROLL_DELAY))
1967 switch (scroll_direction)
1973 scroll_direction = MV_UP;
1977 if (from_x < lev_fieldx - STD_LEV_FIELDX)
1980 scroll_direction = MV_DOWN;
1987 scroll_direction = MV_RIGHT;
1991 if (from_y < lev_fieldy - STD_LEV_FIELDY)
1994 scroll_direction = MV_LEFT;
2001 DrawMicroLevelExt(xpos, ypos, from_x, from_y);
2004 /* redraw micro level label, if needed */
2005 if (strcmp(level.name, NAMELESS_LEVEL_NAME) != 0 &&
2006 strcmp(level.author, ANONYMOUS_NAME) != 0 &&
2007 strcmp(level.author, leveldir_current->name) != 0 &&
2008 DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
2010 int max_label_counter = 23;
2012 if (leveldir_current->imported_from != NULL)
2013 max_label_counter += 14;
2015 label_counter = (label_counter + 1) % max_label_counter;
2016 label_state = (label_counter >= 0 && label_counter <= 7 ?
2017 MICROLABEL_LEVEL_NAME :
2018 label_counter >= 9 && label_counter <= 12 ?
2019 MICROLABEL_CREATED_BY :
2020 label_counter >= 14 && label_counter <= 21 ?
2021 MICROLABEL_LEVEL_AUTHOR :
2022 label_counter >= 23 && label_counter <= 26 ?
2023 MICROLABEL_IMPORTED_FROM :
2024 label_counter >= 28 && label_counter <= 35 ?
2025 MICROLABEL_LEVEL_IMPORT_INFO : MICROLABEL_EMPTY);
2026 DrawMicroLevelLabelExt(label_state);
2029 game_status = last_game_status; /* restore current game status */
2032 void WaitForEventToContinue()
2034 boolean still_wait = TRUE;
2036 /* simulate releasing mouse button over last gadget, if still pressed */
2038 HandleGadgets(-1, -1, 0);
2040 button_status = MB_RELEASED;
2052 case EVENT_BUTTONPRESS:
2053 case EVENT_KEYPRESS:
2057 case EVENT_KEYRELEASE:
2058 ClearPlayerAction();
2062 HandleOtherEvents(&event);
2066 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
2073 /* don't eat all CPU time */
2078 #define MAX_REQUEST_LINES 13
2079 #define MAX_REQUEST_LINE_FONT1_LEN 7
2080 #define MAX_REQUEST_LINE_FONT2_LEN 10
2082 boolean Request(char *text, unsigned int req_state)
2084 int mx, my, ty, result = -1;
2085 unsigned int old_door_state;
2086 int last_game_status = game_status; /* save current game status */
2087 int max_request_line_len = MAX_REQUEST_LINE_FONT1_LEN;
2088 int font_nr = FONT_TEXT_2;
2089 int max_word_len = 0;
2092 for (text_ptr = text; *text_ptr; text_ptr++)
2094 max_word_len = (*text_ptr != ' ' ? max_word_len + 1 : 0);
2096 if (max_word_len > MAX_REQUEST_LINE_FONT1_LEN)
2098 max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
2099 font_nr = FONT_LEVEL_NUMBER;
2106 /* disable deactivated drawing when quick-loading level tape recording */
2107 if (tape.playing && tape.deactivate_display)
2108 TapeDeactivateDisplayOff(TRUE);
2112 SetMouseCursor(CURSOR_DEFAULT);
2115 #if defined(NETWORK_AVALIABLE)
2116 /* pause network game while waiting for request to answer */
2117 if (options.network &&
2118 game_status == GAME_MODE_PLAYING &&
2119 req_state & REQUEST_WAIT_FOR_INPUT)
2120 SendToServer_PausePlaying();
2123 old_door_state = GetDoorState();
2125 /* simulate releasing mouse button over last gadget, if still pressed */
2127 HandleGadgets(-1, -1, 0);
2131 if (old_door_state & DOOR_OPEN_1)
2133 CloseDoor(DOOR_CLOSE_1);
2135 /* save old door content */
2136 BlitBitmap(bitmap_db_door, bitmap_db_door,
2137 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
2138 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
2141 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
2143 /* clear door drawing field */
2144 DrawBackground(DX, DY, DXSIZE, DYSIZE);
2146 /* force DOOR font on preview level */
2147 game_status = GAME_MODE_PSEUDO_DOOR;
2149 /* write text for request */
2150 for (ty = 0; ty < MAX_REQUEST_LINES; ty++)
2152 char text_line[max_request_line_len + 1];
2158 for (tl = 0, tx = 0; tx < max_request_line_len; tl++, tx++)
2161 if (!tc || tc == ' ')
2172 strncpy(text_line, text, tl);
2175 DrawText(DX + (DXSIZE - tl * getFontWidth(font_nr)) / 2,
2176 DY + 8 + ty * (getFontHeight(font_nr) + 2),
2177 text_line, font_nr);
2179 text += tl + (tc == ' ' ? 1 : 0);
2182 game_status = last_game_status; /* restore current game status */
2184 if (req_state & REQ_ASK)
2186 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
2187 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
2189 else if (req_state & REQ_CONFIRM)
2191 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
2193 else if (req_state & REQ_PLAYER)
2195 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
2196 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
2197 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
2198 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
2201 /* copy request gadgets to door backbuffer */
2202 BlitBitmap(drawto, bitmap_db_door,
2203 DX, DY, DXSIZE, DYSIZE,
2204 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2206 OpenDoor(DOOR_OPEN_1);
2212 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
2214 SetDrawBackgroundMask(REDRAW_FIELD);
2219 if (game_status != GAME_MODE_MAIN)
2222 button_status = MB_RELEASED;
2224 request_gadget_id = -1;
2226 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
2229 SetMouseCursor(CURSOR_DEFAULT);
2242 case EVENT_BUTTONPRESS:
2243 case EVENT_BUTTONRELEASE:
2244 case EVENT_MOTIONNOTIFY:
2246 if (event.type == EVENT_MOTIONNOTIFY)
2248 if (!PointerInWindow(window))
2249 continue; /* window and pointer are on different screens */
2254 motion_status = TRUE;
2255 mx = ((MotionEvent *) &event)->x;
2256 my = ((MotionEvent *) &event)->y;
2260 motion_status = FALSE;
2261 mx = ((ButtonEvent *) &event)->x;
2262 my = ((ButtonEvent *) &event)->y;
2263 if (event.type == EVENT_BUTTONPRESS)
2264 button_status = ((ButtonEvent *) &event)->button;
2266 button_status = MB_RELEASED;
2269 /* this sets 'request_gadget_id' */
2270 HandleGadgets(mx, my, button_status);
2272 switch(request_gadget_id)
2274 case TOOL_CTRL_ID_YES:
2277 case TOOL_CTRL_ID_NO:
2280 case TOOL_CTRL_ID_CONFIRM:
2281 result = TRUE | FALSE;
2284 case TOOL_CTRL_ID_PLAYER_1:
2287 case TOOL_CTRL_ID_PLAYER_2:
2290 case TOOL_CTRL_ID_PLAYER_3:
2293 case TOOL_CTRL_ID_PLAYER_4:
2304 case EVENT_KEYPRESS:
2305 switch(GetEventKey((KeyEvent *)&event, TRUE))
2318 if (req_state & REQ_PLAYER)
2322 case EVENT_KEYRELEASE:
2323 ClearPlayerAction();
2327 HandleOtherEvents(&event);
2331 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
2333 int joy = AnyJoystick();
2335 if (joy & JOY_BUTTON_1)
2337 else if (joy & JOY_BUTTON_2)
2343 /* don't eat all CPU time */
2347 if (game_status != GAME_MODE_MAIN)
2352 if (!(req_state & REQ_STAY_OPEN))
2354 CloseDoor(DOOR_CLOSE_1);
2356 if (((old_door_state & DOOR_OPEN_1) && !(req_state & REQ_STAY_CLOSED)) ||
2357 (req_state & REQ_REOPEN))
2358 OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
2363 SetDrawBackgroundMask(REDRAW_FIELD);
2365 #if defined(NETWORK_AVALIABLE)
2366 /* continue network game after request */
2367 if (options.network &&
2368 game_status == GAME_MODE_PLAYING &&
2369 req_state & REQUEST_WAIT_FOR_INPUT)
2370 SendToServer_ContinuePlaying();
2374 /* restore deactivated drawing when quick-loading level tape recording */
2375 if (tape.playing && tape.deactivate_display)
2376 TapeDeactivateDisplayOn();
2382 unsigned int OpenDoor(unsigned int door_state)
2384 if (door_state & DOOR_COPY_BACK)
2386 if (door_state & DOOR_OPEN_1)
2387 BlitBitmap(bitmap_db_door, bitmap_db_door,
2388 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
2389 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2391 if (door_state & DOOR_OPEN_2)
2392 BlitBitmap(bitmap_db_door, bitmap_db_door,
2393 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY2, VXSIZE, VYSIZE,
2394 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
2396 door_state &= ~DOOR_COPY_BACK;
2399 return MoveDoor(door_state);
2402 unsigned int CloseDoor(unsigned int door_state)
2404 unsigned int old_door_state = GetDoorState();
2406 if (!(door_state & DOOR_NO_COPY_BACK))
2408 if (old_door_state & DOOR_OPEN_1)
2409 BlitBitmap(backbuffer, bitmap_db_door,
2410 DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2412 if (old_door_state & DOOR_OPEN_2)
2413 BlitBitmap(backbuffer, bitmap_db_door,
2414 VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
2416 door_state &= ~DOOR_NO_COPY_BACK;
2419 return MoveDoor(door_state);
2422 unsigned int GetDoorState()
2424 return MoveDoor(DOOR_GET_STATE);
2427 unsigned int SetDoorState(unsigned int door_state)
2429 return MoveDoor(door_state | DOOR_SET_STATE);
2432 unsigned int MoveDoor(unsigned int door_state)
2434 static int door1 = DOOR_OPEN_1;
2435 static int door2 = DOOR_CLOSE_2;
2436 unsigned long door_delay = 0;
2437 unsigned long door_delay_value;
2440 if (door_state == DOOR_GET_STATE)
2441 return(door1 | door2);
2443 if (door_state & DOOR_SET_STATE)
2445 if (door_state & DOOR_ACTION_1)
2446 door1 = door_state & DOOR_ACTION_1;
2447 if (door_state & DOOR_ACTION_2)
2448 door2 = door_state & DOOR_ACTION_2;
2450 return(door1 | door2);
2453 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
2454 door_state &= ~DOOR_OPEN_1;
2455 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
2456 door_state &= ~DOOR_CLOSE_1;
2457 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
2458 door_state &= ~DOOR_OPEN_2;
2459 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
2460 door_state &= ~DOOR_CLOSE_2;
2462 door_delay_value = (door_state & DOOR_ACTION_1 ? door_1.step_delay :
2465 if (setup.quick_doors)
2467 stepsize = 20; /* must be choosen to always draw last frame */
2468 door_delay_value = 0;
2471 StopSound(SND_DOOR_OPENING);
2472 StopSound(SND_DOOR_CLOSING);
2476 if (global.autoplay_leveldir)
2478 door_state |= DOOR_NO_DELAY;
2479 door_state &= ~DOOR_CLOSE_ALL;
2482 if (door_state & DOOR_ACTION)
2484 boolean door_1_done = !(door_state & DOOR_ACTION_1);
2485 boolean door_2_done = !(door_state & DOOR_ACTION_2);
2486 int start = ((door_state & DOOR_NO_DELAY) ? DXSIZE : 0);
2487 int end = (door_state & DOOR_ACTION_1 &&
2488 door_1.anim_mode == ANIM_VERTICAL ? DYSIZE : DXSIZE);
2491 if (!(door_state & DOOR_NO_DELAY) && !setup.quick_doors)
2493 /* opening door sound has priority over simultaneously closing door */
2494 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
2495 PlaySoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
2496 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
2497 PlaySoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
2500 for (x = start; x <= end && !(door_1_done && door_2_done); x += stepsize)
2502 Bitmap *bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
2503 GC gc = bitmap->stored_clip_gc;
2505 if (door_state & DOOR_ACTION_1)
2507 int a = MIN(x * door_1.step_offset, end);
2508 int i = (door_state & DOOR_OPEN_1 ? end - a : a);
2512 BlitBitmap(bitmap_db_door, drawto,
2513 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + i / 2,
2514 DXSIZE, DYSIZE - i / 2, DX, DY);
2516 ClearRectangle(drawto, DX, DY + DYSIZE - i / 2, DXSIZE, i / 2);
2519 if (door_1.anim_mode == ANIM_HORIZONTAL && x <= DXSIZE)
2521 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
2522 int dst1_x = DX + DXSIZE - i, dst1_y = DY;
2523 int src2_x = DXSIZE - i, src2_y = DOOR_GFX_PAGEY1;
2524 int dst2_x = DX, dst2_y = DY;
2525 int width = i, height = DYSIZE;
2527 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2528 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2531 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2532 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2535 else if (door_1.anim_mode == ANIM_VERTICAL && x <= DYSIZE)
2537 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
2538 int dst1_x = DX, dst1_y = DY + DYSIZE - i;
2539 int src2_x = 0, src2_y = DOOR_GFX_PAGEY1 + DYSIZE - i;
2540 int dst2_x = DX, dst2_y = DY;
2541 int width = DXSIZE, height = i;
2543 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2544 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2547 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2548 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2551 else if (x <= DXSIZE) /* ANIM_DEFAULT */
2553 int j = (door_1.anim_mode == ANIM_DEFAULT ? (DXSIZE - i) / 3 : 0);
2555 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2556 BlitBitmapMasked(bitmap, drawto,
2557 DXSIZE, DOOR_GFX_PAGEY1, i, 77,
2558 DX + DXSIZE - i, DY + j);
2559 BlitBitmapMasked(bitmap, drawto,
2560 DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63,
2561 DX + DXSIZE - i, DY + 140 + j);
2562 SetClipOrigin(bitmap, gc, DX - DXSIZE + i,
2563 DY - (DOOR_GFX_PAGEY1 + j));
2564 BlitBitmapMasked(bitmap, drawto,
2565 DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j,
2567 BlitBitmapMasked(bitmap, drawto,
2568 DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63,
2571 BlitBitmapMasked(bitmap, drawto,
2572 DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
2574 BlitBitmapMasked(bitmap, drawto,
2575 DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
2577 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2578 BlitBitmapMasked(bitmap, drawto,
2579 DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
2580 DX + DXSIZE - i, DY + 77 + j);
2581 BlitBitmapMasked(bitmap, drawto,
2582 DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
2583 DX + DXSIZE - i, DY + 203 + j);
2586 redraw_mask |= REDRAW_DOOR_1;
2587 door_1_done = (a == end);
2590 if (door_state & DOOR_ACTION_2)
2592 int a = MIN(x * door_2.step_offset, VXSIZE);
2593 int i = (door_state & DOOR_OPEN_2 ? VXSIZE - a : a);
2597 BlitBitmap(bitmap_db_door, drawto,
2598 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + i / 2,
2599 VXSIZE, VYSIZE - i / 2, VX, VY);
2601 ClearRectangle(drawto, VX, VY + VYSIZE - i / 2, VXSIZE, i / 2);
2604 if (door_2.anim_mode == ANIM_HORIZONTAL && x <= VXSIZE)
2606 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
2607 int dst1_x = VX + VXSIZE - i, dst1_y = VY;
2608 int src2_x = VXSIZE - i, src2_y = DOOR_GFX_PAGEY2;
2609 int dst2_x = VX, dst2_y = VY;
2610 int width = i, height = VYSIZE;
2612 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2613 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2616 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2617 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2620 else if (door_2.anim_mode == ANIM_VERTICAL && x <= VYSIZE)
2622 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
2623 int dst1_x = VX, dst1_y = VY + VYSIZE - i;
2624 int src2_x = 0, src2_y = DOOR_GFX_PAGEY2 + VYSIZE - i;
2625 int dst2_x = VX, dst2_y = VY;
2626 int width = VXSIZE, height = i;
2628 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2629 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2632 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2633 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2636 else if (x <= VXSIZE) /* ANIM_DEFAULT */
2638 int j = (door_2.anim_mode == ANIM_DEFAULT ? (VXSIZE - i) / 3 : 0);
2640 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2641 BlitBitmapMasked(bitmap, drawto,
2642 VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2,
2643 VX + VXSIZE - i, VY + j);
2644 SetClipOrigin(bitmap, gc,
2645 VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
2646 BlitBitmapMasked(bitmap, drawto,
2647 VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j,
2650 BlitBitmapMasked(bitmap, drawto,
2651 VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2,
2652 i, VYSIZE / 2, VX, VY + VYSIZE / 2 - j);
2653 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2654 BlitBitmapMasked(bitmap, drawto,
2655 VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2,
2657 VX + VXSIZE - i, VY + VYSIZE / 2 + j);
2660 redraw_mask |= REDRAW_DOOR_2;
2661 door_2_done = (a == VXSIZE);
2666 if (game_status == GAME_MODE_MAIN)
2669 if (!(door_state & DOOR_NO_DELAY))
2670 WaitUntilDelayReached(&door_delay, door_delay_value);
2675 if (setup.quick_doors)
2677 StopSound(SND_DOOR_OPENING);
2678 StopSound(SND_DOOR_CLOSING);
2682 if (door_state & DOOR_ACTION_1)
2683 door1 = door_state & DOOR_ACTION_1;
2684 if (door_state & DOOR_ACTION_2)
2685 door2 = door_state & DOOR_ACTION_2;
2687 return (door1 | door2);
2690 void DrawSpecialEditorDoor()
2692 /* draw bigger toolbox window */
2693 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
2694 DOOR_GFX_PAGEX7, 0, EXSIZE + 8, 8,
2696 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
2697 EX - 4, VY - 4, EXSIZE + 8, EYSIZE - VYSIZE + 4,
2700 redraw_mask |= REDRAW_ALL;
2703 void UndrawSpecialEditorDoor()
2705 /* draw normal tape recorder window */
2706 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
2707 EX - 4, EY - 12, EXSIZE + 8, EYSIZE - VYSIZE + 12,
2710 redraw_mask |= REDRAW_ALL;
2714 /* ---------- new tool button stuff ---------------------------------------- */
2716 /* graphic position values for tool buttons */
2717 #define TOOL_BUTTON_YES_XPOS 2
2718 #define TOOL_BUTTON_YES_YPOS 250
2719 #define TOOL_BUTTON_YES_GFX_YPOS 0
2720 #define TOOL_BUTTON_YES_XSIZE 46
2721 #define TOOL_BUTTON_YES_YSIZE 28
2722 #define TOOL_BUTTON_NO_XPOS 52
2723 #define TOOL_BUTTON_NO_YPOS TOOL_BUTTON_YES_YPOS
2724 #define TOOL_BUTTON_NO_GFX_YPOS TOOL_BUTTON_YES_GFX_YPOS
2725 #define TOOL_BUTTON_NO_XSIZE TOOL_BUTTON_YES_XSIZE
2726 #define TOOL_BUTTON_NO_YSIZE TOOL_BUTTON_YES_YSIZE
2727 #define TOOL_BUTTON_CONFIRM_XPOS TOOL_BUTTON_YES_XPOS
2728 #define TOOL_BUTTON_CONFIRM_YPOS TOOL_BUTTON_YES_YPOS
2729 #define TOOL_BUTTON_CONFIRM_GFX_YPOS 30
2730 #define TOOL_BUTTON_CONFIRM_XSIZE 96
2731 #define TOOL_BUTTON_CONFIRM_YSIZE TOOL_BUTTON_YES_YSIZE
2732 #define TOOL_BUTTON_PLAYER_XSIZE 30
2733 #define TOOL_BUTTON_PLAYER_YSIZE 30
2734 #define TOOL_BUTTON_PLAYER_GFX_XPOS 5
2735 #define TOOL_BUTTON_PLAYER_GFX_YPOS 185
2736 #define TOOL_BUTTON_PLAYER_XPOS (5 + TOOL_BUTTON_PLAYER_XSIZE / 2)
2737 #define TOOL_BUTTON_PLAYER_YPOS (215 - TOOL_BUTTON_PLAYER_YSIZE / 2)
2738 #define TOOL_BUTTON_PLAYER1_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2739 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2740 #define TOOL_BUTTON_PLAYER2_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2741 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2742 #define TOOL_BUTTON_PLAYER3_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2743 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2744 #define TOOL_BUTTON_PLAYER4_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2745 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2746 #define TOOL_BUTTON_PLAYER1_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2747 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2748 #define TOOL_BUTTON_PLAYER2_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2749 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2750 #define TOOL_BUTTON_PLAYER3_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2751 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2752 #define TOOL_BUTTON_PLAYER4_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2753 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2762 } toolbutton_info[NUM_TOOL_BUTTONS] =
2765 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_GFX_YPOS,
2766 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_YPOS,
2767 TOOL_BUTTON_YES_XSIZE, TOOL_BUTTON_YES_YSIZE,
2772 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_GFX_YPOS,
2773 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_YPOS,
2774 TOOL_BUTTON_NO_XSIZE, TOOL_BUTTON_NO_YSIZE,
2779 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_GFX_YPOS,
2780 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_YPOS,
2781 TOOL_BUTTON_CONFIRM_XSIZE, TOOL_BUTTON_CONFIRM_YSIZE,
2782 TOOL_CTRL_ID_CONFIRM,
2786 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2787 TOOL_BUTTON_PLAYER1_XPOS, TOOL_BUTTON_PLAYER1_YPOS,
2788 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2789 TOOL_CTRL_ID_PLAYER_1,
2793 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2794 TOOL_BUTTON_PLAYER2_XPOS, TOOL_BUTTON_PLAYER2_YPOS,
2795 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2796 TOOL_CTRL_ID_PLAYER_2,
2800 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2801 TOOL_BUTTON_PLAYER3_XPOS, TOOL_BUTTON_PLAYER3_YPOS,
2802 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2803 TOOL_CTRL_ID_PLAYER_3,
2807 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2808 TOOL_BUTTON_PLAYER4_XPOS, TOOL_BUTTON_PLAYER4_YPOS,
2809 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2810 TOOL_CTRL_ID_PLAYER_4,
2815 void CreateToolButtons()
2819 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
2821 Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
2822 Bitmap *deco_bitmap = None;
2823 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
2824 struct GadgetInfo *gi;
2825 unsigned long event_mask;
2826 int gd_xoffset, gd_yoffset;
2827 int gd_x1, gd_x2, gd_y;
2830 event_mask = GD_EVENT_RELEASED;
2832 gd_xoffset = toolbutton_info[i].xpos;
2833 gd_yoffset = toolbutton_info[i].ypos;
2834 gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
2835 gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
2836 gd_y = DOOR_GFX_PAGEY1 + gd_yoffset;
2838 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
2840 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
2842 getMiniGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr),
2843 &deco_bitmap, &deco_x, &deco_y);
2844 deco_xpos = (toolbutton_info[i].width - MINI_TILEX) / 2;
2845 deco_ypos = (toolbutton_info[i].height - MINI_TILEY) / 2;
2848 gi = CreateGadget(GDI_CUSTOM_ID, id,
2849 GDI_INFO_TEXT, toolbutton_info[i].infotext,
2850 GDI_X, DX + toolbutton_info[i].x,
2851 GDI_Y, DY + toolbutton_info[i].y,
2852 GDI_WIDTH, toolbutton_info[i].width,
2853 GDI_HEIGHT, toolbutton_info[i].height,
2854 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
2855 GDI_STATE, GD_BUTTON_UNPRESSED,
2856 GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
2857 GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
2858 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
2859 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
2860 GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
2861 GDI_DECORATION_SHIFTING, 1, 1,
2862 GDI_EVENT_MASK, event_mask,
2863 GDI_CALLBACK_ACTION, HandleToolButtons,
2867 Error(ERR_EXIT, "cannot create gadget");
2869 tool_gadget[id] = gi;
2873 void FreeToolButtons()
2877 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
2878 FreeGadget(tool_gadget[i]);
2881 static void UnmapToolButtons()
2885 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
2886 UnmapGadget(tool_gadget[i]);
2889 static void HandleToolButtons(struct GadgetInfo *gi)
2891 request_gadget_id = gi->custom_id;
2899 boolean is_rnd_to_em_mapping;
2905 mapping_EM_to_RND_list[] =
2912 Yacid_splash_eB, FALSE,
2916 Yacid_splash_wB, FALSE,
2920 #ifdef EM_ENGINE_BAD_ROLL
2922 Xstone_force_e, FALSE,
2923 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
2926 Xstone_force_w, FALSE,
2927 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
2930 Xnut_force_e, FALSE,
2931 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
2934 Xnut_force_w, FALSE,
2935 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
2938 Xspring_force_e, FALSE,
2939 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
2942 Xspring_force_w, FALSE,
2943 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
2946 Xemerald_force_e, FALSE,
2947 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
2950 Xemerald_force_w, FALSE,
2951 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
2954 Xdiamond_force_e, FALSE,
2955 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
2958 Xdiamond_force_w, FALSE,
2959 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
2962 Xbomb_force_e, FALSE,
2963 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
2966 Xbomb_force_w, FALSE,
2967 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
2976 Xstone_pause, FALSE,
2981 EL_ROCK, ACTION_FALLING, -1
2985 EL_ROCK, ACTION_FALLING, -1
2989 EL_ROCK, ACTION_FALLING, -1
2993 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
2997 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
3001 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
3005 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
3017 EL_NUT, ACTION_FALLING, -1
3021 EL_NUT, ACTION_FALLING, -1
3025 EL_NUT, ACTION_FALLING, -1
3029 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
3033 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
3037 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
3041 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
3045 EL_BUG_UP, ACTION_MOVING, MV_BIT_UP
3049 EL_BUG_RIGHT, ACTION_MOVING, MV_BIT_RIGHT
3053 EL_BUG_DOWN, ACTION_MOVING, MV_BIT_DOWN
3057 EL_BUG_LEFT, ACTION_MOVING, MV_BIT_LEFT
3061 EL_BUG_UP, ACTION_MOVING, MV_BIT_UP
3065 EL_BUG_RIGHT, ACTION_MOVING, MV_BIT_RIGHT
3069 EL_BUG_DOWN, ACTION_MOVING, MV_BIT_DOWN
3073 EL_BUG_LEFT, ACTION_MOVING, MV_BIT_LEFT
3077 EL_BUG_UP, ACTION_MOVING, MV_BIT_UP
3081 EL_BUG_UP, ACTION_MOVING, MV_BIT_UP
3085 EL_BUG_RIGHT, ACTION_MOVING, MV_BIT_RIGHT
3089 EL_BUG_RIGHT, ACTION_MOVING, MV_BIT_RIGHT
3093 EL_BUG_DOWN, ACTION_MOVING, MV_BIT_DOWN
3097 EL_BUG_DOWN, ACTION_MOVING, MV_BIT_DOWN
3101 EL_BUG_LEFT, ACTION_MOVING, MV_BIT_LEFT
3105 EL_BUG_LEFT, ACTION_MOVING, MV_BIT_LEFT
3109 EL_BUG_UP, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
3113 EL_BUG_RIGHT, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
3117 EL_BUG_DOWN, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
3121 EL_BUG_LEFT, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
3125 EL_BUG_UP, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
3129 EL_BUG_RIGHT, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
3133 EL_BUG_DOWN, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
3137 EL_BUG_LEFT, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
3149 EL_SPACESHIP_UP, ACTION_MOVING, MV_BIT_UP
3153 EL_SPACESHIP_RIGHT, ACTION_MOVING, MV_BIT_RIGHT
3157 EL_SPACESHIP_DOWN, ACTION_MOVING, MV_BIT_DOWN
3161 EL_SPACESHIP_LEFT, ACTION_MOVING, MV_BIT_LEFT
3165 EL_SPACESHIP_UP, ACTION_MOVING, MV_BIT_UP
3169 EL_SPACESHIP_RIGHT, ACTION_MOVING, MV_BIT_RIGHT
3173 EL_SPACESHIP_DOWN, ACTION_MOVING, MV_BIT_DOWN
3177 EL_SPACESHIP_LEFT, ACTION_MOVING, MV_BIT_LEFT
3181 EL_SPACESHIP_UP, ACTION_MOVING, MV_BIT_UP
3185 EL_SPACESHIP_UP, ACTION_MOVING, MV_BIT_UP
3189 EL_SPACESHIP_RIGHT, ACTION_MOVING, MV_BIT_RIGHT
3193 EL_SPACESHIP_RIGHT, ACTION_MOVING, MV_BIT_RIGHT
3197 EL_SPACESHIP_DOWN, ACTION_MOVING, MV_BIT_DOWN
3201 EL_SPACESHIP_DOWN, ACTION_MOVING, MV_BIT_DOWN
3205 EL_SPACESHIP_LEFT, ACTION_MOVING, MV_BIT_LEFT
3209 EL_SPACESHIP_LEFT, ACTION_MOVING, MV_BIT_LEFT
3213 EL_SPACESHIP_UP, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
3217 EL_SPACESHIP_RIGHT, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
3221 EL_SPACESHIP_DOWN, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
3225 EL_SPACESHIP_LEFT, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
3229 EL_SPACESHIP_UP, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
3233 EL_SPACESHIP_RIGHT, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
3237 EL_SPACESHIP_DOWN, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
3241 EL_SPACESHIP_LEFT, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
3248 Ytank_spring, FALSE,
3253 EL_EMC_ANDROID, -1, -1
3257 EL_EMC_ANDROID_UP, ACTION_MOVING, MV_BIT_UP
3260 Xandroid_2_n, FALSE,
3261 EL_EMC_ANDROID_UP, ACTION_MOVING, MV_BIT_UP
3265 EL_EMC_ANDROID_RIGHT, ACTION_MOVING, MV_BIT_RIGHT
3268 Xandroid_2_e, FALSE,
3269 EL_EMC_ANDROID_RIGHT, ACTION_MOVING, MV_BIT_RIGHT
3273 EL_EMC_ANDROID_LEFT, ACTION_MOVING, MV_BIT_LEFT
3276 Xandroid_2_w, FALSE,
3277 EL_EMC_ANDROID_LEFT, ACTION_MOVING, MV_BIT_LEFT
3281 EL_EMC_ANDROID_DOWN, ACTION_MOVING, MV_BIT_DOWN
3284 Xandroid_2_s, FALSE,
3285 EL_EMC_ANDROID_DOWN, ACTION_MOVING, MV_BIT_DOWN
3289 EL_EMC_ANDROID_UP, ACTION_MOVING, MV_BIT_UP
3293 EL_EMC_ANDROID_UP, ACTION_MOVING, MV_BIT_UP
3297 EL_EMC_ANDROID_RIGHT_UP,
3300 Yandroid_neB, FALSE,
3301 EL_EMC_ANDROID_RIGHT_UP, -1, -1
3305 EL_EMC_ANDROID_RIGHT, ACTION_MOVING, MV_BIT_RIGHT
3309 EL_EMC_ANDROID_RIGHT, ACTION_MOVING, MV_BIT_RIGHT
3313 EL_EMC_ANDROID_RIGHT_DOWN, -1, -1
3316 Yandroid_seB, FALSE,
3317 EL_EMC_ANDROID_RIGHT_DOWN, -1, -1
3321 EL_EMC_ANDROID_DOWN, ACTION_MOVING, MV_BIT_DOWN
3325 EL_EMC_ANDROID_DOWN, ACTION_MOVING, MV_BIT_DOWN
3329 EL_EMC_ANDROID_LEFT_DOWN, -1, -1
3332 Yandroid_swB, FALSE,
3333 EL_EMC_ANDROID_LEFT_DOWN, -1, -1
3337 EL_EMC_ANDROID_LEFT, ACTION_MOVING, MV_BIT_LEFT
3341 EL_EMC_ANDROID_LEFT, ACTION_MOVING, MV_BIT_LEFT
3345 EL_EMC_ANDROID_LEFT_UP, -1, -1
3348 Yandroid_nwB, FALSE,
3349 EL_EMC_ANDROID_LEFT_UP, -1, -1
3356 Xspring_pause, FALSE,
3361 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
3365 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
3368 Xspring_fall, FALSE,
3369 EL_SPRING, ACTION_FALLING, -1
3373 EL_SPRING, ACTION_FALLING, -1
3377 EL_SPRING, ACTION_FALLING, -1
3381 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
3385 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
3389 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
3393 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
3396 Yspring_kill_e, FALSE,
3400 Yspring_kill_eB, FALSE,
3404 Yspring_kill_w, FALSE,
3408 Yspring_kill_wB, FALSE,
3413 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
3417 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
3421 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
3425 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
3429 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
3433 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
3437 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
3441 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
3445 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
3449 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
3453 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
3457 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
3460 Yeater_stone, FALSE,
3464 Yeater_spring, FALSE,
3472 Xalien_pause, FALSE,
3477 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
3481 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
3485 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
3489 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
3493 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
3497 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
3501 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
3505 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
3508 Yalien_stone, FALSE,
3512 Yalien_spring, FALSE,
3520 Xemerald_pause, FALSE,
3524 Xemerald_fall, FALSE,
3525 EL_EMERALD, ACTION_FALLING, -1
3528 Xemerald_shine, FALSE,
3533 EL_EMERALD, ACTION_FALLING, -1
3537 EL_EMERALD, ACTION_FALLING, -1
3541 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
3545 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
3549 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
3553 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
3556 Yemerald_eat, FALSE,
3560 Yemerald_stone, FALSE,
3568 Xdiamond_pause, FALSE,
3572 Xdiamond_fall, FALSE,
3573 EL_DIAMOND, ACTION_FALLING, -1
3576 Xdiamond_shine, FALSE,
3581 EL_DIAMOND, ACTION_FALLING, -1
3585 EL_DIAMOND, ACTION_FALLING, -1
3589 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
3593 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
3597 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
3601 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
3604 Ydiamond_eat, FALSE,
3608 Ydiamond_stone, FALSE,
3613 EL_AMOEBA_DROP, ACTION_FALLING, -1
3616 Xdrip_stretch, FALSE,
3617 EL_AMOEBA_DROP, -1, -1
3620 Xdrip_stretchB, FALSE,
3621 EL_AMOEBA_DROP, -1, -1
3625 EL_AMOEBA_DROP, -1, -1
3629 EL_AMOEBA_DROP, ACTION_FALLING, -1
3633 EL_AMOEBA_DROP, ACTION_FALLING, -1
3637 EL_AMOEBA_DROP, ACTION_FALLING, -1
3641 EL_AMOEBA_DROP, ACTION_FALLING, -1
3653 EL_BOMB, ACTION_FALLING, -1
3657 EL_BOMB, ACTION_FALLING, -1
3661 EL_BOMB, ACTION_FALLING, -1
3665 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
3669 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
3673 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
3677 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
3689 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
3693 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
3697 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
3701 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
3705 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
3709 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
3713 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
3717 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
3725 EL_SAND, ACTION_MOVING, MV_BIT_UP
3729 EL_SAND, ACTION_MOVING, MV_BIT_RIGHT
3733 EL_SAND, ACTION_MOVING, MV_BIT_DOWN
3737 EL_SAND, ACTION_MOVING, MV_BIT_LEFT
3745 EL_SAND, ACTION_MOVING, MV_BIT_UP
3749 EL_SAND, ACTION_MOVING, MV_BIT_RIGHT
3753 EL_SAND, ACTION_MOVING, MV_BIT_DOWN
3757 EL_SAND, ACTION_MOVING, MV_BIT_LEFT
3761 EL_ACID_POOL_TOPRIGHT, -1, -1
3765 EL_ACID_POOL_BOTTOMRIGHT, -1, -1
3769 EL_ACID_POOL_BOTTOM, -1, -1
3773 EL_ACID_POOL_BOTTOMLEFT, -1, -1
3777 EL_ACID_POOL_TOPLEFT, -1, -1
3813 EL_EMC_GENERATOR_BALL, -1, -1
3817 EL_EMC_GENERATOR_BALL, -1, -1
3821 EL_EMC_GENERATOR_BALL, -1, -1
3825 EL_EMC_GENERATOR_BALL, -1, -1
3829 EL_EMC_GENERATOR_BALL, -1, -1
3836 Ygrow_ns_eat, FALSE,
3844 Ygrow_ew_eat, FALSE,
3849 EL_MAGIC_WALL, -1, -1
3852 XwonderwallB, FALSE,
3853 EL_MAGIC_WALL, -1, -1
3857 EL_AMOEBA_WET, -1, -1
3861 EL_AMOEBA_WET, -1, -1
3865 EL_AMOEBA_WET, -1, -1
3869 EL_AMOEBA_WET, -1, -1
3873 EL_AMOEBA_WET, -1, -1
3877 EL_AMOEBA_WET, -1, -1
3881 EL_AMOEBA_WET, -1, -1
3885 EL_AMOEBA_WET, -1, -1
3889 EL_EM_GATE_1, -1, -1
3893 EL_EM_GATE_2, -1, -1
3897 EL_EM_GATE_3, -1, -1
3901 EL_EM_GATE_4, -1, -1
3905 EL_EMC_GATE_5, -1, -1
3909 EL_EMC_GATE_6, -1, -1
3913 EL_EMC_GATE_7, -1, -1
3917 EL_EMC_GATE_8, -1, -1
3937 EL_EMC_KEY_5, -1, -1
3941 EL_EMC_KEY_6, -1, -1
3945 EL_EMC_KEY_7, -1, -1
3949 EL_EMC_KEY_8, -1, -1
3953 EL_BALLOON_SWITCH_UP, -1, -1
3957 EL_BALLOON_SWITCH_RIGHT, -1, -1
3961 EL_BALLOON_SWITCH_DOWN, -1, -1
3965 EL_BALLOON_SWITCH_LEFT, -1, -1
3969 EL_BALLOON_SWITCH_ANY, -1, -1
3973 EL_BALLOON_SWITCH_NONE, -1, -1
3977 EL_EXIT_CLOSED, -1, -1
3981 EL_EXIT_OPEN, -1, -1
3985 EL_EXIT_OPEN, -1, -1
3989 EL_EXIT_OPEN, -1, -1
3996 Ydynamite_eat, FALSE,
4001 EL_DYNAMITE_ACTIVE, -1, -1
4005 EL_DYNAMITE_ACTIVE, -1, -1
4009 EL_DYNAMITE_ACTIVE, -1, -1
4013 EL_DYNAMITE_ACTIVE, -1, -1
4017 EL_EMC_BUMPER, -1, -1
4021 EL_EMC_BUMPER, -1, -1
4025 EL_ROBOT_WHEEL, -1, -1
4029 EL_ROBOT_WHEEL, -1, -1
4041 EL_QUICKSAND_EMPTY, -1, -1
4045 EL_QUICKSAND_FULL, -1, -1
4048 Xsand_stonein_1, FALSE,
4049 EL_QUICKSAND_FULL, -1, -1
4052 Xsand_stonein_2, FALSE,
4053 EL_QUICKSAND_FULL, -1, -1
4056 Xsand_stonein_3, FALSE,
4057 EL_QUICKSAND_FULL, -1, -1
4060 Xsand_stonein_4, FALSE,
4061 EL_QUICKSAND_FULL, -1, -1
4064 Xsand_stonesand_1, FALSE,
4065 EL_QUICKSAND_FULL, -1, -1
4068 Xsand_stonesand_2, FALSE,
4069 EL_QUICKSAND_FULL, -1, -1
4072 Xsand_stonesand_3, FALSE,
4073 EL_QUICKSAND_FULL, -1, -1
4076 Xsand_stonesand_4, FALSE,
4077 EL_QUICKSAND_FULL, -1, -1
4080 Xsand_stoneout_1, FALSE,
4081 EL_QUICKSAND_FULL, -1, -1
4084 Xsand_stoneout_2, FALSE,
4085 EL_QUICKSAND_FULL, -1, -1
4088 Xsand_sandstone_1, FALSE,
4089 EL_QUICKSAND_FULL, -1, -1
4092 Xsand_sandstone_2, FALSE,
4093 EL_QUICKSAND_FULL, -1, -1
4096 Xsand_sandstone_3, FALSE,
4097 EL_QUICKSAND_FULL, -1, -1
4100 Xsand_sandstone_4, FALSE,
4101 EL_QUICKSAND_FULL, -1, -1
4105 EL_EMC_PLANT, -1, -1
4109 EL_EMC_PLANT, -1, -1
4113 EL_EMC_LENSES, -1, -1
4117 EL_EMC_MAGNIFIER, -1, -1
4129 EL_INVISIBLE_WALL, -1, -1
4132 Xfake_blankB, FALSE,
4133 EL_INVISIBLE_WALL, -1, -1
4137 EL_INVISIBLE_SAND, -1, -1
4140 Xfake_grassB, FALSE,
4141 EL_INVISIBLE_SAND, -1, -1
4145 EL_EM_GATE_1_GRAY, -1, -1
4149 EL_EM_GATE_2_GRAY, -1, -1
4153 EL_EM_GATE_3_GRAY, -1, -1
4157 EL_EM_GATE_4_GRAY, -1, -1
4161 EL_EMC_GATE_5_GRAY, -1, -1
4165 EL_EMC_GATE_6_GRAY, -1, -1
4169 EL_EMC_GATE_7_GRAY, -1, -1
4173 EL_EMC_GATE_8_GRAY, -1, -1
4177 EL_STEELWALL, -1, -1
4185 EL_EMC_STEELWALL_1, -1, -1
4208 Xround_wall_1, TRUE,
4209 EL_WALL_SLIPPERY, -1, -1
4212 Xround_wall_2, FALSE,
4216 Xround_wall_3, FALSE,
4220 Xround_wall_4, FALSE,
4229 EL_EMC_WALL_6, -1, -1
4233 EL_EMC_WALL_4, -1, -1
4237 EL_EMC_WALL_5, -1, -1
4241 EL_EMC_WALL_7, -1, -1
4245 EL_EMC_WALL_8, -1, -1
4253 EL_EMC_WALL_1, -1, -1
4257 EL_EMC_WALL_2, -1, -1
4261 EL_EMC_WALL_3, -1, -1
4273 EL_CHAR('0'), -1, -1
4277 EL_CHAR('1'), -1, -1
4281 EL_CHAR('2'), -1, -1
4285 EL_CHAR('3'), -1, -1
4289 EL_CHAR('4'), -1, -1
4293 EL_CHAR('5'), -1, -1
4297 EL_CHAR('6'), -1, -1
4301 EL_CHAR('7'), -1, -1
4305 EL_CHAR('8'), -1, -1
4309 EL_CHAR('9'), -1, -1
4313 EL_CHAR('!'), -1, -1
4317 EL_CHAR('"'), -1, -1
4321 EL_CHAR(','), -1, -1
4325 EL_CHAR('-'), -1, -1
4329 EL_CHAR('.'), -1, -1
4333 EL_CHAR(':'), -1, -1
4337 EL_CHAR('?'), -1, -1
4341 EL_CHAR('A'), -1, -1
4345 EL_CHAR('B'), -1, -1
4349 EL_CHAR('C'), -1, -1
4353 EL_CHAR('D'), -1, -1
4357 EL_CHAR('E'), -1, -1
4361 EL_CHAR('F'), -1, -1
4365 EL_CHAR('G'), -1, -1
4369 EL_CHAR('H'), -1, -1
4373 EL_CHAR('I'), -1, -1
4377 EL_CHAR('J'), -1, -1
4381 EL_CHAR('K'), -1, -1
4385 EL_CHAR('L'), -1, -1
4389 EL_CHAR('M'), -1, -1
4393 EL_CHAR('N'), -1, -1
4397 EL_CHAR('O'), -1, -1
4401 EL_CHAR('P'), -1, -1
4405 EL_CHAR('Q'), -1, -1
4409 EL_CHAR('R'), -1, -1
4413 EL_CHAR('S'), -1, -1
4417 EL_CHAR('T'), -1, -1
4421 EL_CHAR('U'), -1, -1
4425 EL_CHAR('V'), -1, -1
4429 EL_CHAR('W'), -1, -1
4433 EL_CHAR('X'), -1, -1
4437 EL_CHAR('Y'), -1, -1
4441 EL_CHAR('Z'), -1, -1
4444 Xalpha_arrow_e, TRUE,
4445 EL_CHAR('>'), -1, -1
4448 Xalpha_arrow_w, TRUE,
4449 EL_CHAR('<'), -1, -1
4453 EL_CHAR('©'), -1, -1
4463 EL_EMC_LEVEL_BORDER, -1, -1
4472 int map_element_RND_to_EM(int element_rnd)
4474 static unsigned short mapping_RND_to_EM[NUM_FILE_ELEMENTS];
4475 static boolean mapping_initialized = FALSE;
4477 if (!mapping_initialized)
4481 /* return "Xalpha_quest" for all undefined elements in mapping array */
4482 for (i = 0; i < NUM_FILE_ELEMENTS; i++)
4483 mapping_RND_to_EM[i] = Xalpha_quest;
4485 for (i = 0; mapping_EM_to_RND_list[i].element_em != -1; i++)
4486 if (mapping_EM_to_RND_list[i].is_rnd_to_em_mapping)
4487 mapping_RND_to_EM[mapping_EM_to_RND_list[i].element_rnd] =
4488 mapping_EM_to_RND_list[i].element_em;
4490 mapping_initialized = TRUE;
4493 if (element_rnd >= 0 && element_rnd < NUM_FILE_ELEMENTS)
4494 return mapping_RND_to_EM[element_rnd];
4496 Error(ERR_WARN, "invalid RND level element %d", element_rnd);
4501 int map_element_EM_to_RND(int element_em)
4503 static unsigned short mapping_EM_to_RND[TILE_MAX];
4504 static boolean mapping_initialized = FALSE;
4506 if (!mapping_initialized)
4510 /* return "EL_UNKNOWN" for all undefined elements in mapping array */
4511 for (i = 0; i < TILE_MAX; i++)
4512 mapping_EM_to_RND[i] = EL_UNKNOWN;
4514 for (i = 0; mapping_EM_to_RND_list[i].element_em != -1; i++)
4515 mapping_EM_to_RND[mapping_EM_to_RND_list[i].element_em] =
4516 mapping_EM_to_RND_list[i].element_rnd;
4518 mapping_initialized = TRUE;
4521 if (element_em >= 0 && element_em < TILE_MAX)
4522 return mapping_EM_to_RND[element_em];
4524 Error(ERR_WARN, "invalid EM level element %d", element_em);
4531 int map_element_RND_to_EM(int element_rnd)
4533 static unsigned short mapping_RND_to_EM[NUM_FILE_ELEMENTS];
4534 static boolean mapping_initialized = FALSE;
4541 mapping_RND_to_EM_list[] =
4543 { Xblank, EL_EMPTY },
4544 { Xstone, EL_ROCK },
4546 { Xbug_n, EL_BUG_UP },
4547 { Xbug_e, EL_BUG_RIGHT },
4548 { Xbug_s, EL_BUG_DOWN },
4549 { Xbug_w, EL_BUG_LEFT },
4550 { Xtank_n, EL_SPACESHIP_UP },
4551 { Xtank_e, EL_SPACESHIP_RIGHT },
4552 { Xtank_s, EL_SPACESHIP_DOWN },
4553 { Xtank_w, EL_SPACESHIP_LEFT },
4554 { Xandroid, EL_EMC_ANDROID },
4555 { Xandroid_1_n, EL_EMC_ANDROID_UP },
4556 { Xandroid_1_e, EL_EMC_ANDROID_RIGHT },
4557 { Xandroid_1_w, EL_EMC_ANDROID_LEFT },
4558 { Xandroid_1_s, EL_EMC_ANDROID_DOWN },
4559 { Xspring, EL_SPRING },
4560 { Xeater_n, EL_YAMYAM },
4561 { Xalien, EL_ROBOT },
4562 { Xemerald, EL_EMERALD },
4563 { Xdiamond, EL_DIAMOND },
4564 { Xdrip_fall, EL_AMOEBA_DROP },
4566 { Xballoon, EL_BALLOON },
4567 { Xgrass, EL_EMC_GRASS },
4569 { Xacid_ne, EL_ACID_POOL_TOPRIGHT },
4570 { Xacid_se, EL_ACID_POOL_BOTTOMRIGHT },
4571 { Xacid_s, EL_ACID_POOL_BOTTOM },
4572 { Xacid_sw, EL_ACID_POOL_BOTTOMLEFT },
4573 { Xacid_nw, EL_ACID_POOL_TOPLEFT },
4574 { Xacid_1, EL_ACID },
4575 { Xball_1, EL_EMC_GENERATOR_BALL },
4576 { Xgrow_ns, EL_EMC_GROW },
4577 { Xwonderwall, EL_MAGIC_WALL },
4578 { Xamoeba_1, EL_AMOEBA_WET },
4579 { Xdoor_1, EL_EM_GATE_1 },
4580 { Xdoor_2, EL_EM_GATE_2 },
4581 { Xdoor_3, EL_EM_GATE_3 },
4582 { Xdoor_4, EL_EM_GATE_4 },
4583 { Xdoor_5, EL_EMC_GATE_5 },
4584 { Xdoor_6, EL_EMC_GATE_6 },
4585 { Xdoor_7, EL_EMC_GATE_7 },
4586 { Xdoor_8, EL_EMC_GATE_8 },
4587 { Xkey_1, EL_EM_KEY_1 },
4588 { Xkey_2, EL_EM_KEY_2 },
4589 { Xkey_3, EL_EM_KEY_3 },
4590 { Xkey_4, EL_EM_KEY_4 },
4591 { Xkey_5, EL_EMC_KEY_5 },
4592 { Xkey_6, EL_EMC_KEY_6 },
4593 { Xkey_7, EL_EMC_KEY_7 },
4594 { Xkey_8, EL_EMC_KEY_8 },
4595 { Xwind_n, EL_BALLOON_SWITCH_UP },
4596 { Xwind_e, EL_BALLOON_SWITCH_RIGHT },
4597 { Xwind_s, EL_BALLOON_SWITCH_DOWN },
4598 { Xwind_w, EL_BALLOON_SWITCH_LEFT },
4599 { Xwind_nesw, EL_BALLOON_SWITCH_ANY },
4600 { Xwind_stop, EL_BALLOON_SWITCH_NONE },
4601 { Xexit, EL_EXIT_CLOSED },
4602 { Xexit_1, EL_EXIT_OPEN },
4603 { Xdynamite, EL_DYNAMITE },
4604 { Xdynamite_1, EL_DYNAMITE_ACTIVE },
4605 { Xbumper, EL_EMC_BUMPER },
4606 { Xwheel, EL_ROBOT_WHEEL },
4607 { Xswitch, EL_UNKNOWN },
4608 { Xsand, EL_QUICKSAND_EMPTY },
4609 { Xsand_stone, EL_QUICKSAND_FULL },
4610 { Xplant, EL_EMC_PLANT },
4611 { Xlenses, EL_EMC_LENSES },
4612 { Xmagnify, EL_EMC_MAGNIFIER },
4613 { Xdripper, EL_UNKNOWN },
4614 { Xfake_blank, EL_INVISIBLE_WALL },
4615 { Xfake_grass, EL_INVISIBLE_SAND },
4616 { Xfake_door_1, EL_EM_GATE_1_GRAY },
4617 { Xfake_door_2, EL_EM_GATE_2_GRAY },
4618 { Xfake_door_3, EL_EM_GATE_3_GRAY },
4619 { Xfake_door_4, EL_EM_GATE_4_GRAY },
4620 { Xfake_door_5, EL_EMC_GATE_5_GRAY },
4621 { Xfake_door_6, EL_EMC_GATE_6_GRAY },
4622 { Xfake_door_7, EL_EMC_GATE_7_GRAY },
4623 { Xfake_door_8, EL_EMC_GATE_8_GRAY },
4624 { Xsteel_1, EL_STEELWALL },
4625 { Xsteel_2, EL_UNKNOWN },
4626 { Xsteel_3, EL_EMC_STEELWALL_1 },
4627 { Xsteel_4, EL_UNKNOWN },
4628 { Xwall_1, EL_WALL },
4629 { Xwall_2, EL_UNKNOWN },
4630 { Xwall_3, EL_UNKNOWN },
4631 { Xwall_4, EL_UNKNOWN },
4632 { Xround_wall_1, EL_WALL_SLIPPERY },
4633 { Xround_wall_2, EL_UNKNOWN },
4634 { Xround_wall_3, EL_UNKNOWN },
4635 { Xround_wall_4, EL_UNKNOWN },
4636 { Xdecor_1, EL_UNKNOWN },
4637 { Xdecor_2, EL_EMC_WALL_6 },
4638 { Xdecor_3, EL_EMC_WALL_4 },
4639 { Xdecor_4, EL_EMC_WALL_5 },
4640 { Xdecor_5, EL_EMC_WALL_7 },
4641 { Xdecor_6, EL_EMC_WALL_8 },
4642 { Xdecor_7, EL_UNKNOWN },
4643 { Xdecor_8, EL_EMC_WALL_1 },
4644 { Xdecor_9, EL_EMC_WALL_2 },
4645 { Xdecor_10, EL_EMC_WALL_3 },
4646 { Xdecor_11, EL_UNKNOWN },
4647 { Xdecor_12, EL_UNKNOWN },
4648 { Xalpha_0, EL_CHAR('0') },
4649 { Xalpha_1, EL_CHAR('1') },
4650 { Xalpha_2, EL_CHAR('2') },
4651 { Xalpha_3, EL_CHAR('3') },
4652 { Xalpha_4, EL_CHAR('4') },
4653 { Xalpha_5, EL_CHAR('5') },
4654 { Xalpha_6, EL_CHAR('6') },
4655 { Xalpha_7, EL_CHAR('7') },
4656 { Xalpha_8, EL_CHAR('8') },
4657 { Xalpha_9, EL_CHAR('9') },
4658 { Xalpha_excla, EL_CHAR('!') },
4659 { Xalpha_quote, EL_CHAR('"') },
4660 { Xalpha_comma, EL_CHAR(',') },
4661 { Xalpha_minus, EL_CHAR('-') },
4662 { Xalpha_perio, EL_CHAR('.') },
4663 { Xalpha_colon, EL_CHAR(':') },
4664 { Xalpha_quest, EL_CHAR('?') },
4665 { Xalpha_a, EL_CHAR('A') },
4666 { Xalpha_b, EL_CHAR('B') },
4667 { Xalpha_c, EL_CHAR('C') },
4668 { Xalpha_d, EL_CHAR('D') },
4669 { Xalpha_e, EL_CHAR('E') },
4670 { Xalpha_f, EL_CHAR('F') },
4671 { Xalpha_g, EL_CHAR('G') },
4672 { Xalpha_h, EL_CHAR('H') },
4673 { Xalpha_i, EL_CHAR('I') },
4674 { Xalpha_j, EL_CHAR('J') },
4675 { Xalpha_k, EL_CHAR('K') },
4676 { Xalpha_l, EL_CHAR('L') },
4677 { Xalpha_m, EL_CHAR('M') },
4678 { Xalpha_n, EL_CHAR('N') },
4679 { Xalpha_o, EL_CHAR('O') },
4680 { Xalpha_p, EL_CHAR('P') },
4681 { Xalpha_q, EL_CHAR('Q') },
4682 { Xalpha_r, EL_CHAR('R') },
4683 { Xalpha_s, EL_CHAR('S') },
4684 { Xalpha_t, EL_CHAR('T') },
4685 { Xalpha_u, EL_CHAR('U') },
4686 { Xalpha_v, EL_CHAR('V') },
4687 { Xalpha_w, EL_CHAR('W') },
4688 { Xalpha_x, EL_CHAR('X') },
4689 { Xalpha_y, EL_CHAR('Y') },
4690 { Xalpha_z, EL_CHAR('Z') },
4691 { Xalpha_arrow_e, EL_CHAR('>') },
4692 { Xalpha_arrow_w, EL_CHAR('<') },
4693 { Xalpha_copyr, EL_CHAR('©') },
4695 { Zplayer, EL_PLAYER_1 },
4696 { Zplayer, EL_PLAYER_2 },
4697 { Zplayer, EL_PLAYER_3 },
4698 { Zplayer, EL_PLAYER_4 },
4700 { ZBORDER, EL_EMC_LEVEL_BORDER },
4705 if (!mapping_initialized)
4709 /* return "Xalpha_quest" for all undefined elements in mapping array */
4710 for (i = 0; i < NUM_FILE_ELEMENTS; i++)
4711 mapping_RND_to_EM[i] = Xalpha_quest;
4713 for (i = 0; mapping_RND_to_EM_list[i].element_rnd != -1; i++)
4714 mapping_RND_to_EM[mapping_RND_to_EM_list[i].element_rnd] =
4715 mapping_RND_to_EM_list[i].element_em;
4717 mapping_initialized = TRUE;
4720 if (element_rnd >= 0 && element_rnd < NUM_FILE_ELEMENTS)
4721 return mapping_RND_to_EM[element_rnd];
4723 Error(ERR_WARN, "invalid RND level element %d", element_rnd);
4728 int map_element_EM_to_RND(int element_em)
4730 static unsigned short mapping_EM_to_RND[TILE_MAX];
4731 static boolean mapping_initialized = FALSE;
4738 mapping_EM_to_RND_list[] =
4740 { Xblank, EL_EMPTY },
4741 { Yacid_splash_eB, EL_EMPTY },
4742 { Yacid_splash_wB, EL_EMPTY },
4744 #ifdef EM_ENGINE_BAD_ROLL
4745 { Xstone_force_e, EL_ROCK },
4746 { Xstone_force_w, EL_ROCK },
4747 { Xnut_force_e, EL_NUT },
4748 { Xnut_force_w, EL_NUT },
4749 { Xspring_force_e, EL_SPRING },
4750 { Xspring_force_w, EL_SPRING },
4751 { Xemerald_force_e, EL_EMERALD },
4752 { Xemerald_force_w, EL_EMERALD },
4753 { Xdiamond_force_e, EL_DIAMOND },
4754 { Xdiamond_force_w, EL_DIAMOND },
4755 { Xbomb_force_e, EL_BOMB },
4756 { Xbomb_force_w, EL_BOMB },
4759 { Xstone, EL_ROCK },
4760 { Xstone_pause, EL_ROCK },
4761 { Xstone_fall, EL_ROCK },
4762 { Ystone_s, EL_ROCK },
4763 { Ystone_sB, EL_ROCK },
4764 { Ystone_e, EL_ROCK },
4765 { Ystone_eB, EL_ROCK },
4766 { Ystone_w, EL_ROCK },
4767 { Ystone_wB, EL_ROCK },
4769 { Xnut_pause, EL_NUT },
4770 { Xnut_fall, EL_NUT },
4772 { Ynut_sB, EL_NUT },
4774 { Ynut_eB, EL_NUT },
4776 { Ynut_wB, EL_NUT },
4777 { Xbug_n, EL_BUG_UP },
4778 { Xbug_e, EL_BUG_RIGHT },
4779 { Xbug_s, EL_BUG_DOWN },
4780 { Xbug_w, EL_BUG_LEFT },
4781 { Xbug_gon, EL_BUG_UP },
4782 { Xbug_goe, EL_BUG_RIGHT },
4783 { Xbug_gos, EL_BUG_DOWN },
4784 { Xbug_gow, EL_BUG_LEFT },
4785 { Ybug_n, EL_BUG_UP },
4786 { Ybug_nB, EL_BUG_UP },
4787 { Ybug_e, EL_BUG_RIGHT },
4788 { Ybug_eB, EL_BUG_RIGHT },
4789 { Ybug_s, EL_BUG_DOWN },
4790 { Ybug_sB, EL_BUG_DOWN },
4791 { Ybug_w, EL_BUG_LEFT },
4792 { Ybug_wB, EL_BUG_LEFT },
4793 { Ybug_w_n, EL_BUG_UP },
4794 { Ybug_n_e, EL_BUG_RIGHT },
4795 { Ybug_e_s, EL_BUG_DOWN },
4796 { Ybug_s_w, EL_BUG_LEFT },
4797 { Ybug_e_n, EL_BUG_UP },
4798 { Ybug_s_e, EL_BUG_RIGHT },
4799 { Ybug_w_s, EL_BUG_DOWN },
4800 { Ybug_n_w, EL_BUG_LEFT },
4801 { Ybug_stone, EL_ROCK },
4802 { Ybug_spring, EL_SPRING },
4803 { Xtank_n, EL_SPACESHIP_UP },
4804 { Xtank_e, EL_SPACESHIP_RIGHT },
4805 { Xtank_s, EL_SPACESHIP_DOWN },
4806 { Xtank_w, EL_SPACESHIP_LEFT },
4807 { Xtank_gon, EL_SPACESHIP_UP },
4808 { Xtank_goe, EL_SPACESHIP_RIGHT },
4809 { Xtank_gos, EL_SPACESHIP_DOWN },
4810 { Xtank_gow, EL_SPACESHIP_LEFT },
4811 { Ytank_n, EL_SPACESHIP_UP },
4812 { Ytank_nB, EL_SPACESHIP_UP },
4813 { Ytank_e, EL_SPACESHIP_RIGHT },
4814 { Ytank_eB, EL_SPACESHIP_RIGHT },
4815 { Ytank_s, EL_SPACESHIP_DOWN },
4816 { Ytank_sB, EL_SPACESHIP_DOWN },
4817 { Ytank_w, EL_SPACESHIP_LEFT },
4818 { Ytank_wB, EL_SPACESHIP_LEFT },
4819 { Ytank_w_n, EL_SPACESHIP_UP },
4820 { Ytank_n_e, EL_SPACESHIP_RIGHT },
4821 { Ytank_e_s, EL_SPACESHIP_DOWN },
4822 { Ytank_s_w, EL_SPACESHIP_LEFT },
4823 { Ytank_e_n, EL_SPACESHIP_UP },
4824 { Ytank_s_e, EL_SPACESHIP_RIGHT },
4825 { Ytank_w_s, EL_SPACESHIP_DOWN },
4826 { Ytank_n_w, EL_SPACESHIP_LEFT },
4827 { Ytank_stone, EL_ROCK },
4828 { Ytank_spring, EL_SPRING },
4829 { Xandroid, EL_EMC_ANDROID },
4830 { Xandroid_1_n, EL_EMC_ANDROID_UP },
4831 { Xandroid_2_n, EL_EMC_ANDROID_UP },
4832 { Xandroid_1_e, EL_EMC_ANDROID_RIGHT },
4833 { Xandroid_2_e, EL_EMC_ANDROID_RIGHT },
4834 { Xandroid_1_w, EL_EMC_ANDROID_LEFT },
4835 { Xandroid_2_w, EL_EMC_ANDROID_LEFT },
4836 { Xandroid_1_s, EL_EMC_ANDROID_DOWN },
4837 { Xandroid_2_s, EL_EMC_ANDROID_DOWN },
4838 { Yandroid_n, EL_EMC_ANDROID_UP },
4839 { Yandroid_nB, EL_EMC_ANDROID_UP },
4840 { Yandroid_ne, EL_EMC_ANDROID_RIGHT_UP },
4841 { Yandroid_neB, EL_EMC_ANDROID_RIGHT_UP },
4842 { Yandroid_e, EL_EMC_ANDROID_RIGHT },
4843 { Yandroid_eB, EL_EMC_ANDROID_RIGHT },
4844 { Yandroid_se, EL_EMC_ANDROID_RIGHT_DOWN },
4845 { Yandroid_seB, EL_EMC_ANDROID_RIGHT_DOWN },
4846 { Yandroid_s, EL_EMC_ANDROID_DOWN },
4847 { Yandroid_sB, EL_EMC_ANDROID_DOWN },
4848 { Yandroid_sw, EL_EMC_ANDROID_LEFT_DOWN },
4849 { Yandroid_swB, EL_EMC_ANDROID_LEFT_DOWN },
4850 { Yandroid_w, EL_EMC_ANDROID_LEFT },
4851 { Yandroid_wB, EL_EMC_ANDROID_LEFT },
4852 { Yandroid_nw, EL_EMC_ANDROID_LEFT_UP },
4853 { Yandroid_nwB, EL_EMC_ANDROID_LEFT_UP },
4854 { Xspring, EL_SPRING },
4855 { Xspring_pause, EL_SPRING },
4856 { Xspring_e, EL_SPRING },
4857 { Xspring_w, EL_SPRING },
4858 { Xspring_fall, EL_SPRING },
4859 { Yspring_s, EL_SPRING },
4860 { Yspring_sB, EL_SPRING },
4861 { Yspring_e, EL_SPRING },
4862 { Yspring_eB, EL_SPRING },
4863 { Yspring_w, EL_SPRING },
4864 { Yspring_wB, EL_SPRING },
4865 { Yspring_kill_e, EL_SPRING },
4866 { Yspring_kill_eB, EL_SPRING },
4867 { Yspring_kill_w, EL_SPRING },
4868 { Yspring_kill_wB, EL_SPRING },
4869 { Xeater_n, EL_YAMYAM },
4870 { Xeater_e, EL_YAMYAM },
4871 { Xeater_w, EL_YAMYAM },
4872 { Xeater_s, EL_YAMYAM },
4873 { Yeater_n, EL_YAMYAM },
4874 { Yeater_nB, EL_YAMYAM },
4875 { Yeater_e, EL_YAMYAM },
4876 { Yeater_eB, EL_YAMYAM },
4877 { Yeater_s, EL_YAMYAM },
4878 { Yeater_sB, EL_YAMYAM },
4879 { Yeater_w, EL_YAMYAM },
4880 { Yeater_wB, EL_YAMYAM },
4881 { Yeater_stone, EL_ROCK },
4882 { Yeater_spring, EL_SPRING },
4883 { Xalien, EL_ROBOT },
4884 { Xalien_pause, EL_ROBOT },
4885 { Yalien_n, EL_ROBOT },
4886 { Yalien_nB, EL_ROBOT },
4887 { Yalien_e, EL_ROBOT },
4888 { Yalien_eB, EL_ROBOT },
4889 { Yalien_s, EL_ROBOT },
4890 { Yalien_sB, EL_ROBOT },
4891 { Yalien_w, EL_ROBOT },
4892 { Yalien_wB, EL_ROBOT },
4893 { Yalien_stone, EL_ROCK },
4894 { Yalien_spring, EL_SPRING },
4895 { Xemerald, EL_EMERALD },
4896 { Xemerald_pause, EL_EMERALD },
4897 { Xemerald_fall, EL_EMERALD },
4898 { Xemerald_shine, EL_EMERALD },
4899 { Yemerald_s, EL_EMERALD },
4900 { Yemerald_sB, EL_EMERALD },
4901 { Yemerald_e, EL_EMERALD },
4902 { Yemerald_eB, EL_EMERALD },
4903 { Yemerald_w, EL_EMERALD },
4904 { Yemerald_wB, EL_EMERALD },
4905 { Yemerald_eat, EL_EMERALD },
4906 { Yemerald_stone, EL_ROCK },
4907 { Xdiamond, EL_DIAMOND },
4908 { Xdiamond_pause, EL_DIAMOND },
4909 { Xdiamond_fall, EL_DIAMOND },
4910 { Xdiamond_shine, EL_DIAMOND },
4911 { Ydiamond_s, EL_DIAMOND },
4912 { Ydiamond_sB, EL_DIAMOND },
4913 { Ydiamond_e, EL_DIAMOND },
4914 { Ydiamond_eB, EL_DIAMOND },
4915 { Ydiamond_w, EL_DIAMOND },
4916 { Ydiamond_wB, EL_DIAMOND },
4917 { Ydiamond_eat, EL_DIAMOND },
4918 { Ydiamond_stone, EL_ROCK },
4919 { Xdrip_fall, EL_AMOEBA_DROP },
4920 { Xdrip_stretch, EL_AMOEBA_DROP },
4921 { Xdrip_stretchB, EL_AMOEBA_DROP },
4922 { Xdrip_eat, EL_AMOEBA_DROP },
4923 { Ydrip_s1, EL_AMOEBA_DROP },
4924 { Ydrip_s1B, EL_AMOEBA_DROP },
4925 { Ydrip_s2, EL_AMOEBA_DROP },
4926 { Ydrip_s2B, EL_AMOEBA_DROP },
4928 { Xbomb_pause, EL_BOMB },
4929 { Xbomb_fall, EL_BOMB },
4930 { Ybomb_s, EL_BOMB },
4931 { Ybomb_sB, EL_BOMB },
4932 { Ybomb_e, EL_BOMB },
4933 { Ybomb_eB, EL_BOMB },
4934 { Ybomb_w, EL_BOMB },
4935 { Ybomb_wB, EL_BOMB },
4936 { Ybomb_eat, EL_BOMB },
4937 { Xballoon, EL_BALLOON },
4938 { Yballoon_n, EL_BALLOON },
4939 { Yballoon_nB, EL_BALLOON },
4940 { Yballoon_e, EL_BALLOON },
4941 { Yballoon_eB, EL_BALLOON },
4942 { Yballoon_s, EL_BALLOON },
4943 { Yballoon_sB, EL_BALLOON },
4944 { Yballoon_w, EL_BALLOON },
4945 { Yballoon_wB, EL_BALLOON },
4946 { Xgrass, EL_SAND },
4947 { Ygrass_nB, EL_SAND },
4948 { Ygrass_eB, EL_SAND },
4949 { Ygrass_sB, EL_SAND },
4950 { Ygrass_wB, EL_SAND },
4952 { Ydirt_nB, EL_SAND },
4953 { Ydirt_eB, EL_SAND },
4954 { Ydirt_sB, EL_SAND },
4955 { Ydirt_wB, EL_SAND },
4956 { Xacid_ne, EL_ACID_POOL_TOPRIGHT },
4957 { Xacid_se, EL_ACID_POOL_BOTTOMRIGHT },
4958 { Xacid_s, EL_ACID_POOL_BOTTOM },
4959 { Xacid_sw, EL_ACID_POOL_BOTTOMLEFT },
4960 { Xacid_nw, EL_ACID_POOL_TOPLEFT },
4961 { Xacid_1, EL_ACID },
4962 { Xacid_2, EL_ACID },
4963 { Xacid_3, EL_ACID },
4964 { Xacid_4, EL_ACID },
4965 { Xacid_5, EL_ACID },
4966 { Xacid_6, EL_ACID },
4967 { Xacid_7, EL_ACID },
4968 { Xacid_8, EL_ACID },
4969 { Xball_1, EL_EMC_GENERATOR_BALL },
4970 { Xball_1B, EL_EMC_GENERATOR_BALL },
4971 { Xball_2, EL_EMC_GENERATOR_BALL },
4972 { Xball_2B, EL_EMC_GENERATOR_BALL },
4973 { Yball_eat, EL_EMC_GENERATOR_BALL },
4974 { Xgrow_ns, EL_EMC_GROW },
4975 { Ygrow_ns_eat, EL_EMC_GROW },
4976 { Xgrow_ew, EL_EMC_GROW },
4977 { Ygrow_ew_eat, EL_EMC_GROW },
4978 { Xwonderwall, EL_MAGIC_WALL },
4979 { XwonderwallB, EL_MAGIC_WALL },
4980 { Xamoeba_1, EL_AMOEBA_WET },
4981 { Xamoeba_2, EL_AMOEBA_WET },
4982 { Xamoeba_3, EL_AMOEBA_WET },
4983 { Xamoeba_4, EL_AMOEBA_WET },
4984 { Xamoeba_5, EL_AMOEBA_WET },
4985 { Xamoeba_6, EL_AMOEBA_WET },
4986 { Xamoeba_7, EL_AMOEBA_WET },
4987 { Xamoeba_8, EL_AMOEBA_WET },
4988 { Xdoor_1, EL_EM_GATE_1 },
4989 { Xdoor_2, EL_EM_GATE_2 },
4990 { Xdoor_3, EL_EM_GATE_3 },
4991 { Xdoor_4, EL_EM_GATE_4 },
4992 { Xdoor_5, EL_EMC_GATE_5 },
4993 { Xdoor_6, EL_EMC_GATE_6 },
4994 { Xdoor_7, EL_EMC_GATE_7 },
4995 { Xdoor_8, EL_EMC_GATE_8 },
4996 { Xkey_1, EL_EM_KEY_1 },
4997 { Xkey_2, EL_EM_KEY_2 },
4998 { Xkey_3, EL_EM_KEY_3 },
4999 { Xkey_4, EL_EM_KEY_4 },
5000 { Xkey_5, EL_EMC_KEY_5 },
5001 { Xkey_6, EL_EMC_KEY_6 },
5002 { Xkey_7, EL_EMC_KEY_7 },
5003 { Xkey_8, EL_EMC_KEY_8 },
5004 { Xwind_n, EL_BALLOON_SWITCH_UP },
5005 { Xwind_e, EL_BALLOON_SWITCH_RIGHT },
5006 { Xwind_s, EL_BALLOON_SWITCH_DOWN },
5007 { Xwind_w, EL_BALLOON_SWITCH_LEFT },
5008 { Xwind_nesw, EL_BALLOON_SWITCH_ANY },
5009 { Xwind_stop, EL_BALLOON_SWITCH_NONE },
5010 { Xexit, EL_EXIT_CLOSED },
5011 { Xexit_1, EL_EXIT_OPEN },
5012 { Xexit_2, EL_EXIT_OPEN },
5013 { Xexit_3, EL_EXIT_OPEN },
5014 { Xdynamite, EL_DYNAMITE },
5015 { Ydynamite_eat, EL_DYNAMITE },
5016 { Xdynamite_1, EL_DYNAMITE_ACTIVE },
5017 { Xdynamite_2, EL_DYNAMITE_ACTIVE },
5018 { Xdynamite_3, EL_DYNAMITE_ACTIVE },
5019 { Xdynamite_4, EL_DYNAMITE_ACTIVE },
5020 { Xbumper, EL_EMC_BUMPER },
5021 { XbumperB, EL_EMC_BUMPER },
5022 { Xwheel, EL_ROBOT_WHEEL },
5023 { XwheelB, EL_ROBOT_WHEEL },
5024 { Xswitch, EL_UNKNOWN },
5025 { XswitchB, EL_UNKNOWN },
5026 { Xsand, EL_QUICKSAND_EMPTY },
5027 { Xsand_stone, EL_QUICKSAND_FULL },
5028 { Xsand_stonein_1, EL_QUICKSAND_FULL },
5029 { Xsand_stonein_2, EL_QUICKSAND_FULL },
5030 { Xsand_stonein_3, EL_QUICKSAND_FULL },
5031 { Xsand_stonein_4, EL_QUICKSAND_FULL },
5032 { Xsand_stonesand_1, EL_QUICKSAND_FULL },
5033 { Xsand_stonesand_2, EL_QUICKSAND_FULL },
5034 { Xsand_stonesand_3, EL_QUICKSAND_FULL },
5035 { Xsand_stonesand_4, EL_QUICKSAND_FULL },
5036 { Xsand_stoneout_1, EL_QUICKSAND_FULL },
5037 { Xsand_stoneout_2, EL_QUICKSAND_FULL },
5038 { Xsand_sandstone_1, EL_QUICKSAND_FULL },
5039 { Xsand_sandstone_2, EL_QUICKSAND_FULL },
5040 { Xsand_sandstone_3, EL_QUICKSAND_FULL },
5041 { Xsand_sandstone_4, EL_QUICKSAND_FULL },
5042 { Xplant, EL_EMC_PLANT },
5043 { Yplant, EL_EMC_PLANT },
5044 { Xlenses, EL_EMC_LENSES },
5045 { Xmagnify, EL_EMC_MAGNIFIER },
5046 { Xdripper, EL_UNKNOWN },
5047 { XdripperB, EL_UNKNOWN },
5048 { Xfake_blank, EL_INVISIBLE_WALL },
5049 { Xfake_blankB, EL_INVISIBLE_WALL },
5050 { Xfake_grass, EL_INVISIBLE_SAND },
5051 { Xfake_grassB, EL_INVISIBLE_SAND },
5052 { Xfake_door_1, EL_EM_GATE_1_GRAY },
5053 { Xfake_door_2, EL_EM_GATE_2_GRAY },
5054 { Xfake_door_3, EL_EM_GATE_3_GRAY },
5055 { Xfake_door_4, EL_EM_GATE_4_GRAY },
5056 { Xfake_door_5, EL_EMC_GATE_5_GRAY },
5057 { Xfake_door_6, EL_EMC_GATE_6_GRAY },
5058 { Xfake_door_7, EL_EMC_GATE_7_GRAY },
5059 { Xfake_door_8, EL_EMC_GATE_8_GRAY },
5060 { Xsteel_1, EL_STEELWALL },
5061 { Xsteel_2, EL_UNKNOWN },
5062 { Xsteel_3, EL_EMC_STEELWALL_1 },
5063 { Xsteel_4, EL_UNKNOWN },
5064 { Xwall_1, EL_WALL },
5065 { Xwall_2, EL_UNKNOWN },
5066 { Xwall_3, EL_UNKNOWN },
5067 { Xwall_4, EL_UNKNOWN },
5068 { Xround_wall_1, EL_WALL_SLIPPERY },
5069 { Xround_wall_2, EL_UNKNOWN },
5070 { Xround_wall_3, EL_UNKNOWN },
5071 { Xround_wall_4, EL_UNKNOWN },
5072 { Xdecor_1, EL_UNKNOWN },
5073 { Xdecor_2, EL_EMC_WALL_6 },
5074 { Xdecor_3, EL_EMC_WALL_4 },
5075 { Xdecor_4, EL_EMC_WALL_5 },
5076 { Xdecor_5, EL_EMC_WALL_7 },
5077 { Xdecor_6, EL_EMC_WALL_8 },
5078 { Xdecor_7, EL_UNKNOWN },
5079 { Xdecor_8, EL_EMC_WALL_1 },
5080 { Xdecor_9, EL_EMC_WALL_2 },
5081 { Xdecor_10, EL_EMC_WALL_3 },
5082 { Xdecor_11, EL_UNKNOWN },
5083 { Xdecor_12, EL_UNKNOWN },
5084 { Xalpha_0, EL_CHAR('0') },
5085 { Xalpha_1, EL_CHAR('1') },
5086 { Xalpha_2, EL_CHAR('2') },
5087 { Xalpha_3, EL_CHAR('3') },
5088 { Xalpha_4, EL_CHAR('4') },
5089 { Xalpha_5, EL_CHAR('5') },
5090 { Xalpha_6, EL_CHAR('6') },
5091 { Xalpha_7, EL_CHAR('7') },
5092 { Xalpha_8, EL_CHAR('8') },
5093 { Xalpha_9, EL_CHAR('9') },
5094 { Xalpha_excla, EL_CHAR('!') },
5095 { Xalpha_quote, EL_CHAR('"') },
5096 { Xalpha_comma, EL_CHAR(',') },
5097 { Xalpha_minus, EL_CHAR('-') },
5098 { Xalpha_perio, EL_CHAR('.') },
5099 { Xalpha_colon, EL_CHAR(':') },
5100 { Xalpha_quest, EL_CHAR('?') },
5101 { Xalpha_a, EL_CHAR('A') },
5102 { Xalpha_b, EL_CHAR('B') },
5103 { Xalpha_c, EL_CHAR('C') },
5104 { Xalpha_d, EL_CHAR('D') },
5105 { Xalpha_e, EL_CHAR('E') },
5106 { Xalpha_f, EL_CHAR('F') },
5107 { Xalpha_g, EL_CHAR('G') },
5108 { Xalpha_h, EL_CHAR('H') },
5109 { Xalpha_i, EL_CHAR('I') },
5110 { Xalpha_j, EL_CHAR('J') },
5111 { Xalpha_k, EL_CHAR('K') },
5112 { Xalpha_l, EL_CHAR('L') },
5113 { Xalpha_m, EL_CHAR('M') },
5114 { Xalpha_n, EL_CHAR('N') },
5115 { Xalpha_o, EL_CHAR('O') },
5116 { Xalpha_p, EL_CHAR('P') },
5117 { Xalpha_q, EL_CHAR('Q') },
5118 { Xalpha_r, EL_CHAR('R') },
5119 { Xalpha_s, EL_CHAR('S') },
5120 { Xalpha_t, EL_CHAR('T') },
5121 { Xalpha_u, EL_CHAR('U') },
5122 { Xalpha_v, EL_CHAR('V') },
5123 { Xalpha_w, EL_CHAR('W') },
5124 { Xalpha_x, EL_CHAR('X') },
5125 { Xalpha_y, EL_CHAR('Y') },
5126 { Xalpha_z, EL_CHAR('Z') },
5127 { Xalpha_arrow_e, EL_CHAR('>') },
5128 { Xalpha_arrow_w, EL_CHAR('<') },
5129 { Xalpha_copyr, EL_CHAR('©') },
5131 { Zplayer, EL_PLAYER_1 },
5133 { ZBORDER, EL_EMC_LEVEL_BORDER },
5138 if (!mapping_initialized)
5142 /* return "EL_UNKNOWN" for all undefined elements in mapping array */
5143 for (i = 0; i < TILE_MAX; i++)
5144 mapping_EM_to_RND[i] = EL_UNKNOWN;
5146 for (i = 0; mapping_EM_to_RND_list[i].element_em != -1; i++)
5147 mapping_EM_to_RND[mapping_EM_to_RND_list[i].element_em] =
5148 mapping_EM_to_RND_list[i].element_rnd;
5150 mapping_initialized = TRUE;
5153 if (element_em >= 0 && element_em < TILE_MAX)
5154 return mapping_EM_to_RND[element_em];
5156 Error(ERR_WARN, "invalid EM level element %d", element_em);
5163 int get_next_element(int element)
5167 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
5168 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
5169 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
5170 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
5171 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
5172 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
5173 case EL_AMOEBA_DROPPING: return EL_AMOEBA_WET;
5175 default: return element;
5179 int el_act_dir2img(int element, int action, int direction)
5181 element = GFX_ELEMENT(element);
5182 direction = MV_DIR_BIT(direction); /* default: MV_NO_MOVING => MV_DOWN */
5184 return element_info[element].direction_graphic[action][direction];
5187 static int el_act_dir2crm(int element, int action, int direction)
5189 element = GFX_ELEMENT(element);
5190 direction = MV_DIR_BIT(direction); /* default: MV_NO_MOVING => MV_DOWN */
5192 return element_info[element].direction_crumbled[action][direction];
5195 int el_act2img(int element, int action)
5197 element = GFX_ELEMENT(element);
5199 return element_info[element].graphic[action];
5202 int el_act2crm(int element, int action)
5204 element = GFX_ELEMENT(element);
5206 return element_info[element].crumbled[action];
5209 int el_dir2img(int element, int direction)
5211 element = GFX_ELEMENT(element);
5213 return el_act_dir2img(element, ACTION_DEFAULT, direction);
5216 int el2baseimg(int element)
5218 return element_info[element].graphic[ACTION_DEFAULT];
5221 int el2img(int element)
5223 element = GFX_ELEMENT(element);
5225 return element_info[element].graphic[ACTION_DEFAULT];
5228 int el2edimg(int element)
5230 element = GFX_ELEMENT(element);
5232 return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
5235 int el2preimg(int element)
5237 element = GFX_ELEMENT(element);
5239 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];
5242 int getGameFrameDelay_EM(int native_em_game_frame_delay)
5244 return (GameFrameDelay == GAME_FRAME_DELAY ? native_em_game_frame_delay :