1 /***********************************************************
2 * Rocks'n'Diamonds -- McDuffin Strikes Back! *
3 *----------------------------------------------------------*
4 * (c) 1995-2006 Artsoft Entertainment *
6 * Detmolder Strasse 189 *
9 * e-mail: info@artsoft.org *
10 *----------------------------------------------------------*
12 ***********************************************************/
14 #include "libgame/libgame.h"
25 /* select level set with EMC X11 graphics before activating EM GFX debugging */
26 #define DEBUG_EM_GFX 0
28 /* tool button identifiers */
29 #define TOOL_CTRL_ID_YES 0
30 #define TOOL_CTRL_ID_NO 1
31 #define TOOL_CTRL_ID_CONFIRM 2
32 #define TOOL_CTRL_ID_PLAYER_1 3
33 #define TOOL_CTRL_ID_PLAYER_2 4
34 #define TOOL_CTRL_ID_PLAYER_3 5
35 #define TOOL_CTRL_ID_PLAYER_4 6
37 #define NUM_TOOL_BUTTONS 7
39 /* forward declaration for internal use */
40 static void UnmapToolButtons();
41 static void HandleToolButtons(struct GadgetInfo *);
42 static int el_act_dir2crm(int, int, int);
43 static int el_act2crm(int, int);
45 static struct GadgetInfo *tool_gadget[NUM_TOOL_BUTTONS];
46 static int request_gadget_id = -1;
48 static char *print_if_not_empty(int element)
50 static char *s = NULL;
51 char *token_name = element_info[element].token_name;
56 s = checked_malloc(strlen(token_name) + 10 + 1);
58 if (element != EL_EMPTY)
59 sprintf(s, "%d\t['%s']", element, token_name);
61 sprintf(s, "%d", element);
66 void DumpTile(int x, int y)
71 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
78 printf("Field Info: SCREEN(%d, %d), LEVEL(%d, %d)\n", sx, sy, x, y);
81 if (!IN_LEV_FIELD(x, y))
83 printf("(not in level field)\n");
89 printf(" Feld: %d\t['%s']\n", Feld[x][y],
90 element_info[Feld[x][y]].token_name);
91 printf(" Back: %s\n", print_if_not_empty(Back[x][y]));
92 printf(" Store: %s\n", print_if_not_empty(Store[x][y]));
93 printf(" Store2: %s\n", print_if_not_empty(Store2[x][y]));
94 printf(" StorePlayer: %s\n", print_if_not_empty(StorePlayer[x][y]));
95 printf(" MovPos: %d\n", MovPos[x][y]);
96 printf(" MovDir: %d\n", MovDir[x][y]);
97 printf(" MovDelay: %d\n", MovDelay[x][y]);
98 printf(" ChangeDelay: %d\n", ChangeDelay[x][y]);
99 printf(" CustomValue: %d\n", CustomValue[x][y]);
100 printf(" GfxElement: %d\n", GfxElement[x][y]);
101 printf(" GfxAction: %d\n", GfxAction[x][y]);
102 printf(" GfxFrame: %d\n", GfxFrame[x][y]);
106 void SetDrawtoField(int mode)
108 if (mode == DRAW_BUFFERED && setup.soft_scrolling)
119 drawto_field = fieldbuffer;
121 else /* DRAW_BACKBUFFER */
127 BX2 = SCR_FIELDX - 1;
128 BY2 = SCR_FIELDY - 1;
132 drawto_field = backbuffer;
136 void RedrawPlayfield(boolean force_redraw, int x, int y, int width, int height)
138 if (game_status == GAME_MODE_PLAYING &&
139 level.game_engine_type == GAME_ENGINE_TYPE_EM)
141 /* currently there is no partial redraw -- always redraw whole playfield */
142 RedrawPlayfield_EM(TRUE);
144 /* blit playfield from scroll buffer to normal back buffer for fading in */
145 BlitScreenToBitmap_EM(backbuffer);
147 else if (game_status == GAME_MODE_PLAYING &&
148 level.game_engine_type == GAME_ENGINE_TYPE_SP)
150 /* currently there is no partial redraw -- always redraw whole playfield */
151 RedrawPlayfield_SP(TRUE);
153 /* blit playfield from scroll buffer to normal back buffer for fading in */
154 BlitScreenToBitmap_SP(backbuffer);
156 else if (game_status == GAME_MODE_PLAYING &&
157 !game.envelope_active)
163 width = gfx.sxsize + 2 * TILEX;
164 height = gfx.sysize + 2 * TILEY;
170 int x1 = (x - SX) / TILEX, y1 = (y - SY) / TILEY;
171 int x2 = (x - SX + width) / TILEX, y2 = (y - SY + height) / TILEY;
173 for (xx = BX1; xx <= BX2; xx++)
174 for (yy = BY1; yy <= BY2; yy++)
175 if (xx >= x1 && xx <= x2 && yy >= y1 && yy <= y2)
176 DrawScreenField(xx, yy);
180 if (setup.soft_scrolling)
182 int fx = FX, fy = FY;
184 fx += (ScreenMovDir & (MV_LEFT|MV_RIGHT) ? ScreenGfxPos : 0);
185 fy += (ScreenMovDir & (MV_UP|MV_DOWN) ? ScreenGfxPos : 0);
187 BlitBitmap(fieldbuffer, backbuffer, fx,fy, SXSIZE,SYSIZE, SX,SY);
199 BlitBitmap(drawto, window, x, y, width, height, x, y);
202 void DrawMaskedBorder_Rect(int x, int y, int width, int height)
204 Bitmap *bitmap = graphic_info[IMG_GLOBAL_BORDER].bitmap;
206 SetClipOrigin(bitmap, bitmap->stored_clip_gc, 0, 0);
207 BlitBitmapMasked(bitmap, backbuffer, x, y, width, height, x, y);
210 void DrawMaskedBorder_FIELD()
212 if (global.border_status >= GAME_MODE_TITLE &&
213 global.border_status <= GAME_MODE_PLAYING &&
214 border.draw_masked[global.border_status])
215 DrawMaskedBorder_Rect(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
218 void DrawMaskedBorder_DOOR_1()
220 if (border.draw_masked[GFX_SPECIAL_ARG_DOOR] &&
221 (global.border_status != GAME_MODE_EDITOR ||
222 border.draw_masked[GFX_SPECIAL_ARG_EDITOR]))
223 DrawMaskedBorder_Rect(DX, DY, DXSIZE, DYSIZE);
226 void DrawMaskedBorder_DOOR_2()
228 if (border.draw_masked[GFX_SPECIAL_ARG_DOOR] &&
229 global.border_status != GAME_MODE_EDITOR)
230 DrawMaskedBorder_Rect(VX, VY, VXSIZE, VYSIZE);
233 void DrawMaskedBorder_DOOR_3()
235 /* currently not available */
238 void DrawMaskedBorder_ALL()
240 DrawMaskedBorder_FIELD();
241 DrawMaskedBorder_DOOR_1();
242 DrawMaskedBorder_DOOR_2();
243 DrawMaskedBorder_DOOR_3();
246 void DrawMaskedBorder(int redraw_mask)
248 /* never draw masked screen borders on borderless screens */
249 if (effectiveGameStatus() == GAME_MODE_LOADING ||
250 effectiveGameStatus() == GAME_MODE_TITLE)
253 if (redraw_mask & REDRAW_ALL)
254 DrawMaskedBorder_ALL();
257 if (redraw_mask & REDRAW_FIELD)
258 DrawMaskedBorder_FIELD();
259 if (redraw_mask & REDRAW_DOOR_1)
260 DrawMaskedBorder_DOOR_1();
261 if (redraw_mask & REDRAW_DOOR_2)
262 DrawMaskedBorder_DOOR_2();
263 if (redraw_mask & REDRAW_DOOR_3)
264 DrawMaskedBorder_DOOR_3();
271 DrawBuffer *buffer = (drawto_field == window ? backbuffer : drawto_field);
274 printf("::: TILES TO REFRESH: %d\n", redraw_tiles);
275 for (x = 0; x < SCR_FIELDX; x++)
276 for (y = 0 ; y < SCR_FIELDY; y++)
277 if (redraw[redraw_x1 + x][redraw_y1 + y])
278 printf("::: - %d, %d [%s]\n",
279 LEVELX(x), LEVELY(y),
280 EL_NAME(Feld[LEVELX(x)][LEVELY(y)]));
283 if (redraw_mask & REDRAW_TILES && redraw_tiles > REDRAWTILES_THRESHOLD)
284 redraw_mask |= REDRAW_FIELD;
286 if (redraw_mask & REDRAW_FIELD)
287 redraw_mask &= ~REDRAW_TILES;
289 if (redraw_mask == REDRAW_NONE)
292 if (redraw_mask & REDRAW_TILES &&
293 game_status == GAME_MODE_PLAYING &&
294 border.draw_masked[GAME_MODE_PLAYING])
295 redraw_mask |= REDRAW_FIELD;
297 if (global.fps_slowdown && game_status == GAME_MODE_PLAYING)
299 static boolean last_frame_skipped = FALSE;
300 boolean skip_even_when_not_scrolling = TRUE;
301 boolean just_scrolling = (ScreenMovDir != 0);
302 boolean verbose = FALSE;
304 if (global.fps_slowdown_factor > 1 &&
305 (FrameCounter % global.fps_slowdown_factor) &&
306 (just_scrolling || skip_even_when_not_scrolling))
308 redraw_mask &= ~REDRAW_MAIN;
310 last_frame_skipped = TRUE;
313 printf("FRAME SKIPPED\n");
317 if (last_frame_skipped)
318 redraw_mask |= REDRAW_FIELD;
320 last_frame_skipped = FALSE;
323 printf("frame not skipped\n");
327 /* synchronize X11 graphics at this point; if we would synchronize the
328 display immediately after the buffer switching (after the XFlush),
329 this could mean that we have to wait for the graphics to complete,
330 although we could go on doing calculations for the next frame */
334 /* prevent drawing masked border to backbuffer when using playfield buffer */
335 if (game_status != GAME_MODE_PLAYING ||
336 redraw_mask & REDRAW_FROM_BACKBUFFER ||
337 buffer == backbuffer)
338 DrawMaskedBorder(redraw_mask);
340 DrawMaskedBorder(redraw_mask & REDRAW_DOORS);
342 if (redraw_mask & REDRAW_ALL)
344 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
346 redraw_mask = REDRAW_NONE;
349 if (redraw_mask & REDRAW_FIELD)
351 if (game_status != GAME_MODE_PLAYING ||
352 redraw_mask & REDRAW_FROM_BACKBUFFER)
354 BlitBitmap(backbuffer, window,
355 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE, REAL_SX, REAL_SY);
359 int fx = FX, fy = FY;
361 if (setup.soft_scrolling)
363 fx += (ScreenMovDir & (MV_LEFT | MV_RIGHT) ? ScreenGfxPos : 0);
364 fy += (ScreenMovDir & (MV_UP | MV_DOWN) ? ScreenGfxPos : 0);
367 if (setup.soft_scrolling ||
368 ABS(ScreenMovPos) + ScrollStepSize == TILEX ||
369 ABS(ScreenMovPos) == ScrollStepSize ||
370 redraw_tiles > REDRAWTILES_THRESHOLD)
372 if (border.draw_masked[GAME_MODE_PLAYING])
374 if (buffer != backbuffer)
376 /* copy playfield buffer to backbuffer to add masked border */
377 BlitBitmap(buffer, backbuffer, fx, fy, SXSIZE, SYSIZE, SX, SY);
378 DrawMaskedBorder(REDRAW_FIELD);
381 BlitBitmap(backbuffer, window,
382 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
387 BlitBitmap(buffer, window, fx, fy, SXSIZE, SYSIZE, SX, SY);
392 printf("redrawing all (ScreenGfxPos == %d) because %s\n",
394 (setup.soft_scrolling ?
395 "setup.soft_scrolling" :
396 ABS(ScreenGfxPos) + ScrollStepSize == TILEX ?
397 "ABS(ScreenGfxPos) + ScrollStepSize == TILEX" :
398 ABS(ScreenGfxPos) == ScrollStepSize ?
399 "ABS(ScreenGfxPos) == ScrollStepSize" :
400 "redraw_tiles > REDRAWTILES_THRESHOLD"));
406 redraw_mask &= ~REDRAW_MAIN;
409 if (redraw_mask & REDRAW_DOORS)
411 if (redraw_mask & REDRAW_DOOR_1)
412 BlitBitmap(backbuffer, window, DX, DY, DXSIZE, DYSIZE, DX, DY);
414 if (redraw_mask & REDRAW_DOOR_2)
415 BlitBitmap(backbuffer, window, VX, VY, VXSIZE, VYSIZE, VX, VY);
417 if (redraw_mask & REDRAW_DOOR_3)
418 BlitBitmap(backbuffer, window, EX, EY, EXSIZE, EYSIZE, EX, EY);
420 redraw_mask &= ~REDRAW_DOORS;
423 if (redraw_mask & REDRAW_MICROLEVEL)
425 BlitBitmap(backbuffer, window, SX, SY + 10 * TILEY, SXSIZE, 7 * TILEY,
426 SX, SY + 10 * TILEY);
428 redraw_mask &= ~REDRAW_MICROLEVEL;
431 if (redraw_mask & REDRAW_TILES)
433 for (x = 0; x < SCR_FIELDX; x++)
434 for (y = 0 ; y < SCR_FIELDY; y++)
435 if (redraw[redraw_x1 + x][redraw_y1 + y])
436 BlitBitmap(buffer, window,
437 FX + x * TILEX, FY + y * TILEY, TILEX, TILEY,
438 SX + x * TILEX, SY + y * TILEY);
441 if (redraw_mask & REDRAW_FPS) /* display frames per second */
446 sprintf(info1, " (only every %d. frame)", global.fps_slowdown_factor);
447 if (!global.fps_slowdown)
450 sprintf(text, "%04.1f fps%s", global.frames_per_second, info1);
452 DrawTextExt(window, SX + SXSIZE + SX, 0, text, FONT_TEXT_2, BLIT_OPAQUE);
454 DrawTextExt(window, SX, SY, text, FONT_TEXT_2, BLIT_OPAQUE);
460 for (x = 0; x < MAX_BUF_XSIZE; x++)
461 for (y = 0; y < MAX_BUF_YSIZE; y++)
464 redraw_mask = REDRAW_NONE;
467 static void FadeCrossSaveBackbuffer()
469 BlitBitmap(backbuffer, bitmap_db_cross, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
472 static void FadeExt(int fade_mask, int fade_mode, int fade_type)
474 static int fade_type_skip = FADE_TYPE_NONE;
475 void (*draw_border_function)(void) = NULL;
476 Bitmap *bitmap = (fade_mode & FADE_TYPE_TRANSFORM ? bitmap_db_cross : NULL);
477 int x, y, width, height;
478 int fade_delay, post_delay;
480 if (fade_type == FADE_TYPE_FADE_OUT)
482 if (fade_type_skip != FADE_TYPE_NONE)
485 printf("::: skipping %d ... [%d] (X)\n", fade_mode, fade_type_skip);
488 /* skip all fade operations until specified fade operation */
489 if (fade_type & fade_type_skip)
490 fade_type_skip = FADE_TYPE_NONE;
495 if (fading.fade_mode & FADE_TYPE_TRANSFORM)
497 FadeCrossSaveBackbuffer();
503 redraw_mask |= fade_mask;
505 if (fade_type == FADE_TYPE_SKIP)
508 printf("::: will skip %d ... [%d]\n", fade_mode, fade_type_skip);
511 fade_type_skip = fade_mode;
517 printf("::: !!! FADING %d ... [%d] [%d]\n", fade_mode, fade_type,
522 fade_delay = fading.fade_delay;
523 post_delay = (fade_mode == FADE_MODE_FADE_OUT ? fading.post_delay : 0);
526 if (fade_type_skip != FADE_TYPE_NONE)
529 printf("::: skipping %d ... [%d]\n", fade_mode, fade_type_skip);
532 /* skip all fade operations until specified fade operation */
533 if (fade_type & fade_type_skip)
534 fade_type_skip = FADE_TYPE_NONE;
544 if (global.autoplay_leveldir)
546 // fading.fade_mode = FADE_MODE_NONE;
553 if (fading.fade_mode == FADE_MODE_NONE)
561 /* !!! what about fade_mask == REDRAW_FIELD | REDRAW_ALL ??? !!! */
564 printf("::: NOW FADING %d ... [%d]\n", fade_mode, fade_type);
568 if (fade_mask == REDRAW_NONE)
569 fade_mask = REDRAW_FIELD;
572 // if (fade_mask & REDRAW_FIELD)
573 if (fade_mask == REDRAW_FIELD)
578 height = FULL_SYSIZE;
581 fade_delay = fading.fade_delay;
582 post_delay = (fade_mode == FADE_MODE_FADE_OUT ? fading.post_delay : 0);
585 if (border.draw_masked_when_fading)
586 draw_border_function = DrawMaskedBorder_FIELD; /* update when fading */
588 DrawMaskedBorder_FIELD(); /* draw once */
590 else /* REDRAW_ALL */
598 fade_delay = fading.fade_delay;
599 post_delay = (fade_mode == FADE_MODE_FADE_OUT ? fading.post_delay : 0);
604 if (!setup.fade_screens ||
606 fading.fade_mode == FADE_MODE_NONE)
608 if (!setup.fade_screens || fade_delay == 0)
611 if (fade_mode == FADE_MODE_FADE_OUT)
615 if (fade_mode == FADE_MODE_FADE_OUT &&
616 fading.fade_mode != FADE_MODE_NONE)
617 ClearRectangle(backbuffer, x, y, width, height);
621 BlitBitmap(backbuffer, window, x, y, width, height, x, y);
622 redraw_mask = REDRAW_NONE;
630 FadeRectangle(bitmap, x, y, width, height, fade_mode, fade_delay, post_delay,
631 draw_border_function);
633 redraw_mask &= ~fade_mask;
636 void FadeIn(int fade_mask)
638 if (fading.fade_mode & FADE_TYPE_TRANSFORM)
639 FadeExt(fade_mask, fading.fade_mode, FADE_TYPE_FADE_IN);
641 FadeExt(fade_mask, FADE_MODE_FADE_IN, FADE_TYPE_FADE_IN);
644 void FadeOut(int fade_mask)
646 if (fading.fade_mode & FADE_TYPE_TRANSFORM)
647 FadeExt(fade_mask, fading.fade_mode, FADE_TYPE_FADE_OUT);
649 FadeExt(fade_mask, FADE_MODE_FADE_OUT, FADE_TYPE_FADE_OUT);
651 global.border_status = game_status;
654 static void FadeSetLeaveNext(struct TitleFadingInfo fading_leave, boolean set)
656 static struct TitleFadingInfo fading_leave_stored;
659 fading_leave_stored = fading_leave;
661 fading = fading_leave_stored;
664 void FadeSetEnterMenu()
666 fading = menu.enter_menu;
669 printf("::: storing enter_menu\n");
672 FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */
675 void FadeSetLeaveMenu()
677 fading = menu.leave_menu;
680 printf("::: storing leave_menu\n");
683 FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */
686 void FadeSetEnterScreen()
688 fading = menu.enter_screen[game_status];
691 printf("::: storing leave_screen[%d]\n", game_status);
694 FadeSetLeaveNext(menu.leave_screen[game_status], TRUE); /* store */
697 void FadeSetNextScreen()
699 fading = menu.next_screen;
702 printf("::: storing next_screen\n");
705 // (do not overwrite fade mode set by FadeSetEnterScreen)
706 // FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */
709 void FadeSetLeaveScreen()
712 printf("::: recalling last stored value\n");
715 FadeSetLeaveNext(menu.leave_screen[game_status], FALSE); /* recall */
718 void FadeSetFromType(int type)
720 if (type & TYPE_ENTER_SCREEN)
721 FadeSetEnterScreen();
722 else if (type & TYPE_ENTER)
724 else if (type & TYPE_LEAVE)
728 void FadeSetDisabled()
730 static struct TitleFadingInfo fading_none = { FADE_MODE_NONE, -1, -1, -1 };
732 fading = fading_none;
735 void FadeSkipNextFadeIn()
737 FadeExt(0, FADE_MODE_SKIP_FADE_IN, FADE_TYPE_SKIP);
740 void FadeSkipNextFadeOut()
742 FadeExt(0, FADE_MODE_SKIP_FADE_OUT, FADE_TYPE_SKIP);
745 void SetWindowBackgroundImageIfDefined(int graphic)
747 if (graphic_info[graphic].bitmap)
748 SetWindowBackgroundBitmap(graphic_info[graphic].bitmap);
751 void SetMainBackgroundImageIfDefined(int graphic)
753 if (graphic_info[graphic].bitmap)
754 SetMainBackgroundBitmap(graphic_info[graphic].bitmap);
757 void SetDoorBackgroundImageIfDefined(int graphic)
759 if (graphic_info[graphic].bitmap)
760 SetDoorBackgroundBitmap(graphic_info[graphic].bitmap);
763 void SetWindowBackgroundImage(int graphic)
765 SetWindowBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
766 graphic_info[graphic].bitmap ?
767 graphic_info[graphic].bitmap :
768 graphic_info[IMG_BACKGROUND].bitmap);
771 void SetMainBackgroundImage(int graphic)
773 SetMainBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
774 graphic_info[graphic].bitmap ?
775 graphic_info[graphic].bitmap :
776 graphic_info[IMG_BACKGROUND].bitmap);
779 void SetDoorBackgroundImage(int graphic)
781 SetDoorBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
782 graphic_info[graphic].bitmap ?
783 graphic_info[graphic].bitmap :
784 graphic_info[IMG_BACKGROUND].bitmap);
787 void SetPanelBackground()
789 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, bitmap_db_panel,
790 DOOR_GFX_PAGEX5, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE, 0, 0);
792 SetDoorBackgroundBitmap(bitmap_db_panel);
795 void DrawBackground(int x, int y, int width, int height)
797 /* !!! "drawto" might still point to playfield buffer here (see below) !!! */
798 /* (when entering hall of fame after playing) */
800 ClearRectangleOnBackground(drawto, x, y, width, height);
802 ClearRectangleOnBackground(backbuffer, x, y, width, height);
805 redraw_mask |= REDRAW_FIELD;
808 void DrawBackgroundForFont(int x, int y, int width, int height, int font_nr)
810 struct FontBitmapInfo *font = getFontBitmapInfo(font_nr);
812 if (font->bitmap == NULL)
815 DrawBackground(x, y, width, height);
818 void DrawBackgroundForGraphic(int x, int y, int width, int height, int graphic)
820 struct GraphicInfo *g = &graphic_info[graphic];
822 if (g->bitmap == NULL)
825 DrawBackground(x, y, width, height);
830 /* !!! "drawto" might still point to playfield buffer here (see above) !!! */
831 /* (when entering hall of fame after playing) */
832 DrawBackground(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
834 /* !!! maybe this should be done before clearing the background !!! */
835 if (setup.soft_scrolling && game_status == GAME_MODE_PLAYING)
837 ClearRectangle(fieldbuffer, 0, 0, FXSIZE, FYSIZE);
838 SetDrawtoField(DRAW_BUFFERED);
841 SetDrawtoField(DRAW_BACKBUFFER);
844 void MarkTileDirty(int x, int y)
846 int xx = redraw_x1 + x;
847 int yy = redraw_y1 + y;
852 redraw[xx][yy] = TRUE;
853 redraw_mask |= REDRAW_TILES;
856 void SetBorderElement()
860 BorderElement = EL_EMPTY;
862 for (y = 0; y < lev_fieldy && BorderElement == EL_EMPTY; y++)
864 for (x = 0; x < lev_fieldx; x++)
866 if (!IS_INDESTRUCTIBLE(Feld[x][y]))
867 BorderElement = EL_STEELWALL;
869 if (y != 0 && y != lev_fieldy - 1 && x != lev_fieldx - 1)
875 void FloodFillLevel(int from_x, int from_y, int fill_element,
876 short field[MAX_LEV_FIELDX][MAX_LEV_FIELDY],
877 int max_fieldx, int max_fieldy)
881 static int check[4][2] = { { -1, 0 }, { 0, -1 }, { 1, 0 }, { 0, 1 } };
882 static int safety = 0;
884 /* check if starting field still has the desired content */
885 if (field[from_x][from_y] == fill_element)
890 if (safety > max_fieldx * max_fieldy)
891 Error(ERR_EXIT, "Something went wrong in 'FloodFill()'. Please debug.");
893 old_element = field[from_x][from_y];
894 field[from_x][from_y] = fill_element;
896 for (i = 0; i < 4; i++)
898 x = from_x + check[i][0];
899 y = from_y + check[i][1];
901 if (IN_FIELD(x, y, max_fieldx, max_fieldy) && field[x][y] == old_element)
902 FloodFillLevel(x, y, fill_element, field, max_fieldx, max_fieldy);
908 void SetRandomAnimationValue(int x, int y)
910 gfx.anim_random_frame = GfxRandom[x][y];
913 inline int getGraphicAnimationFrame(int graphic, int sync_frame)
915 /* animation synchronized with global frame counter, not move position */
916 if (graphic_info[graphic].anim_global_sync || sync_frame < 0)
917 sync_frame = FrameCounter;
919 return getAnimationFrame(graphic_info[graphic].anim_frames,
920 graphic_info[graphic].anim_delay,
921 graphic_info[graphic].anim_mode,
922 graphic_info[graphic].anim_start_frame,
926 void getSizedGraphicSource(int graphic, int frame, int tilesize_raw,
927 Bitmap **bitmap, int *x, int *y)
931 int width_mult, width_div;
932 int height_mult, height_div;
936 { 15, 16, 2, 3 }, /* 1 x 1 */
937 { 7, 8, 2, 3 }, /* 2 x 2 */
938 { 3, 4, 2, 3 }, /* 4 x 4 */
939 { 1, 2, 2, 3 }, /* 8 x 8 */
940 { 0, 1, 2, 3 }, /* 16 x 16 */
941 { 0, 1, 0, 1 }, /* 32 x 32 */
943 struct GraphicInfo *g = &graphic_info[graphic];
944 Bitmap *src_bitmap = g->bitmap;
945 int tilesize = MIN(MAX(1, tilesize_raw), TILESIZE);
946 int offset_calc_pos = log_2(tilesize);
947 int width_mult = offset_calc[offset_calc_pos].width_mult;
948 int width_div = offset_calc[offset_calc_pos].width_div;
949 int height_mult = offset_calc[offset_calc_pos].height_mult;
950 int height_div = offset_calc[offset_calc_pos].height_div;
951 int startx = src_bitmap->width * width_mult / width_div;
952 int starty = src_bitmap->height * height_mult / height_div;
953 int src_x = g->src_x * tilesize / TILESIZE;
954 int src_y = g->src_y * tilesize / TILESIZE;
955 int width = g->width * tilesize / TILESIZE;
956 int height = g->height * tilesize / TILESIZE;
957 int offset_x = g->offset_x * tilesize / TILESIZE;
958 int offset_y = g->offset_y * tilesize / TILESIZE;
960 if (g->offset_y == 0) /* frames are ordered horizontally */
962 int max_width = g->anim_frames_per_line * width;
963 int pos = (src_y / height) * max_width + src_x + frame * offset_x;
965 src_x = pos % max_width;
966 src_y = src_y % height + pos / max_width * height;
968 else if (g->offset_x == 0) /* frames are ordered vertically */
970 int max_height = g->anim_frames_per_line * height;
971 int pos = (src_x / width) * max_height + src_y + frame * offset_y;
973 src_x = src_x % width + pos / max_height * width;
974 src_y = pos % max_height;
976 else /* frames are ordered diagonally */
978 src_x = src_x + frame * offset_x;
979 src_y = src_y + frame * offset_y;
982 *bitmap = src_bitmap;
987 void getMiniGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
990 getSizedGraphicSource(graphic, 0, MINI_TILESIZE, bitmap, x, y);
992 struct GraphicInfo *g = &graphic_info[graphic];
994 int mini_starty = g->bitmap->height * 2 / 3;
997 *x = mini_startx + g->src_x / 2;
998 *y = mini_starty + g->src_y / 2;
1002 inline void getGraphicSourceExt(int graphic, int frame, Bitmap **bitmap,
1003 int *x, int *y, boolean get_backside)
1005 struct GraphicInfo *g = &graphic_info[graphic];
1006 int src_x = g->src_x + (get_backside ? g->offset2_x : 0);
1007 int src_y = g->src_y + (get_backside ? g->offset2_y : 0);
1009 *bitmap = g->bitmap;
1011 if (g->offset_y == 0) /* frames are ordered horizontally */
1013 int max_width = g->anim_frames_per_line * g->width;
1014 int pos = (src_y / g->height) * max_width + src_x + frame * g->offset_x;
1016 *x = pos % max_width;
1017 *y = src_y % g->height + pos / max_width * g->height;
1019 else if (g->offset_x == 0) /* frames are ordered vertically */
1021 int max_height = g->anim_frames_per_line * g->height;
1022 int pos = (src_x / g->width) * max_height + src_y + frame * g->offset_y;
1024 *x = src_x % g->width + pos / max_height * g->width;
1025 *y = pos % max_height;
1027 else /* frames are ordered diagonally */
1029 *x = src_x + frame * g->offset_x;
1030 *y = src_y + frame * g->offset_y;
1034 void getGraphicSource(int graphic, int frame, Bitmap **bitmap, int *x, int *y)
1036 getGraphicSourceExt(graphic, frame, bitmap, x, y, FALSE);
1039 void DrawGraphic(int x, int y, int graphic, int frame)
1042 if (!IN_SCR_FIELD(x, y))
1044 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
1045 printf("DrawGraphic(): This should never happen!\n");
1050 DrawGraphicExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic, frame);
1051 MarkTileDirty(x, y);
1054 void DrawGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
1060 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1061 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
1064 void DrawGraphicThruMask(int x, int y, int graphic, int frame)
1067 if (!IN_SCR_FIELD(x, y))
1069 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
1070 printf("DrawGraphicThruMask(): This should never happen!\n");
1075 DrawGraphicThruMaskExt(drawto_field, FX + x * TILEX, FY + y *TILEY, graphic,
1077 MarkTileDirty(x, y);
1080 void DrawGraphicThruMaskExt(DrawBuffer *d, int dst_x, int dst_y, int graphic,
1086 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1088 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1089 dst_x - src_x, dst_y - src_y);
1090 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX, TILEY, dst_x, dst_y);
1093 void DrawSizedGraphic(int x, int y, int graphic, int frame, int tilesize)
1095 DrawSizedGraphicExt(drawto, SX + x * tilesize, SY + y * tilesize, graphic,
1097 MarkTileDirty(x / tilesize, y / tilesize);
1100 void DrawSizedGraphicExt(DrawBuffer *d, int x, int y, int graphic, int frame,
1106 getSizedGraphicSource(graphic, frame, tilesize, &src_bitmap, &src_x, &src_y);
1107 BlitBitmap(src_bitmap, d, src_x, src_y, tilesize, tilesize, x, y);
1110 void DrawMiniGraphic(int x, int y, int graphic)
1112 DrawMiniGraphicExt(drawto, SX + x * MINI_TILEX,SY + y * MINI_TILEY, graphic);
1113 MarkTileDirty(x / 2, y / 2);
1116 void DrawMiniGraphicExt(DrawBuffer *d, int x, int y, int graphic)
1121 getMiniGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
1122 BlitBitmap(src_bitmap, d, src_x, src_y, MINI_TILEX, MINI_TILEY, x, y);
1125 inline static void DrawGraphicShiftedNormal(int x, int y, int dx, int dy,
1126 int graphic, int frame,
1127 int cut_mode, int mask_mode)
1132 int width = TILEX, height = TILEY;
1135 if (dx || dy) /* shifted graphic */
1137 if (x < BX1) /* object enters playfield from the left */
1144 else if (x > BX2) /* object enters playfield from the right */
1150 else if (x==BX1 && dx < 0) /* object leaves playfield to the left */
1156 else if (x==BX2 && dx > 0) /* object leaves playfield to the right */
1158 else if (dx) /* general horizontal movement */
1159 MarkTileDirty(x + SIGN(dx), y);
1161 if (y < BY1) /* object enters playfield from the top */
1163 if (cut_mode==CUT_BELOW) /* object completely above top border */
1171 else if (y > BY2) /* object enters playfield from the bottom */
1177 else if (y==BY1 && dy < 0) /* object leaves playfield to the top */
1183 else if (dy > 0 && cut_mode == CUT_ABOVE)
1185 if (y == BY2) /* object completely above bottom border */
1191 MarkTileDirty(x, y + 1);
1192 } /* object leaves playfield to the bottom */
1193 else if (dy > 0 && (y == BY2 || cut_mode == CUT_BELOW))
1195 else if (dy) /* general vertical movement */
1196 MarkTileDirty(x, y + SIGN(dy));
1200 if (!IN_SCR_FIELD(x, y))
1202 printf("DrawGraphicShifted(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
1203 printf("DrawGraphicShifted(): This should never happen!\n");
1208 if (width > 0 && height > 0)
1210 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1215 dst_x = FX + x * TILEX + dx;
1216 dst_y = FY + y * TILEY + dy;
1218 if (mask_mode == USE_MASKING)
1220 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1221 dst_x - src_x, dst_y - src_y);
1222 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1226 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1229 MarkTileDirty(x, y);
1233 inline static void DrawGraphicShiftedDouble(int x, int y, int dx, int dy,
1234 int graphic, int frame,
1235 int cut_mode, int mask_mode)
1240 int width = TILEX, height = TILEY;
1243 int x2 = x + SIGN(dx);
1244 int y2 = y + SIGN(dy);
1246 /* !!! DOES NOT WORK FOR SLOW MOVEMENT !!! */
1247 int sync_frame = GfxFrame[LEVELX(x)][LEVELY(y)];
1249 /* movement with two-tile animations must be sync'ed with movement position,
1250 not with current GfxFrame (which can be higher when using slow movement) */
1251 int anim_pos = (dx ? ABS(dx) : ABS(dy));
1252 int anim_frames = graphic_info[graphic].anim_frames;
1254 /* (we also need anim_delay here for movement animations with less frames) */
1255 int anim_delay = graphic_info[graphic].anim_delay;
1256 int sync_frame = anim_pos * anim_frames * anim_delay / TILESIZE;
1258 int sync_frame = anim_pos * anim_frames / TILESIZE;
1261 boolean draw_start_tile = (cut_mode != CUT_ABOVE); /* only for falling! */
1262 boolean draw_end_tile = (cut_mode != CUT_BELOW); /* only for falling! */
1264 /* re-calculate animation frame for two-tile movement animation */
1265 frame = getGraphicAnimationFrame(graphic, sync_frame);
1269 printf("::: %d, %d, %d => %d [%d]\n",
1270 anim_pos, anim_frames, anim_delay, sync_frame, graphic);
1272 printf("::: %d, %d => %d\n",
1273 anim_pos, anim_frames, sync_frame);
1278 printf("::: %d [%d, %d] [%d] [%d]\n", frame, sync_frame, dy,
1279 GfxFrame[LEVELX(x)][LEVELY(y)], mask_mode);
1282 /* check if movement start graphic inside screen area and should be drawn */
1283 if (draw_start_tile && IN_SCR_FIELD(x1, y1))
1285 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, TRUE);
1287 dst_x = FX + x1 * TILEX;
1288 dst_y = FY + y1 * TILEY;
1290 if (mask_mode == USE_MASKING)
1292 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1293 dst_x - src_x, dst_y - src_y);
1294 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1298 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1301 MarkTileDirty(x1, y1);
1304 /* check if movement end graphic inside screen area and should be drawn */
1305 if (draw_end_tile && IN_SCR_FIELD(x2, y2))
1307 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
1309 dst_x = FX + x2 * TILEX;
1310 dst_y = FY + y2 * TILEY;
1312 if (mask_mode == USE_MASKING)
1314 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1315 dst_x - src_x, dst_y - src_y);
1316 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1320 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1323 MarkTileDirty(x2, y2);
1327 static void DrawGraphicShifted(int x, int y, int dx, int dy,
1328 int graphic, int frame,
1329 int cut_mode, int mask_mode)
1333 DrawGraphic(x, y, graphic, frame);
1338 if (graphic_info[graphic].double_movement) /* EM style movement images */
1339 DrawGraphicShiftedDouble(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
1341 DrawGraphicShiftedNormal(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
1344 void DrawGraphicShiftedThruMask(int x, int y, int dx, int dy, int graphic,
1345 int frame, int cut_mode)
1347 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, USE_MASKING);
1350 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
1351 int cut_mode, int mask_mode)
1353 int lx = LEVELX(x), ly = LEVELY(y);
1357 if (IN_LEV_FIELD(lx, ly))
1359 SetRandomAnimationValue(lx, ly);
1361 graphic = el_act_dir2img(element, GfxAction[lx][ly], GfxDir[lx][ly]);
1362 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1364 /* do not use double (EM style) movement graphic when not moving */
1365 if (graphic_info[graphic].double_movement && !dx && !dy)
1367 graphic = el_act_dir2img(element, ACTION_DEFAULT, GfxDir[lx][ly]);
1368 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1371 else /* border element */
1373 graphic = el2img(element);
1374 frame = getGraphicAnimationFrame(graphic, -1);
1377 if (element == EL_EXPANDABLE_WALL)
1379 boolean left_stopped = FALSE, right_stopped = FALSE;
1381 if (!IN_LEV_FIELD(lx - 1, ly) || IS_WALL(Feld[lx - 1][ly]))
1382 left_stopped = TRUE;
1383 if (!IN_LEV_FIELD(lx + 1, ly) || IS_WALL(Feld[lx + 1][ly]))
1384 right_stopped = TRUE;
1386 if (left_stopped && right_stopped)
1388 else if (left_stopped)
1390 graphic = IMG_EXPANDABLE_WALL_GROWING_RIGHT;
1391 frame = graphic_info[graphic].anim_frames - 1;
1393 else if (right_stopped)
1395 graphic = IMG_EXPANDABLE_WALL_GROWING_LEFT;
1396 frame = graphic_info[graphic].anim_frames - 1;
1401 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, mask_mode);
1402 else if (mask_mode == USE_MASKING)
1403 DrawGraphicThruMask(x, y, graphic, frame);
1405 DrawGraphic(x, y, graphic, frame);
1408 void DrawLevelElementExt(int x, int y, int dx, int dy, int element,
1409 int cut_mode, int mask_mode)
1411 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1412 DrawScreenElementExt(SCREENX(x), SCREENY(y), dx, dy, element,
1413 cut_mode, mask_mode);
1416 void DrawScreenElementShifted(int x, int y, int dx, int dy, int element,
1419 DrawScreenElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1422 void DrawLevelElementShifted(int x, int y, int dx, int dy, int element,
1425 DrawLevelElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1428 void DrawLevelElementThruMask(int x, int y, int element)
1430 DrawLevelElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1433 void DrawLevelFieldThruMask(int x, int y)
1435 DrawLevelElementExt(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
1438 /* !!! implementation of quicksand is totally broken !!! */
1439 #define IS_CRUMBLED_TILE(x, y, e) \
1440 (GFX_CRUMBLED(e) && (!IN_LEV_FIELD(x, y) || \
1441 !IS_MOVING(x, y) || \
1442 (e) == EL_QUICKSAND_EMPTYING || \
1443 (e) == EL_QUICKSAND_FAST_EMPTYING))
1445 inline static void DrawLevelFieldCrumbledSandExtBlit(int x, int y,
1446 int graphic, int frame,
1451 int width, height, bx, by, cx, cy;
1452 int sx = SCREENX(x), sy = SCREENY(y);
1453 int crumbled_border_size = graphic_info[graphic].border_size;
1456 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1458 /* draw simple, sloppy, non-corner-accurate crumbled border */
1460 if (dir == 1 || dir == 2) /* left or right crumbled border */
1462 width = crumbled_border_size;
1464 cx = (dir == 2 ? TILEX - crumbled_border_size : 0);
1467 else /* top or bottom crumbled border */
1470 height = crumbled_border_size;
1472 cy = (dir == 3 ? TILEY - crumbled_border_size : 0);
1475 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1476 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
1478 /* (remaining middle border part must be at least as big as corner part) */
1479 if (!(graphic_info[graphic].style & STYLE_ACCURATE_BORDERS) ||
1480 crumbled_border_size >= TILESIZE / 3)
1483 /* correct corners of crumbled border, if needed */
1485 if (dir == 1 || dir == 2) /* left or right crumbled border */
1487 for (i = -1; i <= 1; i+=2)
1491 int element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1494 /* check if neighbour field is of same crumble type */
1495 if (IS_CRUMBLED_TILE(xx, yy, element) &&
1496 graphic_info[graphic].class ==
1497 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class)
1499 /* no crumbled corner, but continued crumbled border */
1501 width = crumbled_border_size;
1502 height = crumbled_border_size;
1503 cx = (dir == 2 ? TILEX - crumbled_border_size : 0);
1504 cy = (i == 1 ? TILEX - crumbled_border_size : 0);
1506 by = (i == 1 ? crumbled_border_size :
1507 TILEY - 2 * crumbled_border_size);
1509 BlitBitmap(src_bitmap, drawto_field, src_x + bx, src_y + by,
1510 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
1514 else /* top or bottom crumbled border */
1516 for (i = -1; i <= 1; i+=2)
1520 int element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1523 /* check if neighbour field is of same crumble type */
1524 if (IS_CRUMBLED_TILE(xx, yy, element) &&
1525 graphic_info[graphic].class ==
1526 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class)
1528 /* no crumbled corner, but continued crumbled border */
1530 width = crumbled_border_size;
1531 height = crumbled_border_size;
1532 cx = (i == 1 ? TILEX - crumbled_border_size : 0);
1533 cy = (dir == 3 ? TILEY - crumbled_border_size : 0);
1534 bx = (i == 1 ? crumbled_border_size :
1535 TILEY - 2 * crumbled_border_size);
1538 BlitBitmap(src_bitmap, drawto_field, src_x + bx, src_y + by,
1539 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
1545 static void DrawLevelFieldCrumbledSandExt(int x, int y, int graphic, int frame)
1547 int sx = SCREENX(x), sy = SCREENY(y);
1550 static int xy[4][2] =
1558 if (!IN_LEV_FIELD(x, y))
1561 element = TILE_GFX_ELEMENT(x, y);
1563 /* crumble field itself */
1564 if (IS_CRUMBLED_TILE(x, y, element))
1566 if (!IN_SCR_FIELD(sx, sy))
1569 for (i = 0; i < 4; i++)
1571 int xx = x + xy[i][0];
1572 int yy = y + xy[i][1];
1574 element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1577 /* check if neighbour field is of same crumble type */
1579 if (IS_CRUMBLED_TILE(xx, yy, element) &&
1580 graphic_info[graphic].class ==
1581 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class)
1584 if (IS_CRUMBLED_TILE(xx, yy, element))
1588 DrawLevelFieldCrumbledSandExtBlit(x, y, graphic, frame, i);
1591 MarkTileDirty(sx, sy);
1593 else /* center field not crumbled -- crumble neighbour fields */
1595 for (i = 0; i < 4; i++)
1597 int xx = x + xy[i][0];
1598 int yy = y + xy[i][1];
1599 int sxx = sx + xy[i][0];
1600 int syy = sy + xy[i][1];
1602 if (!IN_LEV_FIELD(xx, yy) ||
1603 !IN_SCR_FIELD(sxx, syy))
1606 if (Feld[xx][yy] == EL_ELEMENT_SNAPPING)
1609 element = TILE_GFX_ELEMENT(xx, yy);
1611 if (!IS_CRUMBLED_TILE(xx, yy, element))
1614 graphic = el_act2crm(element, ACTION_DEFAULT);
1616 DrawLevelFieldCrumbledSandExtBlit(xx, yy, graphic, 0, 3 - i);
1618 MarkTileDirty(sxx, syy);
1623 void DrawLevelFieldCrumbledSand(int x, int y)
1627 if (!IN_LEV_FIELD(x, y))
1631 /* !!! CHECK THIS !!! */
1634 if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
1635 GFX_CRUMBLED(GfxElement[x][y]))
1638 if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
1639 GfxElement[x][y] != EL_UNDEFINED &&
1640 GFX_CRUMBLED(GfxElement[x][y]))
1642 DrawLevelFieldCrumbledSandDigging(x, y, GfxDir[x][y], GfxFrame[x][y]);
1649 graphic = el_act2crm(TILE_GFX_ELEMENT(x, y), ACTION_DEFAULT);
1651 graphic = el_act2crm(Feld[x][y], ACTION_DEFAULT);
1654 DrawLevelFieldCrumbledSandExt(x, y, graphic, 0);
1657 void DrawLevelFieldCrumbledSandDigging(int x, int y, int direction,
1660 int graphic1 = el_act_dir2img(GfxElement[x][y], ACTION_DIGGING, direction);
1661 int graphic2 = el_act_dir2crm(GfxElement[x][y], ACTION_DIGGING, direction);
1662 int frame1 = getGraphicAnimationFrame(graphic1, step_frame);
1663 int frame2 = getGraphicAnimationFrame(graphic2, step_frame);
1664 int sx = SCREENX(x), sy = SCREENY(y);
1666 DrawGraphic(sx, sy, graphic1, frame1);
1667 DrawLevelFieldCrumbledSandExt(x, y, graphic2, frame2);
1670 void DrawLevelFieldCrumbledSandNeighbours(int x, int y)
1672 int sx = SCREENX(x), sy = SCREENY(y);
1673 static int xy[4][2] =
1682 for (i = 0; i < 4; i++)
1684 int xx = x + xy[i][0];
1685 int yy = y + xy[i][1];
1686 int sxx = sx + xy[i][0];
1687 int syy = sy + xy[i][1];
1689 if (!IN_LEV_FIELD(xx, yy) ||
1690 !IN_SCR_FIELD(sxx, syy) ||
1691 !GFX_CRUMBLED(Feld[xx][yy]) ||
1695 DrawLevelField(xx, yy);
1699 static int getBorderElement(int x, int y)
1703 { EL_STEELWALL_TOPLEFT, EL_INVISIBLE_STEELWALL_TOPLEFT },
1704 { EL_STEELWALL_TOPRIGHT, EL_INVISIBLE_STEELWALL_TOPRIGHT },
1705 { EL_STEELWALL_BOTTOMLEFT, EL_INVISIBLE_STEELWALL_BOTTOMLEFT },
1706 { EL_STEELWALL_BOTTOMRIGHT, EL_INVISIBLE_STEELWALL_BOTTOMRIGHT },
1707 { EL_STEELWALL_VERTICAL, EL_INVISIBLE_STEELWALL_VERTICAL },
1708 { EL_STEELWALL_HORIZONTAL, EL_INVISIBLE_STEELWALL_HORIZONTAL },
1709 { EL_STEELWALL, EL_INVISIBLE_STEELWALL }
1711 int steel_type = (BorderElement == EL_STEELWALL ? 0 : 1);
1712 int steel_position = (x == -1 && y == -1 ? 0 :
1713 x == lev_fieldx && y == -1 ? 1 :
1714 x == -1 && y == lev_fieldy ? 2 :
1715 x == lev_fieldx && y == lev_fieldy ? 3 :
1716 x == -1 || x == lev_fieldx ? 4 :
1717 y == -1 || y == lev_fieldy ? 5 : 6);
1719 return border[steel_position][steel_type];
1722 void DrawScreenElement(int x, int y, int element)
1724 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
1725 DrawLevelFieldCrumbledSand(LEVELX(x), LEVELY(y));
1728 void DrawLevelElement(int x, int y, int element)
1730 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1731 DrawScreenElement(SCREENX(x), SCREENY(y), element);
1734 void DrawScreenField(int x, int y)
1736 int lx = LEVELX(x), ly = LEVELY(y);
1737 int element, content;
1739 if (!IN_LEV_FIELD(lx, ly))
1741 if (lx < -1 || lx > lev_fieldx || ly < -1 || ly > lev_fieldy)
1744 element = getBorderElement(lx, ly);
1746 DrawScreenElement(x, y, element);
1751 element = Feld[lx][ly];
1752 content = Store[lx][ly];
1754 if (IS_MOVING(lx, ly))
1756 int horiz_move = (MovDir[lx][ly] == MV_LEFT || MovDir[lx][ly] == MV_RIGHT);
1757 boolean cut_mode = NO_CUTTING;
1759 if (element == EL_QUICKSAND_EMPTYING ||
1760 element == EL_QUICKSAND_FAST_EMPTYING ||
1761 element == EL_MAGIC_WALL_EMPTYING ||
1762 element == EL_BD_MAGIC_WALL_EMPTYING ||
1763 element == EL_DC_MAGIC_WALL_EMPTYING ||
1764 element == EL_AMOEBA_DROPPING)
1765 cut_mode = CUT_ABOVE;
1766 else if (element == EL_QUICKSAND_FILLING ||
1767 element == EL_QUICKSAND_FAST_FILLING ||
1768 element == EL_MAGIC_WALL_FILLING ||
1769 element == EL_BD_MAGIC_WALL_FILLING ||
1770 element == EL_DC_MAGIC_WALL_FILLING)
1771 cut_mode = CUT_BELOW;
1774 if (lx == 9 && ly == 1)
1775 printf("::: %s [%d] [%d, %d] [%d]\n",
1776 EL_NAME(TILE_GFX_ELEMENT(lx, ly)),
1777 el_act2crm(TILE_GFX_ELEMENT(lx, ly), ACTION_DEFAULT),
1778 element_info[EL_QUICKSAND_EMPTYING].graphic[ACTION_DEFAULT],
1779 element_info[EL_QUICKSAND_EMPTYING].crumbled[ACTION_DEFAULT],
1780 GFX_CRUMBLED(TILE_GFX_ELEMENT(lx, ly)));
1783 if (cut_mode == CUT_ABOVE)
1785 DrawScreenElement(x, y, element);
1787 DrawScreenElementShifted(x, y, 0, 0, element, NO_CUTTING);
1790 DrawScreenElement(x, y, EL_EMPTY);
1793 DrawScreenElementShifted(x, y, MovPos[lx][ly], 0, element, NO_CUTTING);
1794 else if (cut_mode == NO_CUTTING)
1795 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], element, cut_mode);
1798 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], content, cut_mode);
1801 if (cut_mode == CUT_BELOW &&
1802 IN_LEV_FIELD(lx, ly + 1) && IN_SCR_FIELD(x, y + 1))
1803 DrawLevelElement(lx, ly + 1, element);
1807 if (content == EL_ACID)
1809 int dir = MovDir[lx][ly];
1810 int newlx = lx + (dir == MV_LEFT ? -1 : dir == MV_RIGHT ? +1 : 0);
1811 int newly = ly + (dir == MV_UP ? -1 : dir == MV_DOWN ? +1 : 0);
1813 DrawLevelElementThruMask(newlx, newly, EL_ACID);
1816 else if (IS_BLOCKED(lx, ly))
1821 boolean cut_mode = NO_CUTTING;
1822 int element_old, content_old;
1824 Blocked2Moving(lx, ly, &oldx, &oldy);
1827 horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
1828 MovDir[oldx][oldy] == MV_RIGHT);
1830 element_old = Feld[oldx][oldy];
1831 content_old = Store[oldx][oldy];
1833 if (element_old == EL_QUICKSAND_EMPTYING ||
1834 element_old == EL_QUICKSAND_FAST_EMPTYING ||
1835 element_old == EL_MAGIC_WALL_EMPTYING ||
1836 element_old == EL_BD_MAGIC_WALL_EMPTYING ||
1837 element_old == EL_DC_MAGIC_WALL_EMPTYING ||
1838 element_old == EL_AMOEBA_DROPPING)
1839 cut_mode = CUT_ABOVE;
1841 DrawScreenElement(x, y, EL_EMPTY);
1844 DrawScreenElementShifted(sx, sy, MovPos[oldx][oldy], 0, element_old,
1846 else if (cut_mode == NO_CUTTING)
1847 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], element_old,
1850 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], content_old,
1853 else if (IS_DRAWABLE(element))
1854 DrawScreenElement(x, y, element);
1856 DrawScreenElement(x, y, EL_EMPTY);
1859 void DrawLevelField(int x, int y)
1861 if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1862 DrawScreenField(SCREENX(x), SCREENY(y));
1863 else if (IS_MOVING(x, y))
1867 Moving2Blocked(x, y, &newx, &newy);
1868 if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
1869 DrawScreenField(SCREENX(newx), SCREENY(newy));
1871 else if (IS_BLOCKED(x, y))
1875 Blocked2Moving(x, y, &oldx, &oldy);
1876 if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
1877 DrawScreenField(SCREENX(oldx), SCREENY(oldy));
1881 void DrawMiniElement(int x, int y, int element)
1885 graphic = el2edimg(element);
1886 DrawMiniGraphic(x, y, graphic);
1889 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
1891 int x = sx + scroll_x, y = sy + scroll_y;
1893 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
1894 DrawMiniElement(sx, sy, EL_EMPTY);
1895 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
1896 DrawMiniElement(sx, sy, Feld[x][y]);
1898 DrawMiniGraphic(sx, sy, el2edimg(getBorderElement(x, y)));
1901 void DrawEnvelopeBackground(int envelope_nr, int startx, int starty,
1902 int x, int y, int xsize, int ysize, int font_nr)
1904 int font_width = getFontWidth(font_nr);
1905 int font_height = getFontHeight(font_nr);
1906 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1909 int dst_x = SX + startx + x * font_width;
1910 int dst_y = SY + starty + y * font_height;
1911 int width = graphic_info[graphic].width;
1912 int height = graphic_info[graphic].height;
1913 int inner_width = MAX(width - 2 * font_width, font_width);
1914 int inner_height = MAX(height - 2 * font_height, font_height);
1915 int inner_sx = (width >= 3 * font_width ? font_width : 0);
1916 int inner_sy = (height >= 3 * font_height ? font_height : 0);
1917 boolean draw_masked = graphic_info[graphic].draw_masked;
1919 getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
1921 if (src_bitmap == NULL || width < font_width || height < font_height)
1923 ClearRectangle(drawto, dst_x, dst_y, font_width, font_height);
1927 src_x += (x == 0 ? 0 : x == xsize - 1 ? width - font_width :
1928 inner_sx + (x - 1) * font_width % inner_width);
1929 src_y += (y == 0 ? 0 : y == ysize - 1 ? height - font_height :
1930 inner_sy + (y - 1) * font_height % inner_height);
1934 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1935 dst_x - src_x, dst_y - src_y);
1936 BlitBitmapMasked(src_bitmap, drawto, src_x, src_y, font_width, font_height,
1940 BlitBitmap(src_bitmap, drawto, src_x, src_y, font_width, font_height,
1944 void AnimateEnvelope(int envelope_nr, int anim_mode, int action)
1946 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1947 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
1948 int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
1949 boolean ffwd_delay = (tape.playing && tape.fast_forward);
1950 boolean no_delay = (tape.warp_forward);
1951 unsigned long anim_delay = 0;
1952 int frame_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
1953 int anim_delay_value = (no_delay ? 0 : frame_delay_value);
1954 int font_nr = FONT_ENVELOPE_1 + envelope_nr;
1955 int font_width = getFontWidth(font_nr);
1956 int font_height = getFontHeight(font_nr);
1957 int max_xsize = level.envelope[envelope_nr].xsize;
1958 int max_ysize = level.envelope[envelope_nr].ysize;
1959 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize : 0);
1960 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize : 0);
1961 int xend = max_xsize;
1962 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize : 0);
1963 int xstep = (xstart < xend ? 1 : 0);
1964 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
1967 for (x = xstart, y = ystart; x <= xend && y <= yend; x += xstep, y += ystep)
1969 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
1970 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
1971 int sx = (SXSIZE - xsize * font_width) / 2;
1972 int sy = (SYSIZE - ysize * font_height) / 2;
1975 SetDrawtoField(DRAW_BUFFERED);
1977 BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
1979 SetDrawtoField(DRAW_BACKBUFFER);
1981 for (yy = 0; yy < ysize; yy++) for (xx = 0; xx < xsize; xx++)
1982 DrawEnvelopeBackground(envelope_nr, sx,sy, xx,yy, xsize, ysize, font_nr);
1985 DrawTextBuffer(SX + sx + font_width, SY + sy + font_height,
1986 level.envelope[envelope_nr].text, font_nr, max_xsize,
1987 xsize - 2, ysize - 2, mask_mode,
1988 level.envelope[envelope_nr].autowrap,
1989 level.envelope[envelope_nr].centered, FALSE);
1991 DrawTextToTextArea(SX + sx + font_width, SY + sy + font_height,
1992 level.envelope[envelope_nr].text, font_nr, max_xsize,
1993 xsize - 2, ysize - 2, mask_mode);
1996 redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
1999 WaitUntilDelayReached(&anim_delay, anim_delay_value / 2);
2003 void ShowEnvelope(int envelope_nr)
2005 int element = EL_ENVELOPE_1 + envelope_nr;
2006 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
2007 int sound_opening = element_info[element].sound[ACTION_OPENING];
2008 int sound_closing = element_info[element].sound[ACTION_CLOSING];
2009 boolean ffwd_delay = (tape.playing && tape.fast_forward);
2010 boolean no_delay = (tape.warp_forward);
2011 int normal_delay_value = ONE_SECOND_DELAY / (ffwd_delay ? 2 : 1);
2012 int wait_delay_value = (no_delay ? 0 : normal_delay_value);
2013 int anim_mode = graphic_info[graphic].anim_mode;
2014 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
2015 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
2017 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
2019 PlayMenuSoundStereo(sound_opening, SOUND_MIDDLE);
2021 if (anim_mode == ANIM_DEFAULT)
2022 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_OPENING);
2024 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_OPENING);
2027 Delay(wait_delay_value);
2029 WaitForEventToContinue();
2031 PlayMenuSoundStereo(sound_closing, SOUND_MIDDLE);
2033 if (anim_mode != ANIM_NONE)
2034 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_CLOSING);
2036 if (anim_mode == ANIM_DEFAULT)
2037 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_CLOSING);
2039 game.envelope_active = FALSE;
2041 SetDrawtoField(DRAW_BUFFERED);
2043 redraw_mask |= REDRAW_FIELD;
2047 void DrawPreviewElement(int dst_x, int dst_y, int element, int tilesize)
2051 int graphic = el2preimg(element);
2053 getSizedGraphicSource(graphic, 0, tilesize, &src_bitmap, &src_x, &src_y);
2054 BlitBitmap(src_bitmap, drawto, src_x, src_y, tilesize, tilesize, dst_x,dst_y);
2062 SetMainBackgroundImage(IMG_BACKGROUND_PLAYING);
2063 SetDrawBackgroundMask(REDRAW_FIELD);
2065 SetDrawBackgroundMask(REDRAW_NONE);
2070 for (x = BX1; x <= BX2; x++)
2071 for (y = BY1; y <= BY2; y++)
2072 DrawScreenField(x, y);
2074 redraw_mask |= REDRAW_FIELD;
2077 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
2081 for (x = 0; x < size_x; x++)
2082 for (y = 0; y < size_y; y++)
2083 DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
2085 redraw_mask |= REDRAW_FIELD;
2088 static void DrawPreviewLevelExt(int from_x, int from_y)
2090 boolean show_level_border = (BorderElement != EL_EMPTY);
2091 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
2092 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
2093 int tile_size = preview.tile_size;
2094 int preview_width = preview.xsize * tile_size;
2095 int preview_height = preview.ysize * tile_size;
2096 int real_preview_xsize = MIN(level_xsize, preview.xsize);
2097 int real_preview_ysize = MIN(level_ysize, preview.ysize);
2098 int dst_x = SX + ALIGNED_XPOS(preview.x, preview_width, preview.align);
2099 int dst_y = SY + ALIGNED_YPOS(preview.y, preview_height, preview.valign);
2102 DrawBackground(dst_x, dst_y, preview_width, preview_height);
2104 dst_x += (preview_width - real_preview_xsize * tile_size) / 2;
2105 dst_y += (preview_height - real_preview_ysize * tile_size) / 2;
2107 for (x = 0; x < real_preview_xsize; x++)
2109 for (y = 0; y < real_preview_ysize; y++)
2111 int lx = from_x + x + (show_level_border ? -1 : 0);
2112 int ly = from_y + y + (show_level_border ? -1 : 0);
2113 int element = (IN_LEV_FIELD(lx, ly) ? level.field[lx][ly] :
2114 getBorderElement(lx, ly));
2116 DrawPreviewElement(dst_x + x * tile_size, dst_y + y * tile_size,
2117 element, tile_size);
2121 redraw_mask |= REDRAW_MICROLEVEL;
2124 #define MICROLABEL_EMPTY 0
2125 #define MICROLABEL_LEVEL_NAME 1
2126 #define MICROLABEL_LEVEL_AUTHOR_HEAD 2
2127 #define MICROLABEL_LEVEL_AUTHOR 3
2128 #define MICROLABEL_IMPORTED_FROM_HEAD 4
2129 #define MICROLABEL_IMPORTED_FROM 5
2130 #define MICROLABEL_IMPORTED_BY_HEAD 6
2131 #define MICROLABEL_IMPORTED_BY 7
2133 static int getMaxTextLength(struct TextPosInfo *pos, int font_nr)
2135 int max_text_width = SXSIZE;
2136 int font_width = getFontWidth(font_nr);
2138 if (pos->align == ALIGN_CENTER)
2139 max_text_width = (pos->x < SXSIZE / 2 ? pos->x * 2 : (SXSIZE - pos->x) * 2);
2140 else if (pos->align == ALIGN_RIGHT)
2141 max_text_width = pos->x;
2143 max_text_width = SXSIZE - pos->x;
2145 return max_text_width / font_width;
2148 static void DrawPreviewLevelLabelExt(int mode)
2150 struct TextPosInfo *pos = &menu.main.text.level_info_2;
2151 char label_text[MAX_OUTPUT_LINESIZE + 1];
2152 int max_len_label_text;
2154 int font_nr = pos->font;
2157 if (mode == MICROLABEL_LEVEL_AUTHOR_HEAD ||
2158 mode == MICROLABEL_IMPORTED_FROM_HEAD ||
2159 mode == MICROLABEL_IMPORTED_BY_HEAD)
2160 font_nr = pos->font_alt;
2162 int font_nr = FONT_TEXT_2;
2165 if (mode == MICROLABEL_LEVEL_AUTHOR_HEAD ||
2166 mode == MICROLABEL_IMPORTED_FROM_HEAD ||
2167 mode == MICROLABEL_IMPORTED_BY_HEAD)
2168 font_nr = FONT_TEXT_3;
2172 max_len_label_text = getMaxTextLength(pos, font_nr);
2174 max_len_label_text = SXSIZE / getFontWidth(font_nr);
2178 if (pos->size != -1)
2179 max_len_label_text = pos->size;
2182 for (i = 0; i < max_len_label_text; i++)
2183 label_text[i] = ' ';
2184 label_text[max_len_label_text] = '\0';
2186 if (strlen(label_text) > 0)
2189 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
2191 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
2192 int lypos = MICROLABEL2_YPOS;
2194 DrawText(lxpos, lypos, label_text, font_nr);
2199 (mode == MICROLABEL_LEVEL_NAME ? level.name :
2200 mode == MICROLABEL_LEVEL_AUTHOR_HEAD ? "created by" :
2201 mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
2202 mode == MICROLABEL_IMPORTED_FROM_HEAD ? "imported from" :
2203 mode == MICROLABEL_IMPORTED_FROM ? leveldir_current->imported_from :
2204 mode == MICROLABEL_IMPORTED_BY_HEAD ? "imported by" :
2205 mode == MICROLABEL_IMPORTED_BY ? leveldir_current->imported_by :""),
2206 max_len_label_text);
2207 label_text[max_len_label_text] = '\0';
2209 if (strlen(label_text) > 0)
2212 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
2214 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
2215 int lypos = MICROLABEL2_YPOS;
2217 DrawText(lxpos, lypos, label_text, font_nr);
2221 redraw_mask |= REDRAW_MICROLEVEL;
2224 void DrawPreviewLevel(boolean restart)
2226 static unsigned long scroll_delay = 0;
2227 static unsigned long label_delay = 0;
2228 static int from_x, from_y, scroll_direction;
2229 static int label_state, label_counter;
2230 unsigned long scroll_delay_value = preview.step_delay;
2231 boolean show_level_border = (BorderElement != EL_EMPTY);
2232 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
2233 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
2234 int last_game_status = game_status; /* save current game status */
2237 /* force PREVIEW font on preview level */
2238 game_status = GAME_MODE_PSEUDO_PREVIEW;
2246 if (preview.anim_mode == ANIM_CENTERED)
2248 if (level_xsize > preview.xsize)
2249 from_x = (level_xsize - preview.xsize) / 2;
2250 if (level_ysize > preview.ysize)
2251 from_y = (level_ysize - preview.ysize) / 2;
2254 from_x += preview.xoffset;
2255 from_y += preview.yoffset;
2257 scroll_direction = MV_RIGHT;
2261 DrawPreviewLevelExt(from_x, from_y);
2262 DrawPreviewLevelLabelExt(label_state);
2264 /* initialize delay counters */
2265 DelayReached(&scroll_delay, 0);
2266 DelayReached(&label_delay, 0);
2268 if (leveldir_current->name)
2270 struct TextPosInfo *pos = &menu.main.text.level_info_1;
2271 char label_text[MAX_OUTPUT_LINESIZE + 1];
2273 int font_nr = pos->font;
2275 int font_nr = FONT_TEXT_1;
2278 int max_len_label_text = getMaxTextLength(pos, font_nr);
2280 int max_len_label_text = SXSIZE / getFontWidth(font_nr);
2288 if (pos->size != -1)
2289 max_len_label_text = pos->size;
2292 strncpy(label_text, leveldir_current->name, max_len_label_text);
2293 label_text[max_len_label_text] = '\0';
2296 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
2298 lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
2299 lypos = SY + MICROLABEL1_YPOS;
2301 DrawText(lxpos, lypos, label_text, font_nr);
2305 game_status = last_game_status; /* restore current game status */
2310 /* scroll preview level, if needed */
2311 if (preview.anim_mode != ANIM_NONE &&
2312 (level_xsize > preview.xsize || level_ysize > preview.ysize) &&
2313 DelayReached(&scroll_delay, scroll_delay_value))
2315 switch (scroll_direction)
2320 from_x -= preview.step_offset;
2321 from_x = (from_x < 0 ? 0 : from_x);
2324 scroll_direction = MV_UP;
2328 if (from_x < level_xsize - preview.xsize)
2330 from_x += preview.step_offset;
2331 from_x = (from_x > level_xsize - preview.xsize ?
2332 level_xsize - preview.xsize : from_x);
2335 scroll_direction = MV_DOWN;
2341 from_y -= preview.step_offset;
2342 from_y = (from_y < 0 ? 0 : from_y);
2345 scroll_direction = MV_RIGHT;
2349 if (from_y < level_ysize - preview.ysize)
2351 from_y += preview.step_offset;
2352 from_y = (from_y > level_ysize - preview.ysize ?
2353 level_ysize - preview.ysize : from_y);
2356 scroll_direction = MV_LEFT;
2363 DrawPreviewLevelExt(from_x, from_y);
2366 /* !!! THIS ALL SUCKS -- SHOULD BE CLEANLY REWRITTEN !!! */
2367 /* redraw micro level label, if needed */
2368 if (!strEqual(level.name, NAMELESS_LEVEL_NAME) &&
2369 !strEqual(level.author, ANONYMOUS_NAME) &&
2370 !strEqual(level.author, leveldir_current->name) &&
2371 DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
2373 int max_label_counter = 23;
2375 if (leveldir_current->imported_from != NULL &&
2376 strlen(leveldir_current->imported_from) > 0)
2377 max_label_counter += 14;
2378 if (leveldir_current->imported_by != NULL &&
2379 strlen(leveldir_current->imported_by) > 0)
2380 max_label_counter += 14;
2382 label_counter = (label_counter + 1) % max_label_counter;
2383 label_state = (label_counter >= 0 && label_counter <= 7 ?
2384 MICROLABEL_LEVEL_NAME :
2385 label_counter >= 9 && label_counter <= 12 ?
2386 MICROLABEL_LEVEL_AUTHOR_HEAD :
2387 label_counter >= 14 && label_counter <= 21 ?
2388 MICROLABEL_LEVEL_AUTHOR :
2389 label_counter >= 23 && label_counter <= 26 ?
2390 MICROLABEL_IMPORTED_FROM_HEAD :
2391 label_counter >= 28 && label_counter <= 35 ?
2392 MICROLABEL_IMPORTED_FROM :
2393 label_counter >= 37 && label_counter <= 40 ?
2394 MICROLABEL_IMPORTED_BY_HEAD :
2395 label_counter >= 42 && label_counter <= 49 ?
2396 MICROLABEL_IMPORTED_BY : MICROLABEL_EMPTY);
2398 if (leveldir_current->imported_from == NULL &&
2399 (label_state == MICROLABEL_IMPORTED_FROM_HEAD ||
2400 label_state == MICROLABEL_IMPORTED_FROM))
2401 label_state = (label_state == MICROLABEL_IMPORTED_FROM_HEAD ?
2402 MICROLABEL_IMPORTED_BY_HEAD : MICROLABEL_IMPORTED_BY);
2404 DrawPreviewLevelLabelExt(label_state);
2407 game_status = last_game_status; /* restore current game status */
2410 inline void DrawGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
2411 int graphic, int sync_frame, int mask_mode)
2413 int frame = getGraphicAnimationFrame(graphic, sync_frame);
2415 if (mask_mode == USE_MASKING)
2416 DrawGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
2418 DrawGraphicExt(dst_bitmap, x, y, graphic, frame);
2421 inline void DrawGraphicAnimation(int x, int y, int graphic)
2423 int lx = LEVELX(x), ly = LEVELY(y);
2425 if (!IN_SCR_FIELD(x, y))
2428 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
2429 graphic, GfxFrame[lx][ly], NO_MASKING);
2430 MarkTileDirty(x, y);
2433 void DrawLevelGraphicAnimation(int x, int y, int graphic)
2435 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
2438 void DrawLevelElementAnimation(int x, int y, int element)
2440 int graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
2442 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
2445 inline void DrawLevelGraphicAnimationIfNeeded(int x, int y, int graphic)
2447 int sx = SCREENX(x), sy = SCREENY(y);
2449 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
2452 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
2455 DrawGraphicAnimation(sx, sy, graphic);
2458 if (GFX_CRUMBLED(TILE_GFX_ELEMENT(x, y)))
2459 DrawLevelFieldCrumbledSand(x, y);
2461 if (GFX_CRUMBLED(Feld[x][y]))
2462 DrawLevelFieldCrumbledSand(x, y);
2466 void DrawLevelElementAnimationIfNeeded(int x, int y, int element)
2468 int sx = SCREENX(x), sy = SCREENY(y);
2471 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
2474 graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
2476 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
2479 DrawGraphicAnimation(sx, sy, graphic);
2481 if (GFX_CRUMBLED(element))
2482 DrawLevelFieldCrumbledSand(x, y);
2485 static int getPlayerGraphic(struct PlayerInfo *player, int move_dir)
2487 if (player->use_murphy)
2489 /* this works only because currently only one player can be "murphy" ... */
2490 static int last_horizontal_dir = MV_LEFT;
2491 int graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, move_dir);
2493 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
2494 last_horizontal_dir = move_dir;
2496 if (graphic == IMG_SP_MURPHY) /* undefined => use special graphic */
2498 int direction = (player->is_snapping ? move_dir : last_horizontal_dir);
2500 graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, direction);
2506 return el_act_dir2img(player->artwork_element, player->GfxAction,move_dir);
2509 static boolean equalGraphics(int graphic1, int graphic2)
2511 struct GraphicInfo *g1 = &graphic_info[graphic1];
2512 struct GraphicInfo *g2 = &graphic_info[graphic2];
2514 return (g1->bitmap == g2->bitmap &&
2515 g1->src_x == g2->src_x &&
2516 g1->src_y == g2->src_y &&
2517 g1->anim_frames == g2->anim_frames &&
2518 g1->anim_delay == g2->anim_delay &&
2519 g1->anim_mode == g2->anim_mode);
2522 void DrawAllPlayers()
2526 for (i = 0; i < MAX_PLAYERS; i++)
2527 if (stored_player[i].active)
2528 DrawPlayer(&stored_player[i]);
2531 void DrawPlayerField(int x, int y)
2533 if (!IS_PLAYER(x, y))
2536 DrawPlayer(PLAYERINFO(x, y));
2539 #define DRAW_PLAYER_OVER_PUSHED_ELEMENT 1
2541 void DrawPlayer(struct PlayerInfo *player)
2543 int jx = player->jx;
2544 int jy = player->jy;
2545 int move_dir = player->MovDir;
2546 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? +1 : 0);
2547 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? +1 : 0);
2548 int last_jx = (player->is_moving ? jx - dx : jx);
2549 int last_jy = (player->is_moving ? jy - dy : jy);
2550 int next_jx = jx + dx;
2551 int next_jy = jy + dy;
2552 boolean player_is_moving = (player->MovPos ? TRUE : FALSE);
2553 boolean player_is_opaque = FALSE;
2554 int sx = SCREENX(jx), sy = SCREENY(jy);
2555 int sxx = 0, syy = 0;
2556 int element = Feld[jx][jy], last_element = Feld[last_jx][last_jy];
2558 int action = ACTION_DEFAULT;
2559 int last_player_graphic = getPlayerGraphic(player, move_dir);
2560 int last_player_frame = player->Frame;
2563 /* GfxElement[][] is set to the element the player is digging or collecting;
2564 remove also for off-screen player if the player is not moving anymore */
2565 if (IN_LEV_FIELD(jx, jy) && !player_is_moving)
2566 GfxElement[jx][jy] = EL_UNDEFINED;
2568 if (!player->active || !IN_SCR_FIELD(SCREENX(last_jx), SCREENY(last_jy)))
2572 if (!IN_LEV_FIELD(jx, jy))
2574 printf("DrawPlayerField(): x = %d, y = %d\n",jx,jy);
2575 printf("DrawPlayerField(): sx = %d, sy = %d\n",sx,sy);
2576 printf("DrawPlayerField(): This should never happen!\n");
2581 if (element == EL_EXPLOSION)
2584 action = (player->is_pushing ? ACTION_PUSHING :
2585 player->is_digging ? ACTION_DIGGING :
2586 player->is_collecting ? ACTION_COLLECTING :
2587 player->is_moving ? ACTION_MOVING :
2588 player->is_snapping ? ACTION_SNAPPING :
2589 player->is_dropping ? ACTION_DROPPING :
2590 player->is_waiting ? player->action_waiting : ACTION_DEFAULT);
2592 if (player->is_waiting)
2593 move_dir = player->dir_waiting;
2595 InitPlayerGfxAnimation(player, action, move_dir);
2597 /* ----------------------------------------------------------------------- */
2598 /* draw things in the field the player is leaving, if needed */
2599 /* ----------------------------------------------------------------------- */
2601 if (player->is_moving)
2603 if (Back[last_jx][last_jy] && IS_DRAWABLE(last_element))
2605 DrawLevelElement(last_jx, last_jy, Back[last_jx][last_jy]);
2607 if (last_element == EL_DYNAMITE_ACTIVE ||
2608 last_element == EL_EM_DYNAMITE_ACTIVE ||
2609 last_element == EL_SP_DISK_RED_ACTIVE)
2610 DrawDynamite(last_jx, last_jy);
2612 DrawLevelFieldThruMask(last_jx, last_jy);
2614 else if (last_element == EL_DYNAMITE_ACTIVE ||
2615 last_element == EL_EM_DYNAMITE_ACTIVE ||
2616 last_element == EL_SP_DISK_RED_ACTIVE)
2617 DrawDynamite(last_jx, last_jy);
2619 /* !!! this is not enough to prevent flickering of players which are
2620 moving next to each others without a free tile between them -- this
2621 can only be solved by drawing all players layer by layer (first the
2622 background, then the foreground etc.) !!! => TODO */
2623 else if (!IS_PLAYER(last_jx, last_jy))
2624 DrawLevelField(last_jx, last_jy);
2627 DrawLevelField(last_jx, last_jy);
2630 if (player->is_pushing && IN_SCR_FIELD(SCREENX(next_jx), SCREENY(next_jy)))
2631 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
2634 if (!IN_SCR_FIELD(sx, sy))
2637 /* ----------------------------------------------------------------------- */
2638 /* draw things behind the player, if needed */
2639 /* ----------------------------------------------------------------------- */
2642 DrawLevelElement(jx, jy, Back[jx][jy]);
2643 else if (IS_ACTIVE_BOMB(element))
2644 DrawLevelElement(jx, jy, EL_EMPTY);
2647 if (player_is_moving && GfxElement[jx][jy] != EL_UNDEFINED)
2649 int old_element = GfxElement[jx][jy];
2650 int old_graphic = el_act_dir2img(old_element, action, move_dir);
2651 int frame = getGraphicAnimationFrame(old_graphic, player->StepFrame);
2653 if (GFX_CRUMBLED(old_element))
2654 DrawLevelFieldCrumbledSandDigging(jx, jy, move_dir, player->StepFrame);
2656 DrawGraphic(sx, sy, old_graphic, frame);
2658 if (graphic_info[old_graphic].anim_mode & ANIM_OPAQUE_PLAYER)
2659 player_is_opaque = TRUE;
2663 GfxElement[jx][jy] = EL_UNDEFINED;
2665 /* make sure that pushed elements are drawn with correct frame rate */
2667 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
2669 if (player->is_pushing && player->is_moving && !IS_ANIM_MODE_CE(graphic))
2670 GfxFrame[jx][jy] = player->StepFrame;
2672 if (player->is_pushing && player->is_moving)
2673 GfxFrame[jx][jy] = player->StepFrame;
2676 DrawLevelField(jx, jy);
2680 #if !DRAW_PLAYER_OVER_PUSHED_ELEMENT
2681 /* ----------------------------------------------------------------------- */
2682 /* draw player himself */
2683 /* ----------------------------------------------------------------------- */
2685 graphic = getPlayerGraphic(player, move_dir);
2687 /* in the case of changed player action or direction, prevent the current
2688 animation frame from being restarted for identical animations */
2689 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
2690 player->Frame = last_player_frame;
2692 frame = getGraphicAnimationFrame(graphic, player->Frame);
2696 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
2697 sxx = player->GfxPos;
2699 syy = player->GfxPos;
2702 if (!setup.soft_scrolling && ScreenMovPos)
2705 if (player_is_opaque)
2706 DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
2708 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
2710 if (SHIELD_ON(player))
2712 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
2713 IMG_SHIELD_NORMAL_ACTIVE);
2714 int frame = getGraphicAnimationFrame(graphic, -1);
2716 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
2720 #if DRAW_PLAYER_OVER_PUSHED_ELEMENT
2723 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
2724 sxx = player->GfxPos;
2726 syy = player->GfxPos;
2730 /* ----------------------------------------------------------------------- */
2731 /* draw things the player is pushing, if needed */
2732 /* ----------------------------------------------------------------------- */
2735 printf("::: %d, %d [%d, %d] [%d]\n",
2736 player->is_pushing, player_is_moving, player->GfxAction,
2737 player->is_moving, player_is_moving);
2741 if (player->is_pushing && player->is_moving)
2743 int px = SCREENX(jx), py = SCREENY(jy);
2744 int pxx = (TILEX - ABS(sxx)) * dx;
2745 int pyy = (TILEY - ABS(syy)) * dy;
2746 int gfx_frame = GfxFrame[jx][jy];
2752 if (!IS_MOVING(jx, jy)) /* push movement already finished */
2754 element = Feld[next_jx][next_jy];
2755 gfx_frame = GfxFrame[next_jx][next_jy];
2758 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
2761 sync_frame = (IS_ANIM_MODE_CE(graphic) ? gfx_frame : player->StepFrame);
2762 frame = getGraphicAnimationFrame(graphic, sync_frame);
2764 frame = getGraphicAnimationFrame(graphic, player->StepFrame);
2767 /* draw background element under pushed element (like the Sokoban field) */
2769 if (game.use_masked_pushing && IS_MOVING(jx, jy))
2771 /* this allows transparent pushing animation over non-black background */
2774 DrawLevelElement(jx, jy, Back[jx][jy]);
2776 DrawLevelElement(jx, jy, EL_EMPTY);
2778 if (Back[next_jx][next_jy])
2779 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
2781 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
2783 else if (Back[next_jx][next_jy])
2784 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
2786 if (Back[next_jx][next_jy])
2787 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
2791 printf("::: %d, %d, %d, %d [%d] [%d, %d, %d] [%d] [%d, %d] [%d, %d]\n",
2792 jx, px, player->GfxPos, player->StepFrame,
2797 GfxFrame[jx][jy], GfxFrame[next_jx][next_jy]);
2801 /* do not draw (EM style) pushing animation when pushing is finished */
2802 /* (two-tile animations usually do not contain start and end frame) */
2803 if (graphic_info[graphic].double_movement && !IS_MOVING(jx, jy))
2804 DrawLevelElement(next_jx, next_jy, Feld[next_jx][next_jy]);
2806 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
2808 /* masked drawing is needed for EMC style (double) movement graphics */
2809 /* !!! (ONLY WHEN DRAWING PUSHED ELEMENT OVER THE PLAYER) !!! */
2810 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
2815 #if DRAW_PLAYER_OVER_PUSHED_ELEMENT
2816 /* ----------------------------------------------------------------------- */
2817 /* draw player himself */
2818 /* ----------------------------------------------------------------------- */
2820 graphic = getPlayerGraphic(player, move_dir);
2822 /* in the case of changed player action or direction, prevent the current
2823 animation frame from being restarted for identical animations */
2824 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
2825 player->Frame = last_player_frame;
2827 frame = getGraphicAnimationFrame(graphic, player->Frame);
2831 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
2832 sxx = player->GfxPos;
2834 syy = player->GfxPos;
2837 if (!setup.soft_scrolling && ScreenMovPos)
2840 if (player_is_opaque)
2841 DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
2843 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
2845 if (SHIELD_ON(player))
2847 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
2848 IMG_SHIELD_NORMAL_ACTIVE);
2849 int frame = getGraphicAnimationFrame(graphic, -1);
2851 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
2855 /* ----------------------------------------------------------------------- */
2856 /* draw things in front of player (active dynamite or dynabombs) */
2857 /* ----------------------------------------------------------------------- */
2859 if (IS_ACTIVE_BOMB(element))
2861 graphic = el2img(element);
2862 frame = getGraphicAnimationFrame(graphic, GfxFrame[jx][jy]);
2864 if (game.emulation == EMU_SUPAPLEX)
2865 DrawGraphic(sx, sy, IMG_SP_DISK_RED, frame);
2867 DrawGraphicThruMask(sx, sy, graphic, frame);
2870 if (player_is_moving && last_element == EL_EXPLOSION)
2872 int element = (GfxElement[last_jx][last_jy] != EL_UNDEFINED ?
2873 GfxElement[last_jx][last_jy] : EL_EMPTY);
2874 int graphic = el_act2img(element, ACTION_EXPLODING);
2875 int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
2876 int phase = ExplodePhase[last_jx][last_jy] - 1;
2877 int frame = getGraphicAnimationFrame(graphic, phase - delay);
2880 DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy), graphic, frame);
2883 /* ----------------------------------------------------------------------- */
2884 /* draw elements the player is just walking/passing through/under */
2885 /* ----------------------------------------------------------------------- */
2887 if (player_is_moving)
2889 /* handle the field the player is leaving ... */
2890 if (IS_ACCESSIBLE_INSIDE(last_element))
2891 DrawLevelField(last_jx, last_jy);
2892 else if (IS_ACCESSIBLE_UNDER(last_element))
2893 DrawLevelFieldThruMask(last_jx, last_jy);
2896 /* do not redraw accessible elements if the player is just pushing them */
2897 if (!player_is_moving || !player->is_pushing)
2899 /* ... and the field the player is entering */
2900 if (IS_ACCESSIBLE_INSIDE(element))
2901 DrawLevelField(jx, jy);
2902 else if (IS_ACCESSIBLE_UNDER(element))
2903 DrawLevelFieldThruMask(jx, jy);
2906 MarkTileDirty(sx, sy);
2909 /* ------------------------------------------------------------------------- */
2911 void WaitForEventToContinue()
2913 boolean still_wait = TRUE;
2915 /* simulate releasing mouse button over last gadget, if still pressed */
2917 HandleGadgets(-1, -1, 0);
2919 button_status = MB_RELEASED;
2935 case EVENT_BUTTONPRESS:
2936 case EVENT_KEYPRESS:
2940 case EVENT_KEYRELEASE:
2941 ClearPlayerAction();
2945 HandleOtherEvents(&event);
2949 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
2956 /* don't eat all CPU time */
2961 #define MAX_REQUEST_LINES 13
2962 #define MAX_REQUEST_LINE_FONT1_LEN 7
2963 #define MAX_REQUEST_LINE_FONT2_LEN 10
2965 boolean Request(char *text, unsigned int req_state)
2967 int mx, my, ty, result = -1;
2968 unsigned int old_door_state;
2969 int last_game_status = game_status; /* save current game status */
2970 int max_request_line_len = MAX_REQUEST_LINE_FONT1_LEN;
2971 int font_nr = FONT_TEXT_2;
2972 int max_word_len = 0;
2975 for (text_ptr = text; *text_ptr; text_ptr++)
2977 max_word_len = (*text_ptr != ' ' ? max_word_len + 1 : 0);
2979 if (max_word_len > MAX_REQUEST_LINE_FONT1_LEN)
2981 max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
2983 font_nr = FONT_TEXT_1;
2985 font_nr = FONT_LEVEL_NUMBER;
2992 if (game_status == GAME_MODE_PLAYING)
2994 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
2995 BlitScreenToBitmap_EM(backbuffer);
2996 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
2997 BlitScreenToBitmap_SP(backbuffer);
3000 /* disable deactivated drawing when quick-loading level tape recording */
3001 if (tape.playing && tape.deactivate_display)
3002 TapeDeactivateDisplayOff(TRUE);
3004 SetMouseCursor(CURSOR_DEFAULT);
3006 #if defined(NETWORK_AVALIABLE)
3007 /* pause network game while waiting for request to answer */
3008 if (options.network &&
3009 game_status == GAME_MODE_PLAYING &&
3010 req_state & REQUEST_WAIT_FOR_INPUT)
3011 SendToServer_PausePlaying();
3014 old_door_state = GetDoorState();
3016 /* simulate releasing mouse button over last gadget, if still pressed */
3018 HandleGadgets(-1, -1, 0);
3022 if (old_door_state & DOOR_OPEN_1)
3024 CloseDoor(DOOR_CLOSE_1);
3026 /* save old door content */
3027 BlitBitmap(bitmap_db_door, bitmap_db_door,
3028 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
3029 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
3033 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
3036 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
3038 /* clear door drawing field */
3039 DrawBackground(DX, DY, DXSIZE, DYSIZE);
3041 /* force DOOR font inside door area */
3042 game_status = GAME_MODE_PSEUDO_DOOR;
3044 /* write text for request */
3045 for (ty = 0; ty < MAX_REQUEST_LINES; ty++)
3047 char text_line[max_request_line_len + 1];
3053 for (tl = 0, tx = 0; tx < max_request_line_len; tl++, tx++)
3056 if (!tc || tc == ' ')
3067 strncpy(text_line, text, tl);
3070 DrawText(DX + (DXSIZE - tl * getFontWidth(font_nr)) / 2,
3071 DY + 8 + ty * (getFontHeight(font_nr) + 2),
3072 text_line, font_nr);
3074 text += tl + (tc == ' ' ? 1 : 0);
3077 game_status = last_game_status; /* restore current game status */
3079 if (req_state & REQ_ASK)
3081 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
3082 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
3084 else if (req_state & REQ_CONFIRM)
3086 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
3088 else if (req_state & REQ_PLAYER)
3090 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
3091 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
3092 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
3093 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
3096 /* copy request gadgets to door backbuffer */
3097 BlitBitmap(drawto, bitmap_db_door,
3098 DX, DY, DXSIZE, DYSIZE,
3099 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
3101 OpenDoor(DOOR_OPEN_1);
3103 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
3105 if (game_status == GAME_MODE_PLAYING)
3107 SetPanelBackground();
3108 SetDrawBackgroundMask(REDRAW_DOOR_1);
3112 SetDrawBackgroundMask(REDRAW_FIELD);
3118 if (game_status != GAME_MODE_MAIN)
3121 button_status = MB_RELEASED;
3123 request_gadget_id = -1;
3125 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
3137 case EVENT_BUTTONPRESS:
3138 case EVENT_BUTTONRELEASE:
3139 case EVENT_MOTIONNOTIFY:
3141 if (event.type == EVENT_MOTIONNOTIFY)
3143 if (!PointerInWindow(window))
3144 continue; /* window and pointer are on different screens */
3149 motion_status = TRUE;
3150 mx = ((MotionEvent *) &event)->x;
3151 my = ((MotionEvent *) &event)->y;
3155 motion_status = FALSE;
3156 mx = ((ButtonEvent *) &event)->x;
3157 my = ((ButtonEvent *) &event)->y;
3158 if (event.type == EVENT_BUTTONPRESS)
3159 button_status = ((ButtonEvent *) &event)->button;
3161 button_status = MB_RELEASED;
3164 /* this sets 'request_gadget_id' */
3165 HandleGadgets(mx, my, button_status);
3167 switch (request_gadget_id)
3169 case TOOL_CTRL_ID_YES:
3172 case TOOL_CTRL_ID_NO:
3175 case TOOL_CTRL_ID_CONFIRM:
3176 result = TRUE | FALSE;
3179 case TOOL_CTRL_ID_PLAYER_1:
3182 case TOOL_CTRL_ID_PLAYER_2:
3185 case TOOL_CTRL_ID_PLAYER_3:
3188 case TOOL_CTRL_ID_PLAYER_4:
3199 case EVENT_KEYPRESS:
3200 switch (GetEventKey((KeyEvent *)&event, TRUE))
3203 if (req_state & REQ_CONFIRM)
3219 if (req_state & REQ_PLAYER)
3223 case EVENT_KEYRELEASE:
3224 ClearPlayerAction();
3228 HandleOtherEvents(&event);
3232 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
3234 int joy = AnyJoystick();
3236 if (joy & JOY_BUTTON_1)
3238 else if (joy & JOY_BUTTON_2)
3244 if (game_status == GAME_MODE_PLAYING && local_player->LevelSolved_GameEnd)
3246 HandleGameActions();
3252 if (!PendingEvent()) /* delay only if no pending events */
3263 if (!PendingEvent()) /* delay only if no pending events */
3266 /* don't eat all CPU time */
3273 if (game_status != GAME_MODE_MAIN)
3278 if (!(req_state & REQ_STAY_OPEN))
3280 CloseDoor(DOOR_CLOSE_1);
3282 if (((old_door_state & DOOR_OPEN_1) && !(req_state & REQ_STAY_CLOSED)) ||
3283 (req_state & REQ_REOPEN))
3284 OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
3289 if (game_status == GAME_MODE_PLAYING)
3291 SetPanelBackground();
3292 SetDrawBackgroundMask(REDRAW_DOOR_1);
3296 SetDrawBackgroundMask(REDRAW_FIELD);
3299 #if defined(NETWORK_AVALIABLE)
3300 /* continue network game after request */
3301 if (options.network &&
3302 game_status == GAME_MODE_PLAYING &&
3303 req_state & REQUEST_WAIT_FOR_INPUT)
3304 SendToServer_ContinuePlaying();
3307 /* restore deactivated drawing when quick-loading level tape recording */
3308 if (tape.playing && tape.deactivate_display)
3309 TapeDeactivateDisplayOn();
3314 unsigned int OpenDoor(unsigned int door_state)
3316 if (door_state & DOOR_COPY_BACK)
3318 if (door_state & DOOR_OPEN_1)
3319 BlitBitmap(bitmap_db_door, bitmap_db_door,
3320 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
3321 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
3323 if (door_state & DOOR_OPEN_2)
3324 BlitBitmap(bitmap_db_door, bitmap_db_door,
3325 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY2, VXSIZE, VYSIZE,
3326 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
3328 door_state &= ~DOOR_COPY_BACK;
3331 return MoveDoor(door_state);
3334 unsigned int CloseDoor(unsigned int door_state)
3336 unsigned int old_door_state = GetDoorState();
3338 if (!(door_state & DOOR_NO_COPY_BACK))
3340 if (old_door_state & DOOR_OPEN_1)
3341 BlitBitmap(backbuffer, bitmap_db_door,
3342 DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
3344 if (old_door_state & DOOR_OPEN_2)
3345 BlitBitmap(backbuffer, bitmap_db_door,
3346 VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
3348 door_state &= ~DOOR_NO_COPY_BACK;
3351 return MoveDoor(door_state);
3354 unsigned int GetDoorState()
3356 return MoveDoor(DOOR_GET_STATE);
3359 unsigned int SetDoorState(unsigned int door_state)
3361 return MoveDoor(door_state | DOOR_SET_STATE);
3364 unsigned int MoveDoor(unsigned int door_state)
3366 static int door1 = DOOR_OPEN_1;
3367 static int door2 = DOOR_CLOSE_2;
3368 unsigned long door_delay = 0;
3369 unsigned long door_delay_value;
3372 if (door_1.width < 0 || door_1.width > DXSIZE)
3373 door_1.width = DXSIZE;
3374 if (door_1.height < 0 || door_1.height > DYSIZE)
3375 door_1.height = DYSIZE;
3376 if (door_2.width < 0 || door_2.width > VXSIZE)
3377 door_2.width = VXSIZE;
3378 if (door_2.height < 0 || door_2.height > VYSIZE)
3379 door_2.height = VYSIZE;
3381 if (door_state == DOOR_GET_STATE)
3382 return (door1 | door2);
3384 if (door_state & DOOR_SET_STATE)
3386 if (door_state & DOOR_ACTION_1)
3387 door1 = door_state & DOOR_ACTION_1;
3388 if (door_state & DOOR_ACTION_2)
3389 door2 = door_state & DOOR_ACTION_2;
3391 return (door1 | door2);
3394 if (!(door_state & DOOR_FORCE_REDRAW))
3396 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
3397 door_state &= ~DOOR_OPEN_1;
3398 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
3399 door_state &= ~DOOR_CLOSE_1;
3400 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
3401 door_state &= ~DOOR_OPEN_2;
3402 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
3403 door_state &= ~DOOR_CLOSE_2;
3406 door_delay_value = (door_state & DOOR_ACTION_1 ? door_1.step_delay :
3409 if (setup.quick_doors)
3411 stepsize = 20; /* must be chosen to always draw last frame */
3412 door_delay_value = 0;
3415 if (global.autoplay_leveldir)
3417 door_state |= DOOR_NO_DELAY;
3418 door_state &= ~DOOR_CLOSE_ALL;
3422 if (game_status == GAME_MODE_EDITOR)
3423 door_state |= DOOR_NO_DELAY;
3426 if (door_state & DOOR_ACTION)
3428 boolean handle_door_1 = (door_state & DOOR_ACTION_1);
3429 boolean handle_door_2 = (door_state & DOOR_ACTION_2);
3430 boolean door_1_done = (!handle_door_1);
3431 boolean door_2_done = (!handle_door_2);
3432 boolean door_1_vertical = (door_1.anim_mode & ANIM_VERTICAL);
3433 boolean door_2_vertical = (door_2.anim_mode & ANIM_VERTICAL);
3434 int door_size_1 = (door_1_vertical ? door_1.height : door_1.width);
3435 int door_size_2 = (door_2_vertical ? door_2.height : door_2.width);
3436 int max_door_size_1 = (door_1_vertical ? DYSIZE : DXSIZE);
3437 int max_door_size_2 = (door_2_vertical ? VYSIZE : VXSIZE);
3438 int door_size = (handle_door_1 ? door_size_1 : door_size_2);
3439 int max_door_size = (handle_door_1 ? max_door_size_1 : max_door_size_2);
3440 int door_skip = max_door_size - door_size;
3441 int end = door_size;
3442 int start = ((door_state & DOOR_NO_DELAY) ? end : 0);
3445 if (!(door_state & DOOR_NO_DELAY) && !setup.quick_doors)
3447 /* opening door sound has priority over simultaneously closing door */
3448 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
3449 PlayMenuSoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
3450 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
3451 PlayMenuSoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
3454 for (k = start; k <= end && !(door_1_done && door_2_done); k += stepsize)
3457 Bitmap *bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
3458 GC gc = bitmap->stored_clip_gc;
3460 if (door_state & DOOR_ACTION_1)
3462 int a = MIN(x * door_1.step_offset, end);
3463 int p = (door_state & DOOR_OPEN_1 ? end - a : a);
3464 int i = p + door_skip;
3466 if (door_1.anim_mode & ANIM_STATIC_PANEL)
3468 BlitBitmap(bitmap_db_door, drawto,
3469 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1,
3470 DXSIZE, DYSIZE, DX, DY);
3474 BlitBitmap(bitmap_db_door, drawto,
3475 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + p / 2,
3476 DXSIZE, DYSIZE - p / 2, DX, DY);
3478 ClearRectangle(drawto, DX, DY + DYSIZE - p / 2, DXSIZE, p / 2);
3481 if (door_1.anim_mode & ANIM_HORIZONTAL && x <= DXSIZE)
3483 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
3484 int dst1_x = DX + DXSIZE - i, dst1_y = DY;
3485 int src2_x = DXSIZE - i, src2_y = DOOR_GFX_PAGEY1;
3486 int dst2_x = DX, dst2_y = DY;
3487 int width = i, height = DYSIZE;
3489 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
3490 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
3493 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
3494 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
3497 else if (door_1.anim_mode & ANIM_VERTICAL && x <= DYSIZE)
3499 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
3500 int dst1_x = DX, dst1_y = DY + DYSIZE - i;
3501 int src2_x = 0, src2_y = DOOR_GFX_PAGEY1 + DYSIZE - i;
3502 int dst2_x = DX, dst2_y = DY;
3503 int width = DXSIZE, height = i;
3505 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
3506 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
3509 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
3510 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
3513 else if (x <= DXSIZE) /* ANIM_DEFAULT */
3515 int j = (door_1.anim_mode == ANIM_DEFAULT ? (DXSIZE - i) / 3 : 0);
3517 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
3518 BlitBitmapMasked(bitmap, drawto,
3519 DXSIZE, DOOR_GFX_PAGEY1, i, 77,
3520 DX + DXSIZE - i, DY + j);
3521 BlitBitmapMasked(bitmap, drawto,
3522 DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63,
3523 DX + DXSIZE - i, DY + 140 + j);
3524 SetClipOrigin(bitmap, gc, DX - DXSIZE + i,
3525 DY - (DOOR_GFX_PAGEY1 + j));
3526 BlitBitmapMasked(bitmap, drawto,
3527 DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j,
3529 BlitBitmapMasked(bitmap, drawto,
3530 DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63,
3533 BlitBitmapMasked(bitmap, drawto,
3534 DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
3536 BlitBitmapMasked(bitmap, drawto,
3537 DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
3539 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
3540 BlitBitmapMasked(bitmap, drawto,
3541 DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
3542 DX + DXSIZE - i, DY + 77 + j);
3543 BlitBitmapMasked(bitmap, drawto,
3544 DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
3545 DX + DXSIZE - i, DY + 203 + j);
3548 redraw_mask |= REDRAW_DOOR_1;
3549 door_1_done = (a == end);
3552 if (door_state & DOOR_ACTION_2)
3554 int a = MIN(x * door_2.step_offset, door_size);
3555 int p = (door_state & DOOR_OPEN_2 ? door_size - a : a);
3556 int i = p + door_skip;
3558 if (door_2.anim_mode & ANIM_STATIC_PANEL)
3560 BlitBitmap(bitmap_db_door, drawto,
3561 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2,
3562 VXSIZE, VYSIZE, VX, VY);
3564 else if (x <= VYSIZE)
3566 BlitBitmap(bitmap_db_door, drawto,
3567 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + p / 2,
3568 VXSIZE, VYSIZE - p / 2, VX, VY);
3570 ClearRectangle(drawto, VX, VY + VYSIZE - p / 2, VXSIZE, p / 2);
3573 if (door_2.anim_mode & ANIM_HORIZONTAL && x <= VXSIZE)
3575 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
3576 int dst1_x = VX + VXSIZE - i, dst1_y = VY;
3577 int src2_x = VXSIZE - i, src2_y = DOOR_GFX_PAGEY2;
3578 int dst2_x = VX, dst2_y = VY;
3579 int width = i, height = VYSIZE;
3581 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
3582 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
3585 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
3586 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
3589 else if (door_2.anim_mode & ANIM_VERTICAL && x <= VYSIZE)
3591 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
3592 int dst1_x = VX, dst1_y = VY + VYSIZE - i;
3593 int src2_x = 0, src2_y = DOOR_GFX_PAGEY2 + VYSIZE - i;
3594 int dst2_x = VX, dst2_y = VY;
3595 int width = VXSIZE, height = i;
3597 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
3598 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
3601 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
3602 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
3605 else if (x <= VXSIZE) /* ANIM_DEFAULT */
3607 int j = (door_2.anim_mode == ANIM_DEFAULT ? (VXSIZE - i) / 3 : 0);
3609 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
3610 BlitBitmapMasked(bitmap, drawto,
3611 VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2,
3612 VX + VXSIZE - i, VY + j);
3613 SetClipOrigin(bitmap, gc,
3614 VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
3615 BlitBitmapMasked(bitmap, drawto,
3616 VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j,
3619 BlitBitmapMasked(bitmap, drawto,
3620 VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2,
3621 i, VYSIZE / 2, VX, VY + VYSIZE / 2 - j);
3622 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
3623 BlitBitmapMasked(bitmap, drawto,
3624 VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2,
3626 VX + VXSIZE - i, VY + VYSIZE / 2 + j);
3629 redraw_mask |= REDRAW_DOOR_2;
3630 door_2_done = (a == VXSIZE);
3633 if (!(door_state & DOOR_NO_DELAY))
3637 if (game_status == GAME_MODE_MAIN)
3640 WaitUntilDelayReached(&door_delay, door_delay_value);
3645 if (door_state & DOOR_ACTION_1)
3646 door1 = door_state & DOOR_ACTION_1;
3647 if (door_state & DOOR_ACTION_2)
3648 door2 = door_state & DOOR_ACTION_2;
3650 return (door1 | door2);
3653 void DrawSpecialEditorDoor()
3655 /* draw bigger toolbox window */
3656 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
3657 DOOR_GFX_PAGEX7, 0, EXSIZE + 8, 8,
3659 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
3660 EX - 6, VY - 4, EXSIZE + 12, EYSIZE - VYSIZE + 4,
3663 redraw_mask |= REDRAW_ALL;
3666 void UndrawSpecialEditorDoor()
3668 /* draw normal tape recorder window */
3669 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
3670 EX - 6, EY - 12, EXSIZE + 12, EYSIZE - VYSIZE + 12,
3673 redraw_mask |= REDRAW_ALL;
3677 /* ---------- new tool button stuff ---------------------------------------- */
3679 /* graphic position values for tool buttons */
3680 #define TOOL_BUTTON_YES_XPOS 2
3681 #define TOOL_BUTTON_YES_YPOS 250
3682 #define TOOL_BUTTON_YES_GFX_YPOS 0
3683 #define TOOL_BUTTON_YES_XSIZE 46
3684 #define TOOL_BUTTON_YES_YSIZE 28
3685 #define TOOL_BUTTON_NO_XPOS 52
3686 #define TOOL_BUTTON_NO_YPOS TOOL_BUTTON_YES_YPOS
3687 #define TOOL_BUTTON_NO_GFX_YPOS TOOL_BUTTON_YES_GFX_YPOS
3688 #define TOOL_BUTTON_NO_XSIZE TOOL_BUTTON_YES_XSIZE
3689 #define TOOL_BUTTON_NO_YSIZE TOOL_BUTTON_YES_YSIZE
3690 #define TOOL_BUTTON_CONFIRM_XPOS TOOL_BUTTON_YES_XPOS
3691 #define TOOL_BUTTON_CONFIRM_YPOS TOOL_BUTTON_YES_YPOS
3692 #define TOOL_BUTTON_CONFIRM_GFX_YPOS 30
3693 #define TOOL_BUTTON_CONFIRM_XSIZE 96
3694 #define TOOL_BUTTON_CONFIRM_YSIZE TOOL_BUTTON_YES_YSIZE
3695 #define TOOL_BUTTON_PLAYER_XSIZE 30
3696 #define TOOL_BUTTON_PLAYER_YSIZE 30
3697 #define TOOL_BUTTON_PLAYER_GFX_XPOS 5
3698 #define TOOL_BUTTON_PLAYER_GFX_YPOS 185
3699 #define TOOL_BUTTON_PLAYER_XPOS (5 + TOOL_BUTTON_PLAYER_XSIZE / 2)
3700 #define TOOL_BUTTON_PLAYER_YPOS (215 - TOOL_BUTTON_PLAYER_YSIZE / 2)
3701 #define TOOL_BUTTON_PLAYER1_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3702 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
3703 #define TOOL_BUTTON_PLAYER2_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3704 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
3705 #define TOOL_BUTTON_PLAYER3_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3706 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
3707 #define TOOL_BUTTON_PLAYER4_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3708 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
3709 #define TOOL_BUTTON_PLAYER1_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3710 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
3711 #define TOOL_BUTTON_PLAYER2_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3712 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
3713 #define TOOL_BUTTON_PLAYER3_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3714 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
3715 #define TOOL_BUTTON_PLAYER4_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3716 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
3725 } toolbutton_info[NUM_TOOL_BUTTONS] =
3728 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_GFX_YPOS,
3729 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_YPOS,
3730 TOOL_BUTTON_YES_XSIZE, TOOL_BUTTON_YES_YSIZE,
3735 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_GFX_YPOS,
3736 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_YPOS,
3737 TOOL_BUTTON_NO_XSIZE, TOOL_BUTTON_NO_YSIZE,
3742 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_GFX_YPOS,
3743 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_YPOS,
3744 TOOL_BUTTON_CONFIRM_XSIZE, TOOL_BUTTON_CONFIRM_YSIZE,
3745 TOOL_CTRL_ID_CONFIRM,
3749 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3750 TOOL_BUTTON_PLAYER1_XPOS, TOOL_BUTTON_PLAYER1_YPOS,
3751 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3752 TOOL_CTRL_ID_PLAYER_1,
3756 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3757 TOOL_BUTTON_PLAYER2_XPOS, TOOL_BUTTON_PLAYER2_YPOS,
3758 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3759 TOOL_CTRL_ID_PLAYER_2,
3763 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3764 TOOL_BUTTON_PLAYER3_XPOS, TOOL_BUTTON_PLAYER3_YPOS,
3765 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3766 TOOL_CTRL_ID_PLAYER_3,
3770 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3771 TOOL_BUTTON_PLAYER4_XPOS, TOOL_BUTTON_PLAYER4_YPOS,
3772 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3773 TOOL_CTRL_ID_PLAYER_4,
3778 void CreateToolButtons()
3782 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3784 Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
3785 Bitmap *deco_bitmap = None;
3786 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
3787 struct GadgetInfo *gi;
3788 unsigned long event_mask;
3789 int gd_xoffset, gd_yoffset;
3790 int gd_x1, gd_x2, gd_y;
3793 event_mask = GD_EVENT_RELEASED;
3795 gd_xoffset = toolbutton_info[i].xpos;
3796 gd_yoffset = toolbutton_info[i].ypos;
3797 gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
3798 gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
3799 gd_y = DOOR_GFX_PAGEY1 + gd_yoffset;
3801 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
3803 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
3805 getMiniGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr),
3806 &deco_bitmap, &deco_x, &deco_y);
3807 deco_xpos = (toolbutton_info[i].width - MINI_TILEX) / 2;
3808 deco_ypos = (toolbutton_info[i].height - MINI_TILEY) / 2;
3811 gi = CreateGadget(GDI_CUSTOM_ID, id,
3812 GDI_INFO_TEXT, toolbutton_info[i].infotext,
3813 GDI_X, DX + toolbutton_info[i].x,
3814 GDI_Y, DY + toolbutton_info[i].y,
3815 GDI_WIDTH, toolbutton_info[i].width,
3816 GDI_HEIGHT, toolbutton_info[i].height,
3817 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
3818 GDI_STATE, GD_BUTTON_UNPRESSED,
3819 GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
3820 GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
3821 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
3822 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
3823 GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
3824 GDI_DECORATION_SHIFTING, 1, 1,
3825 GDI_DIRECT_DRAW, FALSE,
3826 GDI_EVENT_MASK, event_mask,
3827 GDI_CALLBACK_ACTION, HandleToolButtons,
3831 Error(ERR_EXIT, "cannot create gadget");
3833 tool_gadget[id] = gi;
3837 void FreeToolButtons()
3841 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3842 FreeGadget(tool_gadget[i]);
3845 static void UnmapToolButtons()
3849 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3850 UnmapGadget(tool_gadget[i]);
3853 static void HandleToolButtons(struct GadgetInfo *gi)
3855 request_gadget_id = gi->custom_id;
3858 static struct Mapping_EM_to_RND_object
3861 boolean is_rnd_to_em_mapping; /* unique mapping EM <-> RND */
3862 boolean is_backside; /* backside of moving element */
3868 em_object_mapping_list[] =
3871 Xblank, TRUE, FALSE,
3875 Yacid_splash_eB, FALSE, FALSE,
3876 EL_ACID_SPLASH_RIGHT, -1, -1
3879 Yacid_splash_wB, FALSE, FALSE,
3880 EL_ACID_SPLASH_LEFT, -1, -1
3883 #ifdef EM_ENGINE_BAD_ROLL
3885 Xstone_force_e, FALSE, FALSE,
3886 EL_ROCK, -1, MV_BIT_RIGHT
3889 Xstone_force_w, FALSE, FALSE,
3890 EL_ROCK, -1, MV_BIT_LEFT
3893 Xnut_force_e, FALSE, FALSE,
3894 EL_NUT, -1, MV_BIT_RIGHT
3897 Xnut_force_w, FALSE, FALSE,
3898 EL_NUT, -1, MV_BIT_LEFT
3901 Xspring_force_e, FALSE, FALSE,
3902 EL_SPRING, -1, MV_BIT_RIGHT
3905 Xspring_force_w, FALSE, FALSE,
3906 EL_SPRING, -1, MV_BIT_LEFT
3909 Xemerald_force_e, FALSE, FALSE,
3910 EL_EMERALD, -1, MV_BIT_RIGHT
3913 Xemerald_force_w, FALSE, FALSE,
3914 EL_EMERALD, -1, MV_BIT_LEFT
3917 Xdiamond_force_e, FALSE, FALSE,
3918 EL_DIAMOND, -1, MV_BIT_RIGHT
3921 Xdiamond_force_w, FALSE, FALSE,
3922 EL_DIAMOND, -1, MV_BIT_LEFT
3925 Xbomb_force_e, FALSE, FALSE,
3926 EL_BOMB, -1, MV_BIT_RIGHT
3929 Xbomb_force_w, FALSE, FALSE,
3930 EL_BOMB, -1, MV_BIT_LEFT
3932 #endif /* EM_ENGINE_BAD_ROLL */
3935 Xstone, TRUE, FALSE,
3939 Xstone_pause, FALSE, FALSE,
3943 Xstone_fall, FALSE, FALSE,
3947 Ystone_s, FALSE, FALSE,
3948 EL_ROCK, ACTION_FALLING, -1
3951 Ystone_sB, FALSE, TRUE,
3952 EL_ROCK, ACTION_FALLING, -1
3955 Ystone_e, FALSE, FALSE,
3956 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
3959 Ystone_eB, FALSE, TRUE,
3960 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
3963 Ystone_w, FALSE, FALSE,
3964 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
3967 Ystone_wB, FALSE, TRUE,
3968 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
3975 Xnut_pause, FALSE, FALSE,
3979 Xnut_fall, FALSE, FALSE,
3983 Ynut_s, FALSE, FALSE,
3984 EL_NUT, ACTION_FALLING, -1
3987 Ynut_sB, FALSE, TRUE,
3988 EL_NUT, ACTION_FALLING, -1
3991 Ynut_e, FALSE, FALSE,
3992 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
3995 Ynut_eB, FALSE, TRUE,
3996 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
3999 Ynut_w, FALSE, FALSE,
4000 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
4003 Ynut_wB, FALSE, TRUE,
4004 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
4007 Xbug_n, TRUE, FALSE,
4011 Xbug_e, TRUE, FALSE,
4012 EL_BUG_RIGHT, -1, -1
4015 Xbug_s, TRUE, FALSE,
4019 Xbug_w, TRUE, FALSE,
4023 Xbug_gon, FALSE, FALSE,
4027 Xbug_goe, FALSE, FALSE,
4028 EL_BUG_RIGHT, -1, -1
4031 Xbug_gos, FALSE, FALSE,
4035 Xbug_gow, FALSE, FALSE,
4039 Ybug_n, FALSE, FALSE,
4040 EL_BUG, ACTION_MOVING, MV_BIT_UP
4043 Ybug_nB, FALSE, TRUE,
4044 EL_BUG, ACTION_MOVING, MV_BIT_UP
4047 Ybug_e, FALSE, FALSE,
4048 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
4051 Ybug_eB, FALSE, TRUE,
4052 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
4055 Ybug_s, FALSE, FALSE,
4056 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
4059 Ybug_sB, FALSE, TRUE,
4060 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
4063 Ybug_w, FALSE, FALSE,
4064 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
4067 Ybug_wB, FALSE, TRUE,
4068 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
4071 Ybug_w_n, FALSE, FALSE,
4072 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
4075 Ybug_n_e, FALSE, FALSE,
4076 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
4079 Ybug_e_s, FALSE, FALSE,
4080 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
4083 Ybug_s_w, FALSE, FALSE,
4084 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
4087 Ybug_e_n, FALSE, FALSE,
4088 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
4091 Ybug_s_e, FALSE, FALSE,
4092 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
4095 Ybug_w_s, FALSE, FALSE,
4096 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
4099 Ybug_n_w, FALSE, FALSE,
4100 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
4103 Ybug_stone, FALSE, FALSE,
4104 EL_BUG, ACTION_SMASHED_BY_ROCK, -1
4107 Ybug_spring, FALSE, FALSE,
4108 EL_BUG, ACTION_SMASHED_BY_SPRING, -1
4111 Xtank_n, TRUE, FALSE,
4112 EL_SPACESHIP_UP, -1, -1
4115 Xtank_e, TRUE, FALSE,
4116 EL_SPACESHIP_RIGHT, -1, -1
4119 Xtank_s, TRUE, FALSE,
4120 EL_SPACESHIP_DOWN, -1, -1
4123 Xtank_w, TRUE, FALSE,
4124 EL_SPACESHIP_LEFT, -1, -1
4127 Xtank_gon, FALSE, FALSE,
4128 EL_SPACESHIP_UP, -1, -1
4131 Xtank_goe, FALSE, FALSE,
4132 EL_SPACESHIP_RIGHT, -1, -1
4135 Xtank_gos, FALSE, FALSE,
4136 EL_SPACESHIP_DOWN, -1, -1
4139 Xtank_gow, FALSE, FALSE,
4140 EL_SPACESHIP_LEFT, -1, -1
4143 Ytank_n, FALSE, FALSE,
4144 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
4147 Ytank_nB, FALSE, TRUE,
4148 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
4151 Ytank_e, FALSE, FALSE,
4152 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
4155 Ytank_eB, FALSE, TRUE,
4156 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
4159 Ytank_s, FALSE, FALSE,
4160 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
4163 Ytank_sB, FALSE, TRUE,
4164 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
4167 Ytank_w, FALSE, FALSE,
4168 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
4171 Ytank_wB, FALSE, TRUE,
4172 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
4175 Ytank_w_n, FALSE, FALSE,
4176 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
4179 Ytank_n_e, FALSE, FALSE,
4180 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
4183 Ytank_e_s, FALSE, FALSE,
4184 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
4187 Ytank_s_w, FALSE, FALSE,
4188 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
4191 Ytank_e_n, FALSE, FALSE,
4192 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
4195 Ytank_s_e, FALSE, FALSE,
4196 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
4199 Ytank_w_s, FALSE, FALSE,
4200 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
4203 Ytank_n_w, FALSE, FALSE,
4204 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
4207 Ytank_stone, FALSE, FALSE,
4208 EL_SPACESHIP, ACTION_SMASHED_BY_ROCK, -1
4211 Ytank_spring, FALSE, FALSE,
4212 EL_SPACESHIP, ACTION_SMASHED_BY_SPRING, -1
4215 Xandroid, TRUE, FALSE,
4216 EL_EMC_ANDROID, ACTION_ACTIVE, -1
4219 Xandroid_1_n, FALSE, FALSE,
4220 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
4223 Xandroid_2_n, FALSE, FALSE,
4224 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
4227 Xandroid_1_e, FALSE, FALSE,
4228 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
4231 Xandroid_2_e, FALSE, FALSE,
4232 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
4235 Xandroid_1_w, FALSE, FALSE,
4236 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
4239 Xandroid_2_w, FALSE, FALSE,
4240 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
4243 Xandroid_1_s, FALSE, FALSE,
4244 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
4247 Xandroid_2_s, FALSE, FALSE,
4248 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
4251 Yandroid_n, FALSE, FALSE,
4252 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
4255 Yandroid_nB, FALSE, TRUE,
4256 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
4259 Yandroid_ne, FALSE, FALSE,
4260 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPRIGHT
4263 Yandroid_neB, FALSE, TRUE,
4264 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPRIGHT
4267 Yandroid_e, FALSE, FALSE,
4268 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
4271 Yandroid_eB, FALSE, TRUE,
4272 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
4275 Yandroid_se, FALSE, FALSE,
4276 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNRIGHT
4279 Yandroid_seB, FALSE, TRUE,
4280 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNRIGHT
4283 Yandroid_s, FALSE, FALSE,
4284 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
4287 Yandroid_sB, FALSE, TRUE,
4288 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
4291 Yandroid_sw, FALSE, FALSE,
4292 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNLEFT
4295 Yandroid_swB, FALSE, TRUE,
4296 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNLEFT
4299 Yandroid_w, FALSE, FALSE,
4300 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
4303 Yandroid_wB, FALSE, TRUE,
4304 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
4307 Yandroid_nw, FALSE, FALSE,
4308 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPLEFT
4311 Yandroid_nwB, FALSE, TRUE,
4312 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPLEFT
4315 Xspring, TRUE, FALSE,
4319 Xspring_pause, FALSE, FALSE,
4323 Xspring_e, FALSE, FALSE,
4327 Xspring_w, FALSE, FALSE,
4331 Xspring_fall, FALSE, FALSE,
4335 Yspring_s, FALSE, FALSE,
4336 EL_SPRING, ACTION_FALLING, -1
4339 Yspring_sB, FALSE, TRUE,
4340 EL_SPRING, ACTION_FALLING, -1
4343 Yspring_e, FALSE, FALSE,
4344 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
4347 Yspring_eB, FALSE, TRUE,
4348 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
4351 Yspring_w, FALSE, FALSE,
4352 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
4355 Yspring_wB, FALSE, TRUE,
4356 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
4359 Yspring_kill_e, FALSE, FALSE,
4360 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
4363 Yspring_kill_eB, FALSE, TRUE,
4364 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
4367 Yspring_kill_w, FALSE, FALSE,
4368 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
4371 Yspring_kill_wB, FALSE, TRUE,
4372 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
4375 Xeater_n, TRUE, FALSE,
4376 EL_YAMYAM_UP, -1, -1
4379 Xeater_e, TRUE, FALSE,
4380 EL_YAMYAM_RIGHT, -1, -1
4383 Xeater_w, TRUE, FALSE,
4384 EL_YAMYAM_LEFT, -1, -1
4387 Xeater_s, TRUE, FALSE,
4388 EL_YAMYAM_DOWN, -1, -1
4391 Yeater_n, FALSE, FALSE,
4392 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
4395 Yeater_nB, FALSE, TRUE,
4396 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
4399 Yeater_e, FALSE, FALSE,
4400 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
4403 Yeater_eB, FALSE, TRUE,
4404 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
4407 Yeater_s, FALSE, FALSE,
4408 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
4411 Yeater_sB, FALSE, TRUE,
4412 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
4415 Yeater_w, FALSE, FALSE,
4416 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
4419 Yeater_wB, FALSE, TRUE,
4420 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
4423 Yeater_stone, FALSE, FALSE,
4424 EL_YAMYAM, ACTION_SMASHED_BY_ROCK, -1
4427 Yeater_spring, FALSE, FALSE,
4428 EL_YAMYAM, ACTION_SMASHED_BY_SPRING, -1
4431 Xalien, TRUE, FALSE,
4435 Xalien_pause, FALSE, FALSE,
4439 Yalien_n, FALSE, FALSE,
4440 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
4443 Yalien_nB, FALSE, TRUE,
4444 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
4447 Yalien_e, FALSE, FALSE,
4448 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
4451 Yalien_eB, FALSE, TRUE,
4452 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
4455 Yalien_s, FALSE, FALSE,
4456 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
4459 Yalien_sB, FALSE, TRUE,
4460 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
4463 Yalien_w, FALSE, FALSE,
4464 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
4467 Yalien_wB, FALSE, TRUE,
4468 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
4471 Yalien_stone, FALSE, FALSE,
4472 EL_ROBOT, ACTION_SMASHED_BY_ROCK, -1
4475 Yalien_spring, FALSE, FALSE,
4476 EL_ROBOT, ACTION_SMASHED_BY_SPRING, -1
4479 Xemerald, TRUE, FALSE,
4483 Xemerald_pause, FALSE, FALSE,
4487 Xemerald_fall, FALSE, FALSE,
4491 Xemerald_shine, FALSE, FALSE,
4492 EL_EMERALD, ACTION_TWINKLING, -1
4495 Yemerald_s, FALSE, FALSE,
4496 EL_EMERALD, ACTION_FALLING, -1
4499 Yemerald_sB, FALSE, TRUE,
4500 EL_EMERALD, ACTION_FALLING, -1
4503 Yemerald_e, FALSE, FALSE,
4504 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
4507 Yemerald_eB, FALSE, TRUE,
4508 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
4511 Yemerald_w, FALSE, FALSE,
4512 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
4515 Yemerald_wB, FALSE, TRUE,
4516 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
4519 Yemerald_eat, FALSE, FALSE,
4520 EL_EMERALD, ACTION_COLLECTING, -1
4523 Yemerald_stone, FALSE, FALSE,
4524 EL_NUT, ACTION_BREAKING, -1
4527 Xdiamond, TRUE, FALSE,
4531 Xdiamond_pause, FALSE, FALSE,
4535 Xdiamond_fall, FALSE, FALSE,
4539 Xdiamond_shine, FALSE, FALSE,
4540 EL_DIAMOND, ACTION_TWINKLING, -1
4543 Ydiamond_s, FALSE, FALSE,
4544 EL_DIAMOND, ACTION_FALLING, -1
4547 Ydiamond_sB, FALSE, TRUE,
4548 EL_DIAMOND, ACTION_FALLING, -1
4551 Ydiamond_e, FALSE, FALSE,
4552 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
4555 Ydiamond_eB, FALSE, TRUE,
4556 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
4559 Ydiamond_w, FALSE, FALSE,
4560 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
4563 Ydiamond_wB, FALSE, TRUE,
4564 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
4567 Ydiamond_eat, FALSE, FALSE,
4568 EL_DIAMOND, ACTION_COLLECTING, -1
4571 Ydiamond_stone, FALSE, FALSE,
4572 EL_DIAMOND, ACTION_SMASHED_BY_ROCK, -1
4575 Xdrip_fall, TRUE, FALSE,
4576 EL_AMOEBA_DROP, -1, -1
4579 Xdrip_stretch, FALSE, FALSE,
4580 EL_AMOEBA_DROP, ACTION_FALLING, -1
4583 Xdrip_stretchB, FALSE, TRUE,
4584 EL_AMOEBA_DROP, ACTION_FALLING, -1
4587 Xdrip_eat, FALSE, FALSE,
4588 EL_AMOEBA_DROP, ACTION_GROWING, -1
4591 Ydrip_s1, FALSE, FALSE,
4592 EL_AMOEBA_DROP, ACTION_FALLING, -1
4595 Ydrip_s1B, FALSE, TRUE,
4596 EL_AMOEBA_DROP, ACTION_FALLING, -1
4599 Ydrip_s2, FALSE, FALSE,
4600 EL_AMOEBA_DROP, ACTION_FALLING, -1
4603 Ydrip_s2B, FALSE, TRUE,
4604 EL_AMOEBA_DROP, ACTION_FALLING, -1
4611 Xbomb_pause, FALSE, FALSE,
4615 Xbomb_fall, FALSE, FALSE,
4619 Ybomb_s, FALSE, FALSE,
4620 EL_BOMB, ACTION_FALLING, -1
4623 Ybomb_sB, FALSE, TRUE,
4624 EL_BOMB, ACTION_FALLING, -1
4627 Ybomb_e, FALSE, FALSE,
4628 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
4631 Ybomb_eB, FALSE, TRUE,
4632 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
4635 Ybomb_w, FALSE, FALSE,
4636 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
4639 Ybomb_wB, FALSE, TRUE,
4640 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
4643 Ybomb_eat, FALSE, FALSE,
4644 EL_BOMB, ACTION_ACTIVATING, -1
4647 Xballoon, TRUE, FALSE,
4651 Yballoon_n, FALSE, FALSE,
4652 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
4655 Yballoon_nB, FALSE, TRUE,
4656 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
4659 Yballoon_e, FALSE, FALSE,
4660 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
4663 Yballoon_eB, FALSE, TRUE,
4664 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
4667 Yballoon_s, FALSE, FALSE,
4668 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
4671 Yballoon_sB, FALSE, TRUE,
4672 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
4675 Yballoon_w, FALSE, FALSE,
4676 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
4679 Yballoon_wB, FALSE, TRUE,
4680 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
4683 Xgrass, TRUE, FALSE,
4684 EL_EMC_GRASS, -1, -1
4687 Ygrass_nB, FALSE, FALSE,
4688 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_UP
4691 Ygrass_eB, FALSE, FALSE,
4692 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_RIGHT
4695 Ygrass_sB, FALSE, FALSE,
4696 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_DOWN
4699 Ygrass_wB, FALSE, FALSE,
4700 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_LEFT
4707 Ydirt_nB, FALSE, FALSE,
4708 EL_SAND, ACTION_DIGGING, MV_BIT_UP
4711 Ydirt_eB, FALSE, FALSE,
4712 EL_SAND, ACTION_DIGGING, MV_BIT_RIGHT
4715 Ydirt_sB, FALSE, FALSE,
4716 EL_SAND, ACTION_DIGGING, MV_BIT_DOWN
4719 Ydirt_wB, FALSE, FALSE,
4720 EL_SAND, ACTION_DIGGING, MV_BIT_LEFT
4723 Xacid_ne, TRUE, FALSE,
4724 EL_ACID_POOL_TOPRIGHT, -1, -1
4727 Xacid_se, TRUE, FALSE,
4728 EL_ACID_POOL_BOTTOMRIGHT, -1, -1
4731 Xacid_s, TRUE, FALSE,
4732 EL_ACID_POOL_BOTTOM, -1, -1
4735 Xacid_sw, TRUE, FALSE,
4736 EL_ACID_POOL_BOTTOMLEFT, -1, -1
4739 Xacid_nw, TRUE, FALSE,
4740 EL_ACID_POOL_TOPLEFT, -1, -1
4743 Xacid_1, TRUE, FALSE,
4747 Xacid_2, FALSE, FALSE,
4751 Xacid_3, FALSE, FALSE,
4755 Xacid_4, FALSE, FALSE,
4759 Xacid_5, FALSE, FALSE,
4763 Xacid_6, FALSE, FALSE,
4767 Xacid_7, FALSE, FALSE,
4771 Xacid_8, FALSE, FALSE,
4775 Xball_1, TRUE, FALSE,
4776 EL_EMC_MAGIC_BALL, -1, -1
4779 Xball_1B, FALSE, FALSE,
4780 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
4783 Xball_2, FALSE, FALSE,
4784 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
4787 Xball_2B, FALSE, FALSE,
4788 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
4791 Yball_eat, FALSE, FALSE,
4792 EL_EMC_MAGIC_BALL, ACTION_DROPPING, -1
4795 Ykey_1_eat, FALSE, FALSE,
4796 EL_EM_KEY_1, ACTION_COLLECTING, -1
4799 Ykey_2_eat, FALSE, FALSE,
4800 EL_EM_KEY_2, ACTION_COLLECTING, -1
4803 Ykey_3_eat, FALSE, FALSE,
4804 EL_EM_KEY_3, ACTION_COLLECTING, -1
4807 Ykey_4_eat, FALSE, FALSE,
4808 EL_EM_KEY_4, ACTION_COLLECTING, -1
4811 Ykey_5_eat, FALSE, FALSE,
4812 EL_EMC_KEY_5, ACTION_COLLECTING, -1
4815 Ykey_6_eat, FALSE, FALSE,
4816 EL_EMC_KEY_6, ACTION_COLLECTING, -1
4819 Ykey_7_eat, FALSE, FALSE,
4820 EL_EMC_KEY_7, ACTION_COLLECTING, -1
4823 Ykey_8_eat, FALSE, FALSE,
4824 EL_EMC_KEY_8, ACTION_COLLECTING, -1
4827 Ylenses_eat, FALSE, FALSE,
4828 EL_EMC_LENSES, ACTION_COLLECTING, -1
4831 Ymagnify_eat, FALSE, FALSE,
4832 EL_EMC_MAGNIFIER, ACTION_COLLECTING, -1
4835 Ygrass_eat, FALSE, FALSE,
4836 EL_EMC_GRASS, ACTION_SNAPPING, -1
4839 Ydirt_eat, FALSE, FALSE,
4840 EL_SAND, ACTION_SNAPPING, -1
4843 Xgrow_ns, TRUE, FALSE,
4844 EL_EXPANDABLE_WALL_VERTICAL, -1, -1
4847 Ygrow_ns_eat, FALSE, FALSE,
4848 EL_EXPANDABLE_WALL_VERTICAL, ACTION_GROWING, -1
4851 Xgrow_ew, TRUE, FALSE,
4852 EL_EXPANDABLE_WALL_HORIZONTAL, -1, -1
4855 Ygrow_ew_eat, FALSE, FALSE,
4856 EL_EXPANDABLE_WALL_HORIZONTAL, ACTION_GROWING, -1
4859 Xwonderwall, TRUE, FALSE,
4860 EL_MAGIC_WALL, -1, -1
4863 XwonderwallB, FALSE, FALSE,
4864 EL_MAGIC_WALL, ACTION_ACTIVE, -1
4867 Xamoeba_1, TRUE, FALSE,
4868 EL_AMOEBA_DRY, ACTION_OTHER, -1
4871 Xamoeba_2, FALSE, FALSE,
4872 EL_AMOEBA_DRY, ACTION_OTHER, -1
4875 Xamoeba_3, FALSE, FALSE,
4876 EL_AMOEBA_DRY, ACTION_OTHER, -1
4879 Xamoeba_4, FALSE, FALSE,
4880 EL_AMOEBA_DRY, ACTION_OTHER, -1
4883 Xamoeba_5, TRUE, FALSE,
4884 EL_AMOEBA_WET, ACTION_OTHER, -1
4887 Xamoeba_6, FALSE, FALSE,
4888 EL_AMOEBA_WET, ACTION_OTHER, -1
4891 Xamoeba_7, FALSE, FALSE,
4892 EL_AMOEBA_WET, ACTION_OTHER, -1
4895 Xamoeba_8, FALSE, FALSE,
4896 EL_AMOEBA_WET, ACTION_OTHER, -1
4899 Xdoor_1, TRUE, FALSE,
4900 EL_EM_GATE_1, -1, -1
4903 Xdoor_2, TRUE, FALSE,
4904 EL_EM_GATE_2, -1, -1
4907 Xdoor_3, TRUE, FALSE,
4908 EL_EM_GATE_3, -1, -1
4911 Xdoor_4, TRUE, FALSE,
4912 EL_EM_GATE_4, -1, -1
4915 Xdoor_5, TRUE, FALSE,
4916 EL_EMC_GATE_5, -1, -1
4919 Xdoor_6, TRUE, FALSE,
4920 EL_EMC_GATE_6, -1, -1
4923 Xdoor_7, TRUE, FALSE,
4924 EL_EMC_GATE_7, -1, -1
4927 Xdoor_8, TRUE, FALSE,
4928 EL_EMC_GATE_8, -1, -1
4931 Xkey_1, TRUE, FALSE,
4935 Xkey_2, TRUE, FALSE,
4939 Xkey_3, TRUE, FALSE,
4943 Xkey_4, TRUE, FALSE,
4947 Xkey_5, TRUE, FALSE,
4948 EL_EMC_KEY_5, -1, -1
4951 Xkey_6, TRUE, FALSE,
4952 EL_EMC_KEY_6, -1, -1
4955 Xkey_7, TRUE, FALSE,
4956 EL_EMC_KEY_7, -1, -1
4959 Xkey_8, TRUE, FALSE,
4960 EL_EMC_KEY_8, -1, -1
4963 Xwind_n, TRUE, FALSE,
4964 EL_BALLOON_SWITCH_UP, -1, -1
4967 Xwind_e, TRUE, FALSE,
4968 EL_BALLOON_SWITCH_RIGHT, -1, -1
4971 Xwind_s, TRUE, FALSE,
4972 EL_BALLOON_SWITCH_DOWN, -1, -1
4975 Xwind_w, TRUE, FALSE,
4976 EL_BALLOON_SWITCH_LEFT, -1, -1
4979 Xwind_nesw, TRUE, FALSE,
4980 EL_BALLOON_SWITCH_ANY, -1, -1
4983 Xwind_stop, TRUE, FALSE,
4984 EL_BALLOON_SWITCH_NONE, -1, -1
4988 EL_EM_EXIT_CLOSED, -1, -1
4991 Xexit_1, TRUE, FALSE,
4992 EL_EM_EXIT_OPEN, -1, -1
4995 Xexit_2, FALSE, FALSE,
4996 EL_EM_EXIT_OPEN, -1, -1
4999 Xexit_3, FALSE, FALSE,
5000 EL_EM_EXIT_OPEN, -1, -1
5003 Xdynamite, TRUE, FALSE,
5004 EL_EM_DYNAMITE, -1, -1
5007 Ydynamite_eat, FALSE, FALSE,
5008 EL_EM_DYNAMITE, ACTION_COLLECTING, -1
5011 Xdynamite_1, TRUE, FALSE,
5012 EL_EM_DYNAMITE_ACTIVE, -1, -1
5015 Xdynamite_2, FALSE, FALSE,
5016 EL_EM_DYNAMITE_ACTIVE, -1, -1
5019 Xdynamite_3, FALSE, FALSE,
5020 EL_EM_DYNAMITE_ACTIVE, -1, -1
5023 Xdynamite_4, FALSE, FALSE,
5024 EL_EM_DYNAMITE_ACTIVE, -1, -1
5027 Xbumper, TRUE, FALSE,
5028 EL_EMC_SPRING_BUMPER, -1, -1
5031 XbumperB, FALSE, FALSE,
5032 EL_EMC_SPRING_BUMPER, ACTION_ACTIVE, -1
5035 Xwheel, TRUE, FALSE,
5036 EL_ROBOT_WHEEL, -1, -1
5039 XwheelB, FALSE, FALSE,
5040 EL_ROBOT_WHEEL, ACTION_ACTIVE, -1
5043 Xswitch, TRUE, FALSE,
5044 EL_EMC_MAGIC_BALL_SWITCH, -1, -1
5047 XswitchB, FALSE, FALSE,
5048 EL_EMC_MAGIC_BALL_SWITCH, ACTION_ACTIVE, -1
5052 EL_QUICKSAND_EMPTY, -1, -1
5055 Xsand_stone, TRUE, FALSE,
5056 EL_QUICKSAND_FULL, -1, -1
5059 Xsand_stonein_1, FALSE, TRUE,
5060 EL_ROCK, ACTION_FILLING, -1
5063 Xsand_stonein_2, FALSE, TRUE,
5064 EL_ROCK, ACTION_FILLING, -1
5067 Xsand_stonein_3, FALSE, TRUE,
5068 EL_ROCK, ACTION_FILLING, -1
5071 Xsand_stonein_4, FALSE, TRUE,
5072 EL_ROCK, ACTION_FILLING, -1
5076 Xsand_stonesand_1, FALSE, FALSE,
5077 EL_QUICKSAND_EMPTYING, -1, -1
5080 Xsand_stonesand_2, FALSE, FALSE,
5081 EL_QUICKSAND_EMPTYING, -1, -1
5084 Xsand_stonesand_3, FALSE, FALSE,
5085 EL_QUICKSAND_EMPTYING, -1, -1
5088 Xsand_stonesand_4, FALSE, FALSE,
5089 EL_QUICKSAND_EMPTYING, -1, -1
5092 Xsand_stonesand_quickout_1, FALSE, FALSE,
5093 EL_QUICKSAND_EMPTYING, -1, -1
5096 Xsand_stonesand_quickout_2, FALSE, FALSE,
5097 EL_QUICKSAND_EMPTYING, -1, -1
5101 Xsand_stonesand_1, FALSE, FALSE,
5102 EL_QUICKSAND_FULL, -1, -1
5105 Xsand_stonesand_2, FALSE, FALSE,
5106 EL_QUICKSAND_FULL, -1, -1
5109 Xsand_stonesand_3, FALSE, FALSE,
5110 EL_QUICKSAND_FULL, -1, -1
5113 Xsand_stonesand_4, FALSE, FALSE,
5114 EL_QUICKSAND_FULL, -1, -1
5118 Xsand_stoneout_1, FALSE, FALSE,
5119 EL_ROCK, ACTION_EMPTYING, -1
5122 Xsand_stoneout_2, FALSE, FALSE,
5123 EL_ROCK, ACTION_EMPTYING, -1
5127 Xsand_sandstone_1, FALSE, FALSE,
5128 EL_QUICKSAND_FILLING, -1, -1
5131 Xsand_sandstone_2, FALSE, FALSE,
5132 EL_QUICKSAND_FILLING, -1, -1
5135 Xsand_sandstone_3, FALSE, FALSE,
5136 EL_QUICKSAND_FILLING, -1, -1
5139 Xsand_sandstone_4, FALSE, FALSE,
5140 EL_QUICKSAND_FILLING, -1, -1
5144 Xsand_sandstone_1, FALSE, FALSE,
5145 EL_QUICKSAND_FULL, -1, -1
5148 Xsand_sandstone_2, FALSE, FALSE,
5149 EL_QUICKSAND_FULL, -1, -1
5152 Xsand_sandstone_3, FALSE, FALSE,
5153 EL_QUICKSAND_FULL, -1, -1
5156 Xsand_sandstone_4, FALSE, FALSE,
5157 EL_QUICKSAND_FULL, -1, -1
5161 Xplant, TRUE, FALSE,
5162 EL_EMC_PLANT, -1, -1
5165 Yplant, FALSE, FALSE,
5166 EL_EMC_PLANT, -1, -1
5169 Xlenses, TRUE, FALSE,
5170 EL_EMC_LENSES, -1, -1
5173 Xmagnify, TRUE, FALSE,
5174 EL_EMC_MAGNIFIER, -1, -1
5177 Xdripper, TRUE, FALSE,
5178 EL_EMC_DRIPPER, -1, -1
5181 XdripperB, FALSE, FALSE,
5182 EL_EMC_DRIPPER, ACTION_ACTIVE, -1
5185 Xfake_blank, TRUE, FALSE,
5186 EL_INVISIBLE_WALL, -1, -1
5189 Xfake_blankB, FALSE, FALSE,
5190 EL_INVISIBLE_WALL, ACTION_ACTIVE, -1
5193 Xfake_grass, TRUE, FALSE,
5194 EL_EMC_FAKE_GRASS, -1, -1
5197 Xfake_grassB, FALSE, FALSE,
5198 EL_EMC_FAKE_GRASS, ACTION_ACTIVE, -1
5201 Xfake_door_1, TRUE, FALSE,
5202 EL_EM_GATE_1_GRAY, -1, -1
5205 Xfake_door_2, TRUE, FALSE,
5206 EL_EM_GATE_2_GRAY, -1, -1
5209 Xfake_door_3, TRUE, FALSE,
5210 EL_EM_GATE_3_GRAY, -1, -1
5213 Xfake_door_4, TRUE, FALSE,
5214 EL_EM_GATE_4_GRAY, -1, -1
5217 Xfake_door_5, TRUE, FALSE,
5218 EL_EMC_GATE_5_GRAY, -1, -1
5221 Xfake_door_6, TRUE, FALSE,
5222 EL_EMC_GATE_6_GRAY, -1, -1
5225 Xfake_door_7, TRUE, FALSE,
5226 EL_EMC_GATE_7_GRAY, -1, -1
5229 Xfake_door_8, TRUE, FALSE,
5230 EL_EMC_GATE_8_GRAY, -1, -1
5233 Xfake_acid_1, TRUE, FALSE,
5234 EL_EMC_FAKE_ACID, -1, -1
5237 Xfake_acid_2, FALSE, FALSE,
5238 EL_EMC_FAKE_ACID, -1, -1
5241 Xfake_acid_3, FALSE, FALSE,
5242 EL_EMC_FAKE_ACID, -1, -1
5245 Xfake_acid_4, FALSE, FALSE,
5246 EL_EMC_FAKE_ACID, -1, -1
5249 Xfake_acid_5, FALSE, FALSE,
5250 EL_EMC_FAKE_ACID, -1, -1
5253 Xfake_acid_6, FALSE, FALSE,
5254 EL_EMC_FAKE_ACID, -1, -1
5257 Xfake_acid_7, FALSE, FALSE,
5258 EL_EMC_FAKE_ACID, -1, -1
5261 Xfake_acid_8, FALSE, FALSE,
5262 EL_EMC_FAKE_ACID, -1, -1
5265 Xsteel_1, TRUE, FALSE,
5266 EL_STEELWALL, -1, -1
5269 Xsteel_2, TRUE, FALSE,
5270 EL_EMC_STEELWALL_2, -1, -1
5273 Xsteel_3, TRUE, FALSE,
5274 EL_EMC_STEELWALL_3, -1, -1
5277 Xsteel_4, TRUE, FALSE,
5278 EL_EMC_STEELWALL_4, -1, -1
5281 Xwall_1, TRUE, FALSE,
5285 Xwall_2, TRUE, FALSE,
5286 EL_EMC_WALL_14, -1, -1
5289 Xwall_3, TRUE, FALSE,
5290 EL_EMC_WALL_15, -1, -1
5293 Xwall_4, TRUE, FALSE,
5294 EL_EMC_WALL_16, -1, -1
5297 Xround_wall_1, TRUE, FALSE,
5298 EL_WALL_SLIPPERY, -1, -1
5301 Xround_wall_2, TRUE, FALSE,
5302 EL_EMC_WALL_SLIPPERY_2, -1, -1
5305 Xround_wall_3, TRUE, FALSE,
5306 EL_EMC_WALL_SLIPPERY_3, -1, -1
5309 Xround_wall_4, TRUE, FALSE,
5310 EL_EMC_WALL_SLIPPERY_4, -1, -1
5313 Xdecor_1, TRUE, FALSE,
5314 EL_EMC_WALL_8, -1, -1
5317 Xdecor_2, TRUE, FALSE,
5318 EL_EMC_WALL_6, -1, -1
5321 Xdecor_3, TRUE, FALSE,
5322 EL_EMC_WALL_4, -1, -1
5325 Xdecor_4, TRUE, FALSE,
5326 EL_EMC_WALL_7, -1, -1
5329 Xdecor_5, TRUE, FALSE,
5330 EL_EMC_WALL_5, -1, -1
5333 Xdecor_6, TRUE, FALSE,
5334 EL_EMC_WALL_9, -1, -1
5337 Xdecor_7, TRUE, FALSE,
5338 EL_EMC_WALL_10, -1, -1
5341 Xdecor_8, TRUE, FALSE,
5342 EL_EMC_WALL_1, -1, -1
5345 Xdecor_9, TRUE, FALSE,
5346 EL_EMC_WALL_2, -1, -1
5349 Xdecor_10, TRUE, FALSE,
5350 EL_EMC_WALL_3, -1, -1
5353 Xdecor_11, TRUE, FALSE,
5354 EL_EMC_WALL_11, -1, -1
5357 Xdecor_12, TRUE, FALSE,
5358 EL_EMC_WALL_12, -1, -1
5361 Xalpha_0, TRUE, FALSE,
5362 EL_CHAR('0'), -1, -1
5365 Xalpha_1, TRUE, FALSE,
5366 EL_CHAR('1'), -1, -1
5369 Xalpha_2, TRUE, FALSE,
5370 EL_CHAR('2'), -1, -1
5373 Xalpha_3, TRUE, FALSE,
5374 EL_CHAR('3'), -1, -1
5377 Xalpha_4, TRUE, FALSE,
5378 EL_CHAR('4'), -1, -1
5381 Xalpha_5, TRUE, FALSE,
5382 EL_CHAR('5'), -1, -1
5385 Xalpha_6, TRUE, FALSE,
5386 EL_CHAR('6'), -1, -1
5389 Xalpha_7, TRUE, FALSE,
5390 EL_CHAR('7'), -1, -1
5393 Xalpha_8, TRUE, FALSE,
5394 EL_CHAR('8'), -1, -1
5397 Xalpha_9, TRUE, FALSE,
5398 EL_CHAR('9'), -1, -1
5401 Xalpha_excla, TRUE, FALSE,
5402 EL_CHAR('!'), -1, -1
5405 Xalpha_quote, TRUE, FALSE,
5406 EL_CHAR('"'), -1, -1
5409 Xalpha_comma, TRUE, FALSE,
5410 EL_CHAR(','), -1, -1
5413 Xalpha_minus, TRUE, FALSE,
5414 EL_CHAR('-'), -1, -1
5417 Xalpha_perio, TRUE, FALSE,
5418 EL_CHAR('.'), -1, -1
5421 Xalpha_colon, TRUE, FALSE,
5422 EL_CHAR(':'), -1, -1
5425 Xalpha_quest, TRUE, FALSE,
5426 EL_CHAR('?'), -1, -1
5429 Xalpha_a, TRUE, FALSE,
5430 EL_CHAR('A'), -1, -1
5433 Xalpha_b, TRUE, FALSE,
5434 EL_CHAR('B'), -1, -1
5437 Xalpha_c, TRUE, FALSE,
5438 EL_CHAR('C'), -1, -1
5441 Xalpha_d, TRUE, FALSE,
5442 EL_CHAR('D'), -1, -1
5445 Xalpha_e, TRUE, FALSE,
5446 EL_CHAR('E'), -1, -1
5449 Xalpha_f, TRUE, FALSE,
5450 EL_CHAR('F'), -1, -1
5453 Xalpha_g, TRUE, FALSE,
5454 EL_CHAR('G'), -1, -1
5457 Xalpha_h, TRUE, FALSE,
5458 EL_CHAR('H'), -1, -1
5461 Xalpha_i, TRUE, FALSE,
5462 EL_CHAR('I'), -1, -1
5465 Xalpha_j, TRUE, FALSE,
5466 EL_CHAR('J'), -1, -1
5469 Xalpha_k, TRUE, FALSE,
5470 EL_CHAR('K'), -1, -1
5473 Xalpha_l, TRUE, FALSE,
5474 EL_CHAR('L'), -1, -1
5477 Xalpha_m, TRUE, FALSE,
5478 EL_CHAR('M'), -1, -1
5481 Xalpha_n, TRUE, FALSE,
5482 EL_CHAR('N'), -1, -1
5485 Xalpha_o, TRUE, FALSE,
5486 EL_CHAR('O'), -1, -1
5489 Xalpha_p, TRUE, FALSE,
5490 EL_CHAR('P'), -1, -1
5493 Xalpha_q, TRUE, FALSE,
5494 EL_CHAR('Q'), -1, -1
5497 Xalpha_r, TRUE, FALSE,
5498 EL_CHAR('R'), -1, -1
5501 Xalpha_s, TRUE, FALSE,
5502 EL_CHAR('S'), -1, -1
5505 Xalpha_t, TRUE, FALSE,
5506 EL_CHAR('T'), -1, -1
5509 Xalpha_u, TRUE, FALSE,
5510 EL_CHAR('U'), -1, -1
5513 Xalpha_v, TRUE, FALSE,
5514 EL_CHAR('V'), -1, -1
5517 Xalpha_w, TRUE, FALSE,
5518 EL_CHAR('W'), -1, -1
5521 Xalpha_x, TRUE, FALSE,
5522 EL_CHAR('X'), -1, -1
5525 Xalpha_y, TRUE, FALSE,
5526 EL_CHAR('Y'), -1, -1
5529 Xalpha_z, TRUE, FALSE,
5530 EL_CHAR('Z'), -1, -1
5533 Xalpha_arrow_e, TRUE, FALSE,
5534 EL_CHAR('>'), -1, -1
5537 Xalpha_arrow_w, TRUE, FALSE,
5538 EL_CHAR('<'), -1, -1
5541 Xalpha_copyr, TRUE, FALSE,
5542 EL_CHAR('©'), -1, -1
5546 Xboom_bug, FALSE, FALSE,
5547 EL_BUG, ACTION_EXPLODING, -1
5550 Xboom_bomb, FALSE, FALSE,
5551 EL_BOMB, ACTION_EXPLODING, -1
5554 Xboom_android, FALSE, FALSE,
5555 EL_EMC_ANDROID, ACTION_OTHER, -1
5558 Xboom_1, FALSE, FALSE,
5559 EL_DEFAULT, ACTION_EXPLODING, -1
5562 Xboom_2, FALSE, FALSE,
5563 EL_DEFAULT, ACTION_EXPLODING, -1
5566 Znormal, FALSE, FALSE,
5570 Zdynamite, FALSE, FALSE,
5574 Zplayer, FALSE, FALSE,
5578 ZBORDER, FALSE, FALSE,
5588 static struct Mapping_EM_to_RND_player
5597 em_player_mapping_list[] =
5601 EL_PLAYER_1, ACTION_MOVING, MV_BIT_UP,
5605 EL_PLAYER_1, ACTION_MOVING, MV_BIT_RIGHT,
5609 EL_PLAYER_1, ACTION_MOVING, MV_BIT_DOWN,
5613 EL_PLAYER_1, ACTION_MOVING, MV_BIT_LEFT,
5617 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_UP,
5621 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_RIGHT,
5625 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_DOWN,
5629 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_LEFT,
5633 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_UP,
5637 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_RIGHT,
5641 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_DOWN,
5645 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_LEFT,
5649 EL_PLAYER_2, ACTION_MOVING, MV_BIT_UP,
5653 EL_PLAYER_2, ACTION_MOVING, MV_BIT_RIGHT,
5657 EL_PLAYER_2, ACTION_MOVING, MV_BIT_DOWN,
5661 EL_PLAYER_2, ACTION_MOVING, MV_BIT_LEFT,
5665 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_UP,
5669 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_RIGHT,
5673 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_DOWN,
5677 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_LEFT,
5681 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_UP,
5685 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_RIGHT,
5689 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_DOWN,
5693 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_LEFT,
5697 EL_PLAYER_1, ACTION_DEFAULT, -1,
5701 EL_PLAYER_2, ACTION_DEFAULT, -1,
5705 EL_PLAYER_3, ACTION_MOVING, MV_BIT_UP,
5709 EL_PLAYER_3, ACTION_MOVING, MV_BIT_RIGHT,
5713 EL_PLAYER_3, ACTION_MOVING, MV_BIT_DOWN,
5717 EL_PLAYER_3, ACTION_MOVING, MV_BIT_LEFT,
5721 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_UP,
5725 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_RIGHT,
5729 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_DOWN,
5733 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_LEFT,
5737 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_UP,
5741 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_RIGHT,
5745 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_DOWN,
5749 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_LEFT,
5753 EL_PLAYER_4, ACTION_MOVING, MV_BIT_UP,
5757 EL_PLAYER_4, ACTION_MOVING, MV_BIT_RIGHT,
5761 EL_PLAYER_4, ACTION_MOVING, MV_BIT_DOWN,
5765 EL_PLAYER_4, ACTION_MOVING, MV_BIT_LEFT,
5769 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_UP,
5773 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_RIGHT,
5777 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_DOWN,
5781 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_LEFT,
5785 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_UP,
5789 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_RIGHT,
5793 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_DOWN,
5797 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_LEFT,
5801 EL_PLAYER_3, ACTION_DEFAULT, -1,
5805 EL_PLAYER_4, ACTION_DEFAULT, -1,
5814 int map_element_RND_to_EM(int element_rnd)
5816 static unsigned short mapping_RND_to_EM[NUM_FILE_ELEMENTS];
5817 static boolean mapping_initialized = FALSE;
5819 if (!mapping_initialized)
5823 /* return "Xalpha_quest" for all undefined elements in mapping array */
5824 for (i = 0; i < NUM_FILE_ELEMENTS; i++)
5825 mapping_RND_to_EM[i] = Xalpha_quest;
5827 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5828 if (em_object_mapping_list[i].is_rnd_to_em_mapping)
5829 mapping_RND_to_EM[em_object_mapping_list[i].element_rnd] =
5830 em_object_mapping_list[i].element_em;
5832 mapping_initialized = TRUE;
5835 if (element_rnd >= 0 && element_rnd < NUM_FILE_ELEMENTS)
5836 return mapping_RND_to_EM[element_rnd];
5838 Error(ERR_WARN, "invalid RND level element %d", element_rnd);
5843 int map_element_EM_to_RND(int element_em)
5845 static unsigned short mapping_EM_to_RND[TILE_MAX];
5846 static boolean mapping_initialized = FALSE;
5848 if (!mapping_initialized)
5852 /* return "EL_UNKNOWN" for all undefined elements in mapping array */
5853 for (i = 0; i < TILE_MAX; i++)
5854 mapping_EM_to_RND[i] = EL_UNKNOWN;
5856 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5857 mapping_EM_to_RND[em_object_mapping_list[i].element_em] =
5858 em_object_mapping_list[i].element_rnd;
5860 mapping_initialized = TRUE;
5863 if (element_em >= 0 && element_em < TILE_MAX)
5864 return mapping_EM_to_RND[element_em];
5866 Error(ERR_WARN, "invalid EM level element %d", element_em);
5871 void map_android_clone_elements_RND_to_EM(struct LevelInfo *level)
5873 struct LevelInfo_EM *level_em = level->native_em_level;
5874 struct LEVEL *lev = level_em->lev;
5877 for (i = 0; i < TILE_MAX; i++)
5878 lev->android_array[i] = Xblank;
5880 for (i = 0; i < level->num_android_clone_elements; i++)
5882 int element_rnd = level->android_clone_element[i];
5883 int element_em = map_element_RND_to_EM(element_rnd);
5885 for (j = 0; em_object_mapping_list[j].element_em != -1; j++)
5886 if (em_object_mapping_list[j].element_rnd == element_rnd)
5887 lev->android_array[em_object_mapping_list[j].element_em] = element_em;
5891 void map_android_clone_elements_EM_to_RND(struct LevelInfo *level)
5893 struct LevelInfo_EM *level_em = level->native_em_level;
5894 struct LEVEL *lev = level_em->lev;
5897 level->num_android_clone_elements = 0;
5899 for (i = 0; i < TILE_MAX; i++)
5901 int element_em = lev->android_array[i];
5903 boolean element_found = FALSE;
5905 if (element_em == Xblank)
5908 element_rnd = map_element_EM_to_RND(element_em);
5910 for (j = 0; j < level->num_android_clone_elements; j++)
5911 if (level->android_clone_element[j] == element_rnd)
5912 element_found = TRUE;
5916 level->android_clone_element[level->num_android_clone_elements++] =
5919 if (level->num_android_clone_elements == MAX_ANDROID_ELEMENTS)
5924 if (level->num_android_clone_elements == 0)
5926 level->num_android_clone_elements = 1;
5927 level->android_clone_element[0] = EL_EMPTY;
5931 int map_direction_RND_to_EM(int direction)
5933 return (direction == MV_UP ? 0 :
5934 direction == MV_RIGHT ? 1 :
5935 direction == MV_DOWN ? 2 :
5936 direction == MV_LEFT ? 3 :
5940 int map_direction_EM_to_RND(int direction)
5942 return (direction == 0 ? MV_UP :
5943 direction == 1 ? MV_RIGHT :
5944 direction == 2 ? MV_DOWN :
5945 direction == 3 ? MV_LEFT :
5949 int map_element_RND_to_SP(int element_rnd)
5951 int element_sp = 0x20; /* map unknown elements to yellow "hardware" */
5953 if (element_rnd >= EL_SP_START &&
5954 element_rnd <= EL_SP_END)
5955 element_sp = element_rnd - EL_SP_START;
5956 else if (element_rnd == EL_EMPTY_SPACE)
5958 else if (element_rnd == EL_INVISIBLE_WALL)
5964 int map_element_SP_to_RND(int element_sp)
5966 int element_rnd = EL_UNKNOWN;
5968 if (element_sp >= 0x00 &&
5970 element_rnd = EL_SP_START + element_sp;
5971 else if (element_sp == 0x28)
5972 element_rnd = EL_INVISIBLE_WALL;
5977 int map_action_SP_to_RND(int action_sp)
5981 case actActive: return ACTION_ACTIVE;
5982 case actImpact: return ACTION_IMPACT;
5983 case actExploding: return ACTION_EXPLODING;
5984 case actDigging: return ACTION_DIGGING;
5985 case actSnapping: return ACTION_SNAPPING;
5986 case actCollecting: return ACTION_COLLECTING;
5987 case actPassing: return ACTION_PASSING;
5988 case actPushing: return ACTION_PUSHING;
5989 case actDropping: return ACTION_DROPPING;
5991 default: return ACTION_DEFAULT;
5995 int get_next_element(int element)
5999 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
6000 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
6001 case EL_QUICKSAND_FAST_FILLING: return EL_QUICKSAND_FAST_FULL;
6002 case EL_QUICKSAND_FAST_EMPTYING: return EL_QUICKSAND_FAST_EMPTY;
6003 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
6004 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
6005 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
6006 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
6007 case EL_DC_MAGIC_WALL_FILLING: return EL_DC_MAGIC_WALL_FULL;
6008 case EL_DC_MAGIC_WALL_EMPTYING: return EL_DC_MAGIC_WALL_ACTIVE;
6009 case EL_AMOEBA_DROPPING: return EL_AMOEBA_WET;
6011 default: return element;
6016 int el_act_dir2img(int element, int action, int direction)
6018 element = GFX_ELEMENT(element);
6020 if (direction == MV_NONE)
6021 return element_info[element].graphic[action];
6023 direction = MV_DIR_TO_BIT(direction);
6025 return element_info[element].direction_graphic[action][direction];
6028 int el_act_dir2img(int element, int action, int direction)
6030 element = GFX_ELEMENT(element);
6031 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
6033 /* direction_graphic[][] == graphic[] for undefined direction graphics */
6034 return element_info[element].direction_graphic[action][direction];
6039 static int el_act_dir2crm(int element, int action, int direction)
6041 element = GFX_ELEMENT(element);
6043 if (direction == MV_NONE)
6044 return element_info[element].crumbled[action];
6046 direction = MV_DIR_TO_BIT(direction);
6048 return element_info[element].direction_crumbled[action][direction];
6051 static int el_act_dir2crm(int element, int action, int direction)
6053 element = GFX_ELEMENT(element);
6054 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
6056 /* direction_graphic[][] == graphic[] for undefined direction graphics */
6057 return element_info[element].direction_crumbled[action][direction];
6061 int el_act2img(int element, int action)
6063 element = GFX_ELEMENT(element);
6065 return element_info[element].graphic[action];
6068 int el_act2crm(int element, int action)
6070 element = GFX_ELEMENT(element);
6072 return element_info[element].crumbled[action];
6075 int el_dir2img(int element, int direction)
6077 element = GFX_ELEMENT(element);
6079 return el_act_dir2img(element, ACTION_DEFAULT, direction);
6082 int el2baseimg(int element)
6084 return element_info[element].graphic[ACTION_DEFAULT];
6087 int el2img(int element)
6089 element = GFX_ELEMENT(element);
6091 return element_info[element].graphic[ACTION_DEFAULT];
6094 int el2edimg(int element)
6096 element = GFX_ELEMENT(element);
6098 return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
6101 int el2preimg(int element)
6103 element = GFX_ELEMENT(element);
6105 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];
6108 int el2panelimg(int element)
6110 element = GFX_ELEMENT(element);
6112 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PANEL];
6115 int font2baseimg(int font_nr)
6117 return font_info[font_nr].special_graphic[GFX_SPECIAL_ARG_DEFAULT];
6120 int getBeltNrFromBeltElement(int element)
6122 return (element < EL_CONVEYOR_BELT_2_LEFT ? 0 :
6123 element < EL_CONVEYOR_BELT_3_LEFT ? 1 :
6124 element < EL_CONVEYOR_BELT_4_LEFT ? 2 : 3);
6127 int getBeltNrFromBeltActiveElement(int element)
6129 return (element < EL_CONVEYOR_BELT_2_LEFT_ACTIVE ? 0 :
6130 element < EL_CONVEYOR_BELT_3_LEFT_ACTIVE ? 1 :
6131 element < EL_CONVEYOR_BELT_4_LEFT_ACTIVE ? 2 : 3);
6134 int getBeltNrFromBeltSwitchElement(int element)
6136 return (element < EL_CONVEYOR_BELT_2_SWITCH_LEFT ? 0 :
6137 element < EL_CONVEYOR_BELT_3_SWITCH_LEFT ? 1 :
6138 element < EL_CONVEYOR_BELT_4_SWITCH_LEFT ? 2 : 3);
6141 int getBeltDirNrFromBeltElement(int element)
6143 static int belt_base_element[4] =
6145 EL_CONVEYOR_BELT_1_LEFT,
6146 EL_CONVEYOR_BELT_2_LEFT,
6147 EL_CONVEYOR_BELT_3_LEFT,
6148 EL_CONVEYOR_BELT_4_LEFT
6151 int belt_nr = getBeltNrFromBeltElement(element);
6152 int belt_dir_nr = element - belt_base_element[belt_nr];
6154 return (belt_dir_nr % 3);
6157 int getBeltDirNrFromBeltSwitchElement(int element)
6159 static int belt_base_element[4] =
6161 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
6162 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
6163 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
6164 EL_CONVEYOR_BELT_4_SWITCH_LEFT
6167 int belt_nr = getBeltNrFromBeltSwitchElement(element);
6168 int belt_dir_nr = element - belt_base_element[belt_nr];
6170 return (belt_dir_nr % 3);
6173 int getBeltDirFromBeltElement(int element)
6175 static int belt_move_dir[3] =
6182 int belt_dir_nr = getBeltDirNrFromBeltElement(element);
6184 return belt_move_dir[belt_dir_nr];
6187 int getBeltDirFromBeltSwitchElement(int element)
6189 static int belt_move_dir[3] =
6196 int belt_dir_nr = getBeltDirNrFromBeltSwitchElement(element);
6198 return belt_move_dir[belt_dir_nr];
6201 int getBeltElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
6203 static int belt_base_element[4] =
6205 EL_CONVEYOR_BELT_1_LEFT,
6206 EL_CONVEYOR_BELT_2_LEFT,
6207 EL_CONVEYOR_BELT_3_LEFT,
6208 EL_CONVEYOR_BELT_4_LEFT
6211 return belt_base_element[belt_nr] + belt_dir_nr;
6214 int getBeltElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
6216 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
6218 return getBeltElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
6221 int getBeltSwitchElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
6223 static int belt_base_element[4] =
6225 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
6226 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
6227 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
6228 EL_CONVEYOR_BELT_4_SWITCH_LEFT
6231 return belt_base_element[belt_nr] + belt_dir_nr;
6234 int getBeltSwitchElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
6236 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
6238 return getBeltSwitchElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
6241 int getNumActivePlayers_EM()
6243 int num_players = 0;
6249 for (i = 0; i < MAX_PLAYERS; i++)
6250 if (tape.player_participates[i])
6256 int getGameFrameDelay_EM(int native_em_game_frame_delay)
6258 int game_frame_delay_value;
6260 game_frame_delay_value =
6261 (tape.playing && tape.fast_forward ? FfwdFrameDelay :
6262 GameFrameDelay == GAME_FRAME_DELAY ? native_em_game_frame_delay :
6265 if (tape.playing && tape.warp_forward && !tape.pausing)
6266 game_frame_delay_value = 0;
6268 return game_frame_delay_value;
6271 unsigned int InitRND(long seed)
6273 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
6274 return InitEngineRandom_EM(seed);
6275 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
6276 return InitEngineRandom_SP(seed);
6278 return InitEngineRandom_RND(seed);
6282 static struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
6283 static struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
6286 inline static int get_effective_element_EM(int tile, int frame_em)
6288 int element = object_mapping[tile].element_rnd;
6289 int action = object_mapping[tile].action;
6290 boolean is_backside = object_mapping[tile].is_backside;
6291 boolean action_removing = (action == ACTION_DIGGING ||
6292 action == ACTION_SNAPPING ||
6293 action == ACTION_COLLECTING);
6299 case Yacid_splash_eB:
6300 case Yacid_splash_wB:
6301 return (frame_em > 5 ? EL_EMPTY : element);
6307 else /* frame_em == 7 */
6311 case Yacid_splash_eB:
6312 case Yacid_splash_wB:
6315 case Yemerald_stone:
6318 case Ydiamond_stone:
6322 case Xdrip_stretchB:
6341 case Xsand_stonein_1:
6342 case Xsand_stonein_2:
6343 case Xsand_stonein_3:
6344 case Xsand_stonein_4:
6348 return (is_backside || action_removing ? EL_EMPTY : element);
6353 inline static boolean check_linear_animation_EM(int tile)
6357 case Xsand_stonesand_1:
6358 case Xsand_stonesand_quickout_1:
6359 case Xsand_sandstone_1:
6360 case Xsand_stonein_1:
6361 case Xsand_stoneout_1:
6386 inline static void set_crumbled_graphics_EM(struct GraphicInfo_EM *g_em,
6387 boolean has_crumbled_graphics,
6388 int crumbled, int sync_frame)
6390 /* if element can be crumbled, but certain action graphics are just empty
6391 space (like instantly snapping sand to empty space in 1 frame), do not
6392 treat these empty space graphics as crumbled graphics in EMC engine */
6393 if (crumbled == IMG_EMPTY_SPACE)
6394 has_crumbled_graphics = FALSE;
6396 if (has_crumbled_graphics)
6398 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
6399 int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
6400 g_crumbled->anim_delay,
6401 g_crumbled->anim_mode,
6402 g_crumbled->anim_start_frame,
6405 getGraphicSource(crumbled, frame_crumbled, &g_em->crumbled_bitmap,
6406 &g_em->crumbled_src_x, &g_em->crumbled_src_y);
6408 g_em->crumbled_border_size = graphic_info[crumbled].border_size;
6410 g_em->has_crumbled_graphics = TRUE;
6414 g_em->crumbled_bitmap = NULL;
6415 g_em->crumbled_src_x = 0;
6416 g_em->crumbled_src_y = 0;
6417 g_em->crumbled_border_size = 0;
6419 g_em->has_crumbled_graphics = FALSE;
6423 void ResetGfxAnimation_EM(int x, int y, int tile)
6428 void SetGfxAnimation_EM(struct GraphicInfo_EM *g_em,
6429 int tile, int frame_em, int x, int y)
6431 int action = object_mapping[tile].action;
6433 int direction = object_mapping[tile].direction;
6434 int effective_element = get_effective_element_EM(tile, frame_em);
6435 int graphic = (direction == MV_NONE ?
6436 el_act2img(effective_element, action) :
6437 el_act_dir2img(effective_element, action, direction));
6438 struct GraphicInfo *g = &graphic_info[graphic];
6441 boolean action_removing = (action == ACTION_DIGGING ||
6442 action == ACTION_SNAPPING ||
6443 action == ACTION_COLLECTING);
6444 boolean action_moving = (action == ACTION_FALLING ||
6445 action == ACTION_MOVING ||
6446 action == ACTION_PUSHING ||
6447 action == ACTION_EATING ||
6448 action == ACTION_FILLING ||
6449 action == ACTION_EMPTYING);
6450 boolean action_falling = (action == ACTION_FALLING ||
6451 action == ACTION_FILLING ||
6452 action == ACTION_EMPTYING);
6454 /* special case: graphic uses "2nd movement tile" and has defined
6455 7 frames for movement animation (or less) => use default graphic
6456 for last (8th) frame which ends the movement animation */
6457 if (g->double_movement && g->anim_frames < 8 && frame_em == 7)
6459 action = ACTION_DEFAULT; /* (keep action_* unchanged for now) */
6460 graphic = (direction == MV_NONE ?
6461 el_act2img(effective_element, action) :
6462 el_act_dir2img(effective_element, action, direction));
6464 g = &graphic_info[graphic];
6468 if (tile == Xsand_stonesand_1 ||
6469 tile == Xsand_stonesand_2 ||
6470 tile == Xsand_stonesand_3 ||
6471 tile == Xsand_stonesand_4)
6472 printf("::: 1: quicksand frame %d [%d]\n", GfxFrame[x][y], tile);
6476 if ((action_removing || check_linear_animation_EM(tile)) && frame_em == 0)
6480 // printf("::: resetting... [%d]\n", tile);
6483 if (action_removing || check_linear_animation_EM(tile))
6485 GfxFrame[x][y] = frame_em;
6487 // printf("::: resetting... [%d]\n", tile);
6490 else if (action_moving)
6492 boolean is_backside = object_mapping[tile].is_backside;
6496 int direction = object_mapping[tile].direction;
6497 int move_dir = (action_falling ? MV_DOWN : direction);
6502 /* !!! TEST !!! NEW !!! DOES NOT WORK RIGHT YET !!! */
6503 if (g->double_movement && frame_em == 0)
6507 // printf("::: resetting... [%d]\n", tile);
6511 if (move_dir == MV_LEFT)
6512 GfxFrame[x - 1][y] = GfxFrame[x][y];
6513 else if (move_dir == MV_RIGHT)
6514 GfxFrame[x + 1][y] = GfxFrame[x][y];
6515 else if (move_dir == MV_UP)
6516 GfxFrame[x][y - 1] = GfxFrame[x][y];
6517 else if (move_dir == MV_DOWN)
6518 GfxFrame[x][y + 1] = GfxFrame[x][y];
6525 /* special case: animation for Xsand_stonesand_quickout_1/2 twice as fast */
6526 if (tile == Xsand_stonesand_quickout_1 ||
6527 tile == Xsand_stonesand_quickout_2)
6532 if (tile == Xsand_stonesand_1 ||
6533 tile == Xsand_stonesand_2 ||
6534 tile == Xsand_stonesand_3 ||
6535 tile == Xsand_stonesand_4)
6536 printf("::: 2: quicksand frame %d [%d]\n", GfxFrame[x][y], tile);
6540 if (graphic_info[graphic].anim_global_sync)
6541 sync_frame = FrameCounter;
6542 else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY))
6543 sync_frame = GfxFrame[x][y];
6545 sync_frame = 0; /* playfield border (pseudo steel) */
6547 SetRandomAnimationValue(x, y);
6549 int frame = getAnimationFrame(g->anim_frames,
6552 g->anim_start_frame,
6555 g_em->unique_identifier =
6556 (graphic << 16) | ((frame % 8) << 12) | (g_em->width << 6) | g_em->height;
6560 void getGraphicSourceObjectExt_EM(struct GraphicInfo_EM *g_em,
6561 int tile, int frame_em, int x, int y)
6563 int action = object_mapping[tile].action;
6564 int direction = object_mapping[tile].direction;
6565 boolean is_backside = object_mapping[tile].is_backside;
6566 int effective_element = get_effective_element_EM(tile, frame_em);
6568 int effective_action = action;
6570 int effective_action = (frame_em < 7 ? action : ACTION_DEFAULT);
6572 int graphic = (direction == MV_NONE ?
6573 el_act2img(effective_element, effective_action) :
6574 el_act_dir2img(effective_element, effective_action,
6576 int crumbled = (direction == MV_NONE ?
6577 el_act2crm(effective_element, effective_action) :
6578 el_act_dir2crm(effective_element, effective_action,
6580 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
6581 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
6582 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
6583 struct GraphicInfo *g = &graphic_info[graphic];
6585 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
6589 /* special case: graphic uses "2nd movement tile" and has defined
6590 7 frames for movement animation (or less) => use default graphic
6591 for last (8th) frame which ends the movement animation */
6592 if (g->double_movement && g->anim_frames < 8 && frame_em == 7)
6594 effective_action = ACTION_DEFAULT;
6595 graphic = (direction == MV_NONE ?
6596 el_act2img(effective_element, effective_action) :
6597 el_act_dir2img(effective_element, effective_action,
6599 crumbled = (direction == MV_NONE ?
6600 el_act2crm(effective_element, effective_action) :
6601 el_act_dir2crm(effective_element, effective_action,
6604 g = &graphic_info[graphic];
6614 if (frame_em == 0) /* reset animation frame for certain elements */
6616 if (check_linear_animation_EM(tile))
6621 if (graphic_info[graphic].anim_global_sync)
6622 sync_frame = FrameCounter;
6623 else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY))
6624 sync_frame = GfxFrame[x][y];
6626 sync_frame = 0; /* playfield border (pseudo steel) */
6628 SetRandomAnimationValue(x, y);
6633 int xxx_sync_frame = (i == Xdrip_stretch ? 7 :
6634 i == Xdrip_stretchB ? 7 :
6635 i == Ydrip_s2 ? j + 8 :
6636 i == Ydrip_s2B ? j + 8 :
6645 i == Xfake_acid_1 ? 0 :
6646 i == Xfake_acid_2 ? 10 :
6647 i == Xfake_acid_3 ? 20 :
6648 i == Xfake_acid_4 ? 30 :
6649 i == Xfake_acid_5 ? 40 :
6650 i == Xfake_acid_6 ? 50 :
6651 i == Xfake_acid_7 ? 60 :
6652 i == Xfake_acid_8 ? 70 :
6654 i == Xball_2B ? j + 8 :
6655 i == Yball_eat ? j + 1 :
6656 i == Ykey_1_eat ? j + 1 :
6657 i == Ykey_2_eat ? j + 1 :
6658 i == Ykey_3_eat ? j + 1 :
6659 i == Ykey_4_eat ? j + 1 :
6660 i == Ykey_5_eat ? j + 1 :
6661 i == Ykey_6_eat ? j + 1 :
6662 i == Ykey_7_eat ? j + 1 :
6663 i == Ykey_8_eat ? j + 1 :
6664 i == Ylenses_eat ? j + 1 :
6665 i == Ymagnify_eat ? j + 1 :
6666 i == Ygrass_eat ? j + 1 :
6667 i == Ydirt_eat ? j + 1 :
6668 i == Xamoeba_1 ? 0 :
6669 i == Xamoeba_2 ? 1 :
6670 i == Xamoeba_3 ? 2 :
6671 i == Xamoeba_4 ? 3 :
6672 i == Xamoeba_5 ? 0 :
6673 i == Xamoeba_6 ? 1 :
6674 i == Xamoeba_7 ? 2 :
6675 i == Xamoeba_8 ? 3 :
6676 i == Xexit_2 ? j + 8 :
6677 i == Xexit_3 ? j + 16 :
6678 i == Xdynamite_1 ? 0 :
6679 i == Xdynamite_2 ? 8 :
6680 i == Xdynamite_3 ? 16 :
6681 i == Xdynamite_4 ? 24 :
6682 i == Xsand_stonein_1 ? j + 1 :
6683 i == Xsand_stonein_2 ? j + 9 :
6684 i == Xsand_stonein_3 ? j + 17 :
6685 i == Xsand_stonein_4 ? j + 25 :
6686 i == Xsand_stoneout_1 && j == 0 ? 0 :
6687 i == Xsand_stoneout_1 && j == 1 ? 0 :
6688 i == Xsand_stoneout_1 && j == 2 ? 1 :
6689 i == Xsand_stoneout_1 && j == 3 ? 2 :
6690 i == Xsand_stoneout_1 && j == 4 ? 2 :
6691 i == Xsand_stoneout_1 && j == 5 ? 3 :
6692 i == Xsand_stoneout_1 && j == 6 ? 4 :
6693 i == Xsand_stoneout_1 && j == 7 ? 4 :
6694 i == Xsand_stoneout_2 && j == 0 ? 5 :
6695 i == Xsand_stoneout_2 && j == 1 ? 6 :
6696 i == Xsand_stoneout_2 && j == 2 ? 7 :
6697 i == Xsand_stoneout_2 && j == 3 ? 8 :
6698 i == Xsand_stoneout_2 && j == 4 ? 9 :
6699 i == Xsand_stoneout_2 && j == 5 ? 11 :
6700 i == Xsand_stoneout_2 && j == 6 ? 13 :
6701 i == Xsand_stoneout_2 && j == 7 ? 15 :
6702 i == Xboom_bug && j == 1 ? 2 :
6703 i == Xboom_bug && j == 2 ? 2 :
6704 i == Xboom_bug && j == 3 ? 4 :
6705 i == Xboom_bug && j == 4 ? 4 :
6706 i == Xboom_bug && j == 5 ? 2 :
6707 i == Xboom_bug && j == 6 ? 2 :
6708 i == Xboom_bug && j == 7 ? 0 :
6709 i == Xboom_bomb && j == 1 ? 2 :
6710 i == Xboom_bomb && j == 2 ? 2 :
6711 i == Xboom_bomb && j == 3 ? 4 :
6712 i == Xboom_bomb && j == 4 ? 4 :
6713 i == Xboom_bomb && j == 5 ? 2 :
6714 i == Xboom_bomb && j == 6 ? 2 :
6715 i == Xboom_bomb && j == 7 ? 0 :
6716 i == Xboom_android && j == 7 ? 6 :
6717 i == Xboom_1 && j == 1 ? 2 :
6718 i == Xboom_1 && j == 2 ? 2 :
6719 i == Xboom_1 && j == 3 ? 4 :
6720 i == Xboom_1 && j == 4 ? 4 :
6721 i == Xboom_1 && j == 5 ? 6 :
6722 i == Xboom_1 && j == 6 ? 6 :
6723 i == Xboom_1 && j == 7 ? 8 :
6724 i == Xboom_2 && j == 0 ? 8 :
6725 i == Xboom_2 && j == 1 ? 8 :
6726 i == Xboom_2 && j == 2 ? 10 :
6727 i == Xboom_2 && j == 3 ? 10 :
6728 i == Xboom_2 && j == 4 ? 10 :
6729 i == Xboom_2 && j == 5 ? 12 :
6730 i == Xboom_2 && j == 6 ? 12 :
6731 i == Xboom_2 && j == 7 ? 12 :
6733 special_animation && j == 4 ? 3 :
6734 effective_action != action ? 0 :
6740 int xxx_effective_action;
6741 int xxx_has_action_graphics;
6744 int element = object_mapping[i].element_rnd;
6745 int action = object_mapping[i].action;
6746 int direction = object_mapping[i].direction;
6747 boolean is_backside = object_mapping[i].is_backside;
6749 boolean action_removing = (action == ACTION_DIGGING ||
6750 action == ACTION_SNAPPING ||
6751 action == ACTION_COLLECTING);
6753 boolean action_exploding = ((action == ACTION_EXPLODING ||
6754 action == ACTION_SMASHED_BY_ROCK ||
6755 action == ACTION_SMASHED_BY_SPRING) &&
6756 element != EL_DIAMOND);
6757 boolean action_active = (action == ACTION_ACTIVE);
6758 boolean action_other = (action == ACTION_OTHER);
6762 int effective_element = get_effective_element_EM(i, j);
6764 int effective_element = (j > 5 && i == Yacid_splash_eB ? EL_EMPTY :
6765 j > 5 && i == Yacid_splash_wB ? EL_EMPTY :
6767 i == Xdrip_stretch ? element :
6768 i == Xdrip_stretchB ? element :
6769 i == Ydrip_s1 ? element :
6770 i == Ydrip_s1B ? element :
6771 i == Xball_1B ? element :
6772 i == Xball_2 ? element :
6773 i == Xball_2B ? element :
6774 i == Yball_eat ? element :
6775 i == Ykey_1_eat ? element :
6776 i == Ykey_2_eat ? element :
6777 i == Ykey_3_eat ? element :
6778 i == Ykey_4_eat ? element :
6779 i == Ykey_5_eat ? element :
6780 i == Ykey_6_eat ? element :
6781 i == Ykey_7_eat ? element :
6782 i == Ykey_8_eat ? element :
6783 i == Ylenses_eat ? element :
6784 i == Ymagnify_eat ? element :
6785 i == Ygrass_eat ? element :
6786 i == Ydirt_eat ? element :
6787 i == Yemerald_stone ? EL_EMERALD :
6788 i == Ydiamond_stone ? EL_ROCK :
6789 i == Xsand_stonein_1 ? element :
6790 i == Xsand_stonein_2 ? element :
6791 i == Xsand_stonein_3 ? element :
6792 i == Xsand_stonein_4 ? element :
6793 is_backside ? EL_EMPTY :
6794 action_removing ? EL_EMPTY :
6797 int effective_action = (j < 7 ? action :
6798 i == Xdrip_stretch ? action :
6799 i == Xdrip_stretchB ? action :
6800 i == Ydrip_s1 ? action :
6801 i == Ydrip_s1B ? action :
6802 i == Xball_1B ? action :
6803 i == Xball_2 ? action :
6804 i == Xball_2B ? action :
6805 i == Yball_eat ? action :
6806 i == Ykey_1_eat ? action :
6807 i == Ykey_2_eat ? action :
6808 i == Ykey_3_eat ? action :
6809 i == Ykey_4_eat ? action :
6810 i == Ykey_5_eat ? action :
6811 i == Ykey_6_eat ? action :
6812 i == Ykey_7_eat ? action :
6813 i == Ykey_8_eat ? action :
6814 i == Ylenses_eat ? action :
6815 i == Ymagnify_eat ? action :
6816 i == Ygrass_eat ? action :
6817 i == Ydirt_eat ? action :
6818 i == Xsand_stonein_1 ? action :
6819 i == Xsand_stonein_2 ? action :
6820 i == Xsand_stonein_3 ? action :
6821 i == Xsand_stonein_4 ? action :
6822 i == Xsand_stoneout_1 ? action :
6823 i == Xsand_stoneout_2 ? action :
6824 i == Xboom_android ? ACTION_EXPLODING :
6825 action_exploding ? ACTION_EXPLODING :
6826 action_active ? action :
6827 action_other ? action :
6829 int graphic = (el_act_dir2img(effective_element, effective_action,
6831 int crumbled = (el_act_dir2crm(effective_element, effective_action,
6833 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
6834 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
6835 boolean has_action_graphics = (graphic != base_graphic);
6836 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
6837 struct GraphicInfo *g = &graphic_info[graphic];
6839 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
6841 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
6844 /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
6845 boolean special_animation = (action != ACTION_DEFAULT &&
6846 g->anim_frames == 3 &&
6847 g->anim_delay == 2 &&
6848 g->anim_mode & ANIM_LINEAR);
6849 xxx_sync_frame = (i == Xdrip_stretch ? 7 :
6850 i == Xdrip_stretchB ? 7 :
6851 i == Ydrip_s2 ? j + 8 :
6852 i == Ydrip_s2B ? j + 8 :
6861 i == Xfake_acid_1 ? 0 :
6862 i == Xfake_acid_2 ? 10 :
6863 i == Xfake_acid_3 ? 20 :
6864 i == Xfake_acid_4 ? 30 :
6865 i == Xfake_acid_5 ? 40 :
6866 i == Xfake_acid_6 ? 50 :
6867 i == Xfake_acid_7 ? 60 :
6868 i == Xfake_acid_8 ? 70 :
6870 i == Xball_2B ? j + 8 :
6871 i == Yball_eat ? j + 1 :
6872 i == Ykey_1_eat ? j + 1 :
6873 i == Ykey_2_eat ? j + 1 :
6874 i == Ykey_3_eat ? j + 1 :
6875 i == Ykey_4_eat ? j + 1 :
6876 i == Ykey_5_eat ? j + 1 :
6877 i == Ykey_6_eat ? j + 1 :
6878 i == Ykey_7_eat ? j + 1 :
6879 i == Ykey_8_eat ? j + 1 :
6880 i == Ylenses_eat ? j + 1 :
6881 i == Ymagnify_eat ? j + 1 :
6882 i == Ygrass_eat ? j + 1 :
6883 i == Ydirt_eat ? j + 1 :
6884 i == Xamoeba_1 ? 0 :
6885 i == Xamoeba_2 ? 1 :
6886 i == Xamoeba_3 ? 2 :
6887 i == Xamoeba_4 ? 3 :
6888 i == Xamoeba_5 ? 0 :
6889 i == Xamoeba_6 ? 1 :
6890 i == Xamoeba_7 ? 2 :
6891 i == Xamoeba_8 ? 3 :
6892 i == Xexit_2 ? j + 8 :
6893 i == Xexit_3 ? j + 16 :
6894 i == Xdynamite_1 ? 0 :
6895 i == Xdynamite_2 ? 8 :
6896 i == Xdynamite_3 ? 16 :
6897 i == Xdynamite_4 ? 24 :
6898 i == Xsand_stonein_1 ? j + 1 :
6899 i == Xsand_stonein_2 ? j + 9 :
6900 i == Xsand_stonein_3 ? j + 17 :
6901 i == Xsand_stonein_4 ? j + 25 :
6902 i == Xsand_stoneout_1 && j == 0 ? 0 :
6903 i == Xsand_stoneout_1 && j == 1 ? 0 :
6904 i == Xsand_stoneout_1 && j == 2 ? 1 :
6905 i == Xsand_stoneout_1 && j == 3 ? 2 :
6906 i == Xsand_stoneout_1 && j == 4 ? 2 :
6907 i == Xsand_stoneout_1 && j == 5 ? 3 :
6908 i == Xsand_stoneout_1 && j == 6 ? 4 :
6909 i == Xsand_stoneout_1 && j == 7 ? 4 :
6910 i == Xsand_stoneout_2 && j == 0 ? 5 :
6911 i == Xsand_stoneout_2 && j == 1 ? 6 :
6912 i == Xsand_stoneout_2 && j == 2 ? 7 :
6913 i == Xsand_stoneout_2 && j == 3 ? 8 :
6914 i == Xsand_stoneout_2 && j == 4 ? 9 :
6915 i == Xsand_stoneout_2 && j == 5 ? 11 :
6916 i == Xsand_stoneout_2 && j == 6 ? 13 :
6917 i == Xsand_stoneout_2 && j == 7 ? 15 :
6918 i == Xboom_bug && j == 1 ? 2 :
6919 i == Xboom_bug && j == 2 ? 2 :
6920 i == Xboom_bug && j == 3 ? 4 :
6921 i == Xboom_bug && j == 4 ? 4 :
6922 i == Xboom_bug && j == 5 ? 2 :
6923 i == Xboom_bug && j == 6 ? 2 :
6924 i == Xboom_bug && j == 7 ? 0 :
6925 i == Xboom_bomb && j == 1 ? 2 :
6926 i == Xboom_bomb && j == 2 ? 2 :
6927 i == Xboom_bomb && j == 3 ? 4 :
6928 i == Xboom_bomb && j == 4 ? 4 :
6929 i == Xboom_bomb && j == 5 ? 2 :
6930 i == Xboom_bomb && j == 6 ? 2 :
6931 i == Xboom_bomb && j == 7 ? 0 :
6932 i == Xboom_android && j == 7 ? 6 :
6933 i == Xboom_1 && j == 1 ? 2 :
6934 i == Xboom_1 && j == 2 ? 2 :
6935 i == Xboom_1 && j == 3 ? 4 :
6936 i == Xboom_1 && j == 4 ? 4 :
6937 i == Xboom_1 && j == 5 ? 6 :
6938 i == Xboom_1 && j == 6 ? 6 :
6939 i == Xboom_1 && j == 7 ? 8 :
6940 i == Xboom_2 && j == 0 ? 8 :
6941 i == Xboom_2 && j == 1 ? 8 :
6942 i == Xboom_2 && j == 2 ? 10 :
6943 i == Xboom_2 && j == 3 ? 10 :
6944 i == Xboom_2 && j == 4 ? 10 :
6945 i == Xboom_2 && j == 5 ? 12 :
6946 i == Xboom_2 && j == 6 ? 12 :
6947 i == Xboom_2 && j == 7 ? 12 :
6948 special_animation && j == 4 ? 3 :
6949 effective_action != action ? 0 :
6952 xxx_effective_action = effective_action;
6953 xxx_has_action_graphics = has_action_graphics;
6958 int frame = getAnimationFrame(g->anim_frames,
6961 g->anim_start_frame,
6975 int old_src_x = g_em->src_x;
6976 int old_src_y = g_em->src_y;
6980 getGraphicSourceExt(graphic, frame, &g_em->bitmap, &g_em->src_x, &g_em->src_y,
6981 g->double_movement && is_backside);
6983 getGraphicSourceExt(graphic, frame, &g_em->bitmap,
6984 &g_em->src_x, &g_em->src_y, FALSE);
6995 if (graphic == IMG_BUG_MOVING_RIGHT)
6996 printf("::: %d, %d, %d: %d, %d [%d, %d -> %d, %d]\n", graphic, x, y,
6997 g->double_movement, is_backside,
6998 old_src_x, old_src_y, g_em->src_x, g_em->src_y);
7006 g_em->src_offset_x = 0;
7007 g_em->src_offset_y = 0;
7008 g_em->dst_offset_x = 0;
7009 g_em->dst_offset_y = 0;
7010 g_em->width = TILEX;
7011 g_em->height = TILEY;
7013 g_em->preserve_background = FALSE;
7016 /* (updating the "crumbled" graphic definitions is probably not really needed,
7017 as animations for crumbled graphics can't be longer than one EMC cycle) */
7019 set_crumbled_graphics_EM(g_em, has_crumbled_graphics, crumbled,
7024 g_em->crumbled_bitmap = NULL;
7025 g_em->crumbled_src_x = 0;
7026 g_em->crumbled_src_y = 0;
7028 g_em->has_crumbled_graphics = FALSE;
7030 if (has_crumbled_graphics && crumbled != IMG_EMPTY_SPACE)
7032 int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
7033 g_crumbled->anim_delay,
7034 g_crumbled->anim_mode,
7035 g_crumbled->anim_start_frame,
7038 getGraphicSource(crumbled, frame_crumbled, &g_em->crumbled_bitmap,
7039 &g_em->crumbled_src_x, &g_em->crumbled_src_y);
7041 g_em->has_crumbled_graphics = TRUE;
7047 int effective_action = xxx_effective_action;
7048 int has_action_graphics = xxx_has_action_graphics;
7050 if ((!g->double_movement && (effective_action == ACTION_FALLING ||
7051 effective_action == ACTION_MOVING ||
7052 effective_action == ACTION_PUSHING ||
7053 effective_action == ACTION_EATING)) ||
7054 (!has_action_graphics && (effective_action == ACTION_FILLING ||
7055 effective_action == ACTION_EMPTYING)))
7058 (effective_action == ACTION_FALLING ||
7059 effective_action == ACTION_FILLING ||
7060 effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
7061 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
7062 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? 1 : 0);
7063 int num_steps = (i == Ydrip_s1 ? 16 :
7064 i == Ydrip_s1B ? 16 :
7065 i == Ydrip_s2 ? 16 :
7066 i == Ydrip_s2B ? 16 :
7067 i == Xsand_stonein_1 ? 32 :
7068 i == Xsand_stonein_2 ? 32 :
7069 i == Xsand_stonein_3 ? 32 :
7070 i == Xsand_stonein_4 ? 32 :
7071 i == Xsand_stoneout_1 ? 16 :
7072 i == Xsand_stoneout_2 ? 16 : 8);
7073 int cx = ABS(dx) * (TILEX / num_steps);
7074 int cy = ABS(dy) * (TILEY / num_steps);
7075 int step_frame = (i == Ydrip_s2 ? j + 8 :
7076 i == Ydrip_s2B ? j + 8 :
7077 i == Xsand_stonein_2 ? j + 8 :
7078 i == Xsand_stonein_3 ? j + 16 :
7079 i == Xsand_stonein_4 ? j + 24 :
7080 i == Xsand_stoneout_2 ? j + 8 : j) + 1;
7081 int step = (is_backside ? step_frame : num_steps - step_frame);
7083 if (is_backside) /* tile where movement starts */
7085 if (dx < 0 || dy < 0)
7087 g_em->src_offset_x = cx * step;
7088 g_em->src_offset_y = cy * step;
7092 g_em->dst_offset_x = cx * step;
7093 g_em->dst_offset_y = cy * step;
7096 else /* tile where movement ends */
7098 if (dx < 0 || dy < 0)
7100 g_em->dst_offset_x = cx * step;
7101 g_em->dst_offset_y = cy * step;
7105 g_em->src_offset_x = cx * step;
7106 g_em->src_offset_y = cy * step;
7110 g_em->width = TILEX - cx * step;
7111 g_em->height = TILEY - cy * step;
7114 /* create unique graphic identifier to decide if tile must be redrawn */
7115 /* bit 31 - 16 (16 bit): EM style graphic
7116 bit 15 - 12 ( 4 bit): EM style frame
7117 bit 11 - 6 ( 6 bit): graphic width
7118 bit 5 - 0 ( 6 bit): graphic height */
7119 g_em->unique_identifier =
7120 (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
7126 void getGraphicSourcePlayerExt_EM(struct GraphicInfo_EM *g_em,
7127 int player_nr, int anim, int frame_em)
7129 int element = player_mapping[player_nr][anim].element_rnd;
7130 int action = player_mapping[player_nr][anim].action;
7131 int direction = player_mapping[player_nr][anim].direction;
7132 int graphic = (direction == MV_NONE ?
7133 el_act2img(element, action) :
7134 el_act_dir2img(element, action, direction));
7135 struct GraphicInfo *g = &graphic_info[graphic];
7138 InitPlayerGfxAnimation(&stored_player[player_nr], action, direction);
7140 stored_player[player_nr].StepFrame = frame_em;
7142 sync_frame = stored_player[player_nr].Frame;
7144 int frame = getAnimationFrame(g->anim_frames,
7147 g->anim_start_frame,
7150 getGraphicSourceExt(graphic, frame, &g_em->bitmap,
7151 &g_em->src_x, &g_em->src_y, FALSE);
7154 printf("::: %d: %d, %d [%d]\n",
7156 stored_player[player_nr].Frame,
7157 stored_player[player_nr].StepFrame,
7162 void InitGraphicInfo_EM(void)
7165 struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
7166 struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
7171 int num_em_gfx_errors = 0;
7173 if (graphic_info_em_object[0][0].bitmap == NULL)
7175 /* EM graphics not yet initialized in em_open_all() */
7180 printf("::: [4 errors can be ignored (1 x 'bomb', 3 x 'em_dynamite']\n");
7183 /* always start with reliable default values */
7184 for (i = 0; i < TILE_MAX; i++)
7186 object_mapping[i].element_rnd = EL_UNKNOWN;
7187 object_mapping[i].is_backside = FALSE;
7188 object_mapping[i].action = ACTION_DEFAULT;
7189 object_mapping[i].direction = MV_NONE;
7192 /* always start with reliable default values */
7193 for (p = 0; p < MAX_PLAYERS; p++)
7195 for (i = 0; i < SPR_MAX; i++)
7197 player_mapping[p][i].element_rnd = EL_UNKNOWN;
7198 player_mapping[p][i].action = ACTION_DEFAULT;
7199 player_mapping[p][i].direction = MV_NONE;
7203 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
7205 int e = em_object_mapping_list[i].element_em;
7207 object_mapping[e].element_rnd = em_object_mapping_list[i].element_rnd;
7208 object_mapping[e].is_backside = em_object_mapping_list[i].is_backside;
7210 if (em_object_mapping_list[i].action != -1)
7211 object_mapping[e].action = em_object_mapping_list[i].action;
7213 if (em_object_mapping_list[i].direction != -1)
7214 object_mapping[e].direction =
7215 MV_DIR_FROM_BIT(em_object_mapping_list[i].direction);
7218 for (i = 0; em_player_mapping_list[i].action_em != -1; i++)
7220 int a = em_player_mapping_list[i].action_em;
7221 int p = em_player_mapping_list[i].player_nr;
7223 player_mapping[p][a].element_rnd = em_player_mapping_list[i].element_rnd;
7225 if (em_player_mapping_list[i].action != -1)
7226 player_mapping[p][a].action = em_player_mapping_list[i].action;
7228 if (em_player_mapping_list[i].direction != -1)
7229 player_mapping[p][a].direction =
7230 MV_DIR_FROM_BIT(em_player_mapping_list[i].direction);
7233 for (i = 0; i < TILE_MAX; i++)
7235 int element = object_mapping[i].element_rnd;
7236 int action = object_mapping[i].action;
7237 int direction = object_mapping[i].direction;
7238 boolean is_backside = object_mapping[i].is_backside;
7240 boolean action_removing = (action == ACTION_DIGGING ||
7241 action == ACTION_SNAPPING ||
7242 action == ACTION_COLLECTING);
7244 boolean action_exploding = ((action == ACTION_EXPLODING ||
7245 action == ACTION_SMASHED_BY_ROCK ||
7246 action == ACTION_SMASHED_BY_SPRING) &&
7247 element != EL_DIAMOND);
7248 boolean action_active = (action == ACTION_ACTIVE);
7249 boolean action_other = (action == ACTION_OTHER);
7251 for (j = 0; j < 8; j++)
7254 int effective_element = get_effective_element_EM(i, j);
7256 int effective_element = (j > 5 && i == Yacid_splash_eB ? EL_EMPTY :
7257 j > 5 && i == Yacid_splash_wB ? EL_EMPTY :
7259 i == Xdrip_stretch ? element :
7260 i == Xdrip_stretchB ? element :
7261 i == Ydrip_s1 ? element :
7262 i == Ydrip_s1B ? element :
7263 i == Xball_1B ? element :
7264 i == Xball_2 ? element :
7265 i == Xball_2B ? element :
7266 i == Yball_eat ? element :
7267 i == Ykey_1_eat ? element :
7268 i == Ykey_2_eat ? element :
7269 i == Ykey_3_eat ? element :
7270 i == Ykey_4_eat ? element :
7271 i == Ykey_5_eat ? element :
7272 i == Ykey_6_eat ? element :
7273 i == Ykey_7_eat ? element :
7274 i == Ykey_8_eat ? element :
7275 i == Ylenses_eat ? element :
7276 i == Ymagnify_eat ? element :
7277 i == Ygrass_eat ? element :
7278 i == Ydirt_eat ? element :
7279 i == Yemerald_stone ? EL_EMERALD :
7280 i == Ydiamond_stone ? EL_ROCK :
7281 i == Xsand_stonein_1 ? element :
7282 i == Xsand_stonein_2 ? element :
7283 i == Xsand_stonein_3 ? element :
7284 i == Xsand_stonein_4 ? element :
7285 is_backside ? EL_EMPTY :
7286 action_removing ? EL_EMPTY :
7289 int effective_action = (j < 7 ? action :
7290 i == Xdrip_stretch ? action :
7291 i == Xdrip_stretchB ? action :
7292 i == Ydrip_s1 ? action :
7293 i == Ydrip_s1B ? action :
7294 i == Xball_1B ? action :
7295 i == Xball_2 ? action :
7296 i == Xball_2B ? action :
7297 i == Yball_eat ? action :
7298 i == Ykey_1_eat ? action :
7299 i == Ykey_2_eat ? action :
7300 i == Ykey_3_eat ? action :
7301 i == Ykey_4_eat ? action :
7302 i == Ykey_5_eat ? action :
7303 i == Ykey_6_eat ? action :
7304 i == Ykey_7_eat ? action :
7305 i == Ykey_8_eat ? action :
7306 i == Ylenses_eat ? action :
7307 i == Ymagnify_eat ? action :
7308 i == Ygrass_eat ? action :
7309 i == Ydirt_eat ? action :
7310 i == Xsand_stonein_1 ? action :
7311 i == Xsand_stonein_2 ? action :
7312 i == Xsand_stonein_3 ? action :
7313 i == Xsand_stonein_4 ? action :
7314 i == Xsand_stoneout_1 ? action :
7315 i == Xsand_stoneout_2 ? action :
7316 i == Xboom_android ? ACTION_EXPLODING :
7317 action_exploding ? ACTION_EXPLODING :
7318 action_active ? action :
7319 action_other ? action :
7321 int graphic = (el_act_dir2img(effective_element, effective_action,
7323 int crumbled = (el_act_dir2crm(effective_element, effective_action,
7325 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
7326 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
7327 boolean has_action_graphics = (graphic != base_graphic);
7328 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
7329 struct GraphicInfo *g = &graphic_info[graphic];
7331 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
7333 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
7336 /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
7337 boolean special_animation = (action != ACTION_DEFAULT &&
7338 g->anim_frames == 3 &&
7339 g->anim_delay == 2 &&
7340 g->anim_mode & ANIM_LINEAR);
7341 int sync_frame = (i == Xdrip_stretch ? 7 :
7342 i == Xdrip_stretchB ? 7 :
7343 i == Ydrip_s2 ? j + 8 :
7344 i == Ydrip_s2B ? j + 8 :
7353 i == Xfake_acid_1 ? 0 :
7354 i == Xfake_acid_2 ? 10 :
7355 i == Xfake_acid_3 ? 20 :
7356 i == Xfake_acid_4 ? 30 :
7357 i == Xfake_acid_5 ? 40 :
7358 i == Xfake_acid_6 ? 50 :
7359 i == Xfake_acid_7 ? 60 :
7360 i == Xfake_acid_8 ? 70 :
7362 i == Xball_2B ? j + 8 :
7363 i == Yball_eat ? j + 1 :
7364 i == Ykey_1_eat ? j + 1 :
7365 i == Ykey_2_eat ? j + 1 :
7366 i == Ykey_3_eat ? j + 1 :
7367 i == Ykey_4_eat ? j + 1 :
7368 i == Ykey_5_eat ? j + 1 :
7369 i == Ykey_6_eat ? j + 1 :
7370 i == Ykey_7_eat ? j + 1 :
7371 i == Ykey_8_eat ? j + 1 :
7372 i == Ylenses_eat ? j + 1 :
7373 i == Ymagnify_eat ? j + 1 :
7374 i == Ygrass_eat ? j + 1 :
7375 i == Ydirt_eat ? j + 1 :
7376 i == Xamoeba_1 ? 0 :
7377 i == Xamoeba_2 ? 1 :
7378 i == Xamoeba_3 ? 2 :
7379 i == Xamoeba_4 ? 3 :
7380 i == Xamoeba_5 ? 0 :
7381 i == Xamoeba_6 ? 1 :
7382 i == Xamoeba_7 ? 2 :
7383 i == Xamoeba_8 ? 3 :
7384 i == Xexit_2 ? j + 8 :
7385 i == Xexit_3 ? j + 16 :
7386 i == Xdynamite_1 ? 0 :
7387 i == Xdynamite_2 ? 8 :
7388 i == Xdynamite_3 ? 16 :
7389 i == Xdynamite_4 ? 24 :
7390 i == Xsand_stonein_1 ? j + 1 :
7391 i == Xsand_stonein_2 ? j + 9 :
7392 i == Xsand_stonein_3 ? j + 17 :
7393 i == Xsand_stonein_4 ? j + 25 :
7394 i == Xsand_stoneout_1 && j == 0 ? 0 :
7395 i == Xsand_stoneout_1 && j == 1 ? 0 :
7396 i == Xsand_stoneout_1 && j == 2 ? 1 :
7397 i == Xsand_stoneout_1 && j == 3 ? 2 :
7398 i == Xsand_stoneout_1 && j == 4 ? 2 :
7399 i == Xsand_stoneout_1 && j == 5 ? 3 :
7400 i == Xsand_stoneout_1 && j == 6 ? 4 :
7401 i == Xsand_stoneout_1 && j == 7 ? 4 :
7402 i == Xsand_stoneout_2 && j == 0 ? 5 :
7403 i == Xsand_stoneout_2 && j == 1 ? 6 :
7404 i == Xsand_stoneout_2 && j == 2 ? 7 :
7405 i == Xsand_stoneout_2 && j == 3 ? 8 :
7406 i == Xsand_stoneout_2 && j == 4 ? 9 :
7407 i == Xsand_stoneout_2 && j == 5 ? 11 :
7408 i == Xsand_stoneout_2 && j == 6 ? 13 :
7409 i == Xsand_stoneout_2 && j == 7 ? 15 :
7410 i == Xboom_bug && j == 1 ? 2 :
7411 i == Xboom_bug && j == 2 ? 2 :
7412 i == Xboom_bug && j == 3 ? 4 :
7413 i == Xboom_bug && j == 4 ? 4 :
7414 i == Xboom_bug && j == 5 ? 2 :
7415 i == Xboom_bug && j == 6 ? 2 :
7416 i == Xboom_bug && j == 7 ? 0 :
7417 i == Xboom_bomb && j == 1 ? 2 :
7418 i == Xboom_bomb && j == 2 ? 2 :
7419 i == Xboom_bomb && j == 3 ? 4 :
7420 i == Xboom_bomb && j == 4 ? 4 :
7421 i == Xboom_bomb && j == 5 ? 2 :
7422 i == Xboom_bomb && j == 6 ? 2 :
7423 i == Xboom_bomb && j == 7 ? 0 :
7424 i == Xboom_android && j == 7 ? 6 :
7425 i == Xboom_1 && j == 1 ? 2 :
7426 i == Xboom_1 && j == 2 ? 2 :
7427 i == Xboom_1 && j == 3 ? 4 :
7428 i == Xboom_1 && j == 4 ? 4 :
7429 i == Xboom_1 && j == 5 ? 6 :
7430 i == Xboom_1 && j == 6 ? 6 :
7431 i == Xboom_1 && j == 7 ? 8 :
7432 i == Xboom_2 && j == 0 ? 8 :
7433 i == Xboom_2 && j == 1 ? 8 :
7434 i == Xboom_2 && j == 2 ? 10 :
7435 i == Xboom_2 && j == 3 ? 10 :
7436 i == Xboom_2 && j == 4 ? 10 :
7437 i == Xboom_2 && j == 5 ? 12 :
7438 i == Xboom_2 && j == 6 ? 12 :
7439 i == Xboom_2 && j == 7 ? 12 :
7440 special_animation && j == 4 ? 3 :
7441 effective_action != action ? 0 :
7445 Bitmap *debug_bitmap = g_em->bitmap;
7446 int debug_src_x = g_em->src_x;
7447 int debug_src_y = g_em->src_y;
7450 int frame = getAnimationFrame(g->anim_frames,
7453 g->anim_start_frame,
7456 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y,
7457 g->double_movement && is_backside);
7459 g_em->bitmap = src_bitmap;
7460 g_em->src_x = src_x;
7461 g_em->src_y = src_y;
7462 g_em->src_offset_x = 0;
7463 g_em->src_offset_y = 0;
7464 g_em->dst_offset_x = 0;
7465 g_em->dst_offset_y = 0;
7466 g_em->width = TILEX;
7467 g_em->height = TILEY;
7469 g_em->preserve_background = FALSE;
7472 set_crumbled_graphics_EM(g_em, has_crumbled_graphics, crumbled,
7477 g_em->crumbled_bitmap = NULL;
7478 g_em->crumbled_src_x = 0;
7479 g_em->crumbled_src_y = 0;
7480 g_em->crumbled_border_size = 0;
7482 g_em->has_crumbled_graphics = FALSE;
7485 if (has_crumbled_graphics && crumbled == IMG_EMPTY_SPACE)
7486 printf("::: empty crumbled: %d [%s], %d, %d\n",
7487 effective_element, element_info[effective_element].token_name,
7488 effective_action, direction);
7491 /* if element can be crumbled, but certain action graphics are just empty
7492 space (like instantly snapping sand to empty space in 1 frame), do not
7493 treat these empty space graphics as crumbled graphics in EMC engine */
7494 if (has_crumbled_graphics && crumbled != IMG_EMPTY_SPACE)
7496 int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
7497 g_crumbled->anim_delay,
7498 g_crumbled->anim_mode,
7499 g_crumbled->anim_start_frame,
7502 getGraphicSource(crumbled, frame_crumbled, &src_bitmap, &src_x, &src_y);
7504 g_em->has_crumbled_graphics = TRUE;
7505 g_em->crumbled_bitmap = src_bitmap;
7506 g_em->crumbled_src_x = src_x;
7507 g_em->crumbled_src_y = src_y;
7508 g_em->crumbled_border_size = graphic_info[crumbled].border_size;
7512 if (g_em == &graphic_info_em_object[207][0])
7513 printf("... %d, %d [%d, %d, %d, %d] [%d, %d, %d, %d, %d, %d => %d]\n",
7514 graphic_info_em_object[207][0].crumbled_src_x,
7515 graphic_info_em_object[207][0].crumbled_src_y,
7517 crumbled, frame, src_x, src_y,
7522 g->anim_start_frame,
7524 gfx.anim_random_frame,
7529 printf("::: EMC tile %d is crumbled\n", i);
7535 if (element == EL_ROCK &&
7536 effective_action == ACTION_FILLING)
7537 printf("::: has_action_graphics == %d\n", has_action_graphics);
7540 if ((!g->double_movement && (effective_action == ACTION_FALLING ||
7541 effective_action == ACTION_MOVING ||
7542 effective_action == ACTION_PUSHING ||
7543 effective_action == ACTION_EATING)) ||
7544 (!has_action_graphics && (effective_action == ACTION_FILLING ||
7545 effective_action == ACTION_EMPTYING)))
7548 (effective_action == ACTION_FALLING ||
7549 effective_action == ACTION_FILLING ||
7550 effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
7551 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
7552 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? 1 : 0);
7553 int num_steps = (i == Ydrip_s1 ? 16 :
7554 i == Ydrip_s1B ? 16 :
7555 i == Ydrip_s2 ? 16 :
7556 i == Ydrip_s2B ? 16 :
7557 i == Xsand_stonein_1 ? 32 :
7558 i == Xsand_stonein_2 ? 32 :
7559 i == Xsand_stonein_3 ? 32 :
7560 i == Xsand_stonein_4 ? 32 :
7561 i == Xsand_stoneout_1 ? 16 :
7562 i == Xsand_stoneout_2 ? 16 : 8);
7563 int cx = ABS(dx) * (TILEX / num_steps);
7564 int cy = ABS(dy) * (TILEY / num_steps);
7565 int step_frame = (i == Ydrip_s2 ? j + 8 :
7566 i == Ydrip_s2B ? j + 8 :
7567 i == Xsand_stonein_2 ? j + 8 :
7568 i == Xsand_stonein_3 ? j + 16 :
7569 i == Xsand_stonein_4 ? j + 24 :
7570 i == Xsand_stoneout_2 ? j + 8 : j) + 1;
7571 int step = (is_backside ? step_frame : num_steps - step_frame);
7573 if (is_backside) /* tile where movement starts */
7575 if (dx < 0 || dy < 0)
7577 g_em->src_offset_x = cx * step;
7578 g_em->src_offset_y = cy * step;
7582 g_em->dst_offset_x = cx * step;
7583 g_em->dst_offset_y = cy * step;
7586 else /* tile where movement ends */
7588 if (dx < 0 || dy < 0)
7590 g_em->dst_offset_x = cx * step;
7591 g_em->dst_offset_y = cy * step;
7595 g_em->src_offset_x = cx * step;
7596 g_em->src_offset_y = cy * step;
7600 g_em->width = TILEX - cx * step;
7601 g_em->height = TILEY - cy * step;
7604 /* create unique graphic identifier to decide if tile must be redrawn */
7605 /* bit 31 - 16 (16 bit): EM style graphic
7606 bit 15 - 12 ( 4 bit): EM style frame
7607 bit 11 - 6 ( 6 bit): graphic width
7608 bit 5 - 0 ( 6 bit): graphic height */
7609 g_em->unique_identifier =
7610 (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
7614 /* skip check for EMC elements not contained in original EMC artwork */
7615 if (element == EL_EMC_FAKE_ACID)
7618 if (g_em->bitmap != debug_bitmap ||
7619 g_em->src_x != debug_src_x ||
7620 g_em->src_y != debug_src_y ||
7621 g_em->src_offset_x != 0 ||
7622 g_em->src_offset_y != 0 ||
7623 g_em->dst_offset_x != 0 ||
7624 g_em->dst_offset_y != 0 ||
7625 g_em->width != TILEX ||
7626 g_em->height != TILEY)
7628 static int last_i = -1;
7636 printf("::: EMC GFX ERROR for element %d -> %d ('%s', '%s', %d)",
7637 i, element, element_info[element].token_name,
7638 element_action_info[effective_action].suffix, direction);
7640 if (element != effective_element)
7641 printf(" [%d ('%s')]",
7643 element_info[effective_element].token_name);
7647 if (g_em->bitmap != debug_bitmap)
7648 printf(" %d (%d): different bitmap! (0x%08x != 0x%08x)\n",
7649 j, is_backside, (int)(g_em->bitmap), (int)(debug_bitmap));
7651 if (g_em->src_x != debug_src_x ||
7652 g_em->src_y != debug_src_y)
7653 printf(" frame %d (%c): %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
7654 j, (is_backside ? 'B' : 'F'),
7655 g_em->src_x, g_em->src_y,
7656 g_em->src_x / 32, g_em->src_y / 32,
7657 debug_src_x, debug_src_y,
7658 debug_src_x / 32, debug_src_y / 32);
7660 if (g_em->src_offset_x != 0 ||
7661 g_em->src_offset_y != 0 ||
7662 g_em->dst_offset_x != 0 ||
7663 g_em->dst_offset_y != 0)
7664 printf(" %d (%d): offsets %d,%d and %d,%d should be all 0\n",
7666 g_em->src_offset_x, g_em->src_offset_y,
7667 g_em->dst_offset_x, g_em->dst_offset_y);
7669 if (g_em->width != TILEX ||
7670 g_em->height != TILEY)
7671 printf(" %d (%d): size %d,%d should be %d,%d\n",
7673 g_em->width, g_em->height, TILEX, TILEY);
7675 num_em_gfx_errors++;
7682 for (i = 0; i < TILE_MAX; i++)
7684 for (j = 0; j < 8; j++)
7686 int element = object_mapping[i].element_rnd;
7687 int action = object_mapping[i].action;
7688 int direction = object_mapping[i].direction;
7689 boolean is_backside = object_mapping[i].is_backside;
7690 int graphic_action = el_act_dir2img(element, action, direction);
7691 int graphic_default = el_act_dir2img(element, ACTION_DEFAULT, direction);
7693 if ((action == ACTION_SMASHED_BY_ROCK ||
7694 action == ACTION_SMASHED_BY_SPRING ||
7695 action == ACTION_EATING) &&
7696 graphic_action == graphic_default)
7698 int e = (action == ACTION_SMASHED_BY_ROCK ? Ystone_s :
7699 action == ACTION_SMASHED_BY_SPRING ? Yspring_s :
7700 direction == MV_LEFT ? (is_backside? Yspring_wB: Yspring_w) :
7701 direction == MV_RIGHT ? (is_backside? Yspring_eB: Yspring_e) :
7704 /* no separate animation for "smashed by rock" -- use rock instead */
7705 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
7706 struct GraphicInfo_EM *g_xx = &graphic_info_em_object[e][7 - j];
7708 g_em->bitmap = g_xx->bitmap;
7709 g_em->src_x = g_xx->src_x;
7710 g_em->src_y = g_xx->src_y;
7711 g_em->src_offset_x = g_xx->src_offset_x;
7712 g_em->src_offset_y = g_xx->src_offset_y;
7713 g_em->dst_offset_x = g_xx->dst_offset_x;
7714 g_em->dst_offset_y = g_xx->dst_offset_y;
7715 g_em->width = g_xx->width;
7716 g_em->height = g_xx->height;
7717 g_em->unique_identifier = g_xx->unique_identifier;
7720 g_em->preserve_background = TRUE;
7725 for (p = 0; p < MAX_PLAYERS; p++)
7727 for (i = 0; i < SPR_MAX; i++)
7729 int element = player_mapping[p][i].element_rnd;
7730 int action = player_mapping[p][i].action;
7731 int direction = player_mapping[p][i].direction;
7733 for (j = 0; j < 8; j++)
7735 int effective_element = element;
7736 int effective_action = action;
7737 int graphic = (direction == MV_NONE ?
7738 el_act2img(effective_element, effective_action) :
7739 el_act_dir2img(effective_element, effective_action,
7741 struct GraphicInfo *g = &graphic_info[graphic];
7742 struct GraphicInfo_EM *g_em = &graphic_info_em_player[p][i][7 - j];
7748 Bitmap *debug_bitmap = g_em->bitmap;
7749 int debug_src_x = g_em->src_x;
7750 int debug_src_y = g_em->src_y;
7753 int frame = getAnimationFrame(g->anim_frames,
7756 g->anim_start_frame,
7759 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
7761 g_em->bitmap = src_bitmap;
7762 g_em->src_x = src_x;
7763 g_em->src_y = src_y;
7764 g_em->src_offset_x = 0;
7765 g_em->src_offset_y = 0;
7766 g_em->dst_offset_x = 0;
7767 g_em->dst_offset_y = 0;
7768 g_em->width = TILEX;
7769 g_em->height = TILEY;
7773 /* skip check for EMC elements not contained in original EMC artwork */
7774 if (element == EL_PLAYER_3 ||
7775 element == EL_PLAYER_4)
7778 if (g_em->bitmap != debug_bitmap ||
7779 g_em->src_x != debug_src_x ||
7780 g_em->src_y != debug_src_y)
7782 static int last_i = -1;
7790 printf("::: EMC GFX ERROR for p/a %d/%d -> %d ('%s', '%s', %d)",
7791 p, i, element, element_info[element].token_name,
7792 element_action_info[effective_action].suffix, direction);
7794 if (element != effective_element)
7795 printf(" [%d ('%s')]",
7797 element_info[effective_element].token_name);
7801 if (g_em->bitmap != debug_bitmap)
7802 printf(" %d: different bitmap! (0x%08x != 0x%08x)\n",
7803 j, (int)(g_em->bitmap), (int)(debug_bitmap));
7805 if (g_em->src_x != debug_src_x ||
7806 g_em->src_y != debug_src_y)
7807 printf(" frame %d: %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
7809 g_em->src_x, g_em->src_y,
7810 g_em->src_x / 32, g_em->src_y / 32,
7811 debug_src_x, debug_src_y,
7812 debug_src_x / 32, debug_src_y / 32);
7814 num_em_gfx_errors++;
7824 printf("::: [%d errors found]\n", num_em_gfx_errors);
7830 void getGraphicSource_SP(struct GraphicInfo_SP *g_sp,
7831 int graphic, int sync_frame, int x, int y)
7833 int frame = getGraphicAnimationFrame(graphic, sync_frame);
7835 getGraphicSource(graphic, frame, &g_sp->bitmap, &g_sp->src_x, &g_sp->src_y);
7838 boolean isNextAnimationFrame_SP(int graphic, int sync_frame)
7840 return (IS_NEXT_FRAME(sync_frame, graphic));
7843 int getGraphicInfo_Delay(int graphic)
7845 return graphic_info[graphic].anim_delay;
7848 void PlayMenuSoundExt(int sound)
7850 if (sound == SND_UNDEFINED)
7853 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
7854 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
7857 if (IS_LOOP_SOUND(sound))
7858 PlaySoundLoop(sound);
7863 void PlayMenuSound()
7865 PlayMenuSoundExt(menu.sound[game_status]);
7868 void PlayMenuSoundStereo(int sound, int stereo_position)
7870 if (sound == SND_UNDEFINED)
7873 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
7874 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
7877 if (IS_LOOP_SOUND(sound))
7878 PlaySoundExt(sound, SOUND_MAX_VOLUME, stereo_position, SND_CTRL_PLAY_LOOP);
7880 PlaySoundStereo(sound, stereo_position);
7883 void PlayMenuSoundIfLoopExt(int sound)
7885 if (sound == SND_UNDEFINED)
7888 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
7889 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
7892 if (IS_LOOP_SOUND(sound))
7893 PlaySoundLoop(sound);
7896 void PlayMenuSoundIfLoop()
7898 PlayMenuSoundIfLoopExt(menu.sound[game_status]);
7901 void PlayMenuMusicExt(int music)
7903 if (music == MUS_UNDEFINED)
7906 if (!setup.sound_music)
7912 void PlayMenuMusic()
7914 PlayMenuMusicExt(menu.music[game_status]);
7917 void PlaySoundActivating()
7920 PlaySound(SND_MENU_ITEM_ACTIVATING);
7924 void PlaySoundSelecting()
7927 PlaySound(SND_MENU_ITEM_SELECTING);
7931 void ToggleFullscreenIfNeeded()
7933 boolean change_fullscreen = (setup.fullscreen !=
7934 video.fullscreen_enabled);
7935 boolean change_fullscreen_mode = (video.fullscreen_enabled &&
7936 !strEqual(setup.fullscreen_mode,
7937 video.fullscreen_mode_current));
7939 if (!video.fullscreen_available)
7943 if (change_fullscreen || change_fullscreen_mode)
7945 if (setup.fullscreen != video.fullscreen_enabled ||
7946 setup.fullscreen_mode != video.fullscreen_mode_current)
7949 Bitmap *tmp_backbuffer = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
7951 /* save backbuffer content which gets lost when toggling fullscreen mode */
7952 BlitBitmap(backbuffer, tmp_backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
7955 if (change_fullscreen_mode)
7957 if (setup.fullscreen && video.fullscreen_enabled)
7960 /* keep fullscreen, but change fullscreen mode (screen resolution) */
7962 /* (this is now set in sdl.c) */
7964 video.fullscreen_mode_current = setup.fullscreen_mode;
7966 video.fullscreen_enabled = FALSE; /* force new fullscreen mode */
7969 /* toggle fullscreen */
7970 ChangeVideoModeIfNeeded(setup.fullscreen);
7972 setup.fullscreen = video.fullscreen_enabled;
7974 /* restore backbuffer content from temporary backbuffer backup bitmap */
7975 BlitBitmap(tmp_backbuffer, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
7977 FreeBitmap(tmp_backbuffer);
7980 /* update visible window/screen */
7981 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
7983 redraw_mask = REDRAW_ALL;