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"
26 /* select level set with EMC X11 graphics before activating EM GFX debugging */
27 #define DEBUG_EM_GFX 0
29 /* tool button identifiers */
30 #define TOOL_CTRL_ID_YES 0
31 #define TOOL_CTRL_ID_NO 1
32 #define TOOL_CTRL_ID_CONFIRM 2
33 #define TOOL_CTRL_ID_PLAYER_1 3
34 #define TOOL_CTRL_ID_PLAYER_2 4
35 #define TOOL_CTRL_ID_PLAYER_3 5
36 #define TOOL_CTRL_ID_PLAYER_4 6
38 #define NUM_TOOL_BUTTONS 7
40 /* forward declaration for internal use */
41 static void UnmapToolButtons();
42 static void HandleToolButtons(struct GadgetInfo *);
43 static int el_act_dir2crm(int, int, int);
44 static int el_act2crm(int, int);
46 static struct GadgetInfo *tool_gadget[NUM_TOOL_BUTTONS];
47 static int request_gadget_id = -1;
49 static char *print_if_not_empty(int element)
51 static char *s = NULL;
52 char *token_name = element_info[element].token_name;
57 s = checked_malloc(strlen(token_name) + 10 + 1);
59 if (element != EL_EMPTY)
60 sprintf(s, "%d\t['%s']", element, token_name);
62 sprintf(s, "%d", element);
67 void DumpTile(int x, int y)
72 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
79 printf("Field Info: SCREEN(%d, %d), LEVEL(%d, %d)\n", sx, sy, x, y);
82 if (!IN_LEV_FIELD(x, y))
84 printf("(not in level field)\n");
90 printf(" Feld: %d\t['%s']\n", Feld[x][y],
91 element_info[Feld[x][y]].token_name);
92 printf(" Back: %s\n", print_if_not_empty(Back[x][y]));
93 printf(" Store: %s\n", print_if_not_empty(Store[x][y]));
94 printf(" Store2: %s\n", print_if_not_empty(Store2[x][y]));
95 printf(" StorePlayer: %s\n", print_if_not_empty(StorePlayer[x][y]));
96 printf(" MovPos: %d\n", MovPos[x][y]);
97 printf(" MovDir: %d\n", MovDir[x][y]);
98 printf(" MovDelay: %d\n", MovDelay[x][y]);
99 printf(" ChangeDelay: %d\n", ChangeDelay[x][y]);
100 printf(" CustomValue: %d\n", CustomValue[x][y]);
101 printf(" GfxElement: %d\n", GfxElement[x][y]);
102 printf(" GfxAction: %d\n", GfxAction[x][y]);
103 printf(" GfxFrame: %d\n", GfxFrame[x][y]);
107 void SetDrawtoField(int mode)
109 if (mode == DRAW_BUFFERED && setup.soft_scrolling)
120 drawto_field = fieldbuffer;
122 else /* DRAW_BACKBUFFER */
128 BX2 = SCR_FIELDX - 1;
129 BY2 = SCR_FIELDY - 1;
133 drawto_field = backbuffer;
137 void RedrawPlayfield(boolean force_redraw, int x, int y, int width, int height)
139 if (game_status == GAME_MODE_PLAYING &&
140 level.game_engine_type == GAME_ENGINE_TYPE_EM)
142 /* currently there is no partial redraw -- always redraw whole playfield */
143 RedrawPlayfield_EM(TRUE);
145 /* blit playfield from scroll buffer to normal back buffer for fading in */
146 BlitScreenToBitmap_EM(backbuffer);
148 else if (game_status == GAME_MODE_PLAYING &&
149 level.game_engine_type == GAME_ENGINE_TYPE_SP)
151 /* currently there is no partial redraw -- always redraw whole playfield */
152 RedrawPlayfield_SP(TRUE);
154 /* blit playfield from scroll buffer to normal back buffer for fading in */
155 BlitScreenToBitmap_SP(backbuffer);
157 else if (game_status == GAME_MODE_PLAYING &&
158 !game.envelope_active)
164 width = gfx.sxsize + 2 * TILEX;
165 height = gfx.sysize + 2 * TILEY;
171 int x1 = (x - SX) / TILEX, y1 = (y - SY) / TILEY;
172 int x2 = (x - SX + width) / TILEX, y2 = (y - SY + height) / TILEY;
174 for (xx = BX1; xx <= BX2; xx++)
175 for (yy = BY1; yy <= BY2; yy++)
176 if (xx >= x1 && xx <= x2 && yy >= y1 && yy <= y2)
177 DrawScreenField(xx, yy);
181 if (setup.soft_scrolling)
183 int fx = FX, fy = FY;
185 fx += (ScreenMovDir & (MV_LEFT|MV_RIGHT) ? ScreenGfxPos : 0);
186 fy += (ScreenMovDir & (MV_UP|MV_DOWN) ? ScreenGfxPos : 0);
188 BlitBitmap(fieldbuffer, backbuffer, fx,fy, SXSIZE,SYSIZE, SX,SY);
200 BlitBitmap(drawto, window, x, y, width, height, x, y);
203 void DrawMaskedBorder_Rect(int x, int y, int width, int height)
205 Bitmap *bitmap = graphic_info[IMG_GLOBAL_BORDER].bitmap;
207 SetClipOrigin(bitmap, bitmap->stored_clip_gc, 0, 0);
208 BlitBitmapMasked(bitmap, backbuffer, x, y, width, height, x, y);
211 void DrawMaskedBorder_FIELD()
213 if (global.border_status >= GAME_MODE_TITLE &&
214 global.border_status <= GAME_MODE_PLAYING &&
215 border.draw_masked[global.border_status])
216 DrawMaskedBorder_Rect(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
219 void DrawMaskedBorder_DOOR_1()
221 if (border.draw_masked[GFX_SPECIAL_ARG_DOOR] &&
222 (global.border_status != GAME_MODE_EDITOR ||
223 border.draw_masked[GFX_SPECIAL_ARG_EDITOR]))
224 DrawMaskedBorder_Rect(DX, DY, DXSIZE, DYSIZE);
227 void DrawMaskedBorder_DOOR_2()
229 if (border.draw_masked[GFX_SPECIAL_ARG_DOOR] &&
230 global.border_status != GAME_MODE_EDITOR)
231 DrawMaskedBorder_Rect(VX, VY, VXSIZE, VYSIZE);
234 void DrawMaskedBorder_DOOR_3()
236 /* currently not available */
239 void DrawMaskedBorder_ALL()
241 DrawMaskedBorder_FIELD();
242 DrawMaskedBorder_DOOR_1();
243 DrawMaskedBorder_DOOR_2();
244 DrawMaskedBorder_DOOR_3();
247 void DrawMaskedBorder(int redraw_mask)
249 /* never draw masked screen borders on borderless screens */
250 if (effectiveGameStatus() == GAME_MODE_LOADING ||
251 effectiveGameStatus() == GAME_MODE_TITLE)
254 if (redraw_mask & REDRAW_ALL)
255 DrawMaskedBorder_ALL();
258 if (redraw_mask & REDRAW_FIELD)
259 DrawMaskedBorder_FIELD();
260 if (redraw_mask & REDRAW_DOOR_1)
261 DrawMaskedBorder_DOOR_1();
262 if (redraw_mask & REDRAW_DOOR_2)
263 DrawMaskedBorder_DOOR_2();
264 if (redraw_mask & REDRAW_DOOR_3)
265 DrawMaskedBorder_DOOR_3();
272 DrawBuffer *buffer = (drawto_field == window ? backbuffer : drawto_field);
275 printf("::: TILES TO REFRESH: %d\n", redraw_tiles);
276 for (x = 0; x < SCR_FIELDX; x++)
277 for (y = 0 ; y < SCR_FIELDY; y++)
278 if (redraw[redraw_x1 + x][redraw_y1 + y])
279 printf("::: - %d, %d [%s]\n",
280 LEVELX(x), LEVELY(y),
281 EL_NAME(Feld[LEVELX(x)][LEVELY(y)]));
284 if (redraw_mask & REDRAW_TILES && redraw_tiles > REDRAWTILES_THRESHOLD)
285 redraw_mask |= REDRAW_FIELD;
287 if (redraw_mask & REDRAW_FIELD)
288 redraw_mask &= ~REDRAW_TILES;
290 if (redraw_mask == REDRAW_NONE)
293 if (redraw_mask & REDRAW_TILES &&
294 game_status == GAME_MODE_PLAYING &&
295 border.draw_masked[GAME_MODE_PLAYING])
296 redraw_mask |= REDRAW_FIELD;
298 if (global.fps_slowdown && game_status == GAME_MODE_PLAYING)
300 static boolean last_frame_skipped = FALSE;
301 boolean skip_even_when_not_scrolling = TRUE;
302 boolean just_scrolling = (ScreenMovDir != 0);
303 boolean verbose = FALSE;
305 if (global.fps_slowdown_factor > 1 &&
306 (FrameCounter % global.fps_slowdown_factor) &&
307 (just_scrolling || skip_even_when_not_scrolling))
309 redraw_mask &= ~REDRAW_MAIN;
311 last_frame_skipped = TRUE;
314 printf("FRAME SKIPPED\n");
318 if (last_frame_skipped)
319 redraw_mask |= REDRAW_FIELD;
321 last_frame_skipped = FALSE;
324 printf("frame not skipped\n");
328 /* synchronize X11 graphics at this point; if we would synchronize the
329 display immediately after the buffer switching (after the XFlush),
330 this could mean that we have to wait for the graphics to complete,
331 although we could go on doing calculations for the next frame */
335 /* prevent drawing masked border to backbuffer when using playfield buffer */
336 if (game_status != GAME_MODE_PLAYING ||
337 redraw_mask & REDRAW_FROM_BACKBUFFER ||
338 buffer == backbuffer)
339 DrawMaskedBorder(redraw_mask);
341 DrawMaskedBorder(redraw_mask & REDRAW_DOORS);
343 if (redraw_mask & REDRAW_ALL)
345 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
347 redraw_mask = REDRAW_NONE;
350 if (redraw_mask & REDRAW_FIELD)
352 if (game_status != GAME_MODE_PLAYING ||
353 redraw_mask & REDRAW_FROM_BACKBUFFER)
355 BlitBitmap(backbuffer, window,
356 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE, REAL_SX, REAL_SY);
360 int fx = FX, fy = FY;
362 if (setup.soft_scrolling)
364 fx += (ScreenMovDir & (MV_LEFT | MV_RIGHT) ? ScreenGfxPos : 0);
365 fy += (ScreenMovDir & (MV_UP | MV_DOWN) ? ScreenGfxPos : 0);
368 if (setup.soft_scrolling ||
369 ABS(ScreenMovPos) + ScrollStepSize == TILEX ||
370 ABS(ScreenMovPos) == ScrollStepSize ||
371 redraw_tiles > REDRAWTILES_THRESHOLD)
373 if (border.draw_masked[GAME_MODE_PLAYING])
375 if (buffer != backbuffer)
377 /* copy playfield buffer to backbuffer to add masked border */
378 BlitBitmap(buffer, backbuffer, fx, fy, SXSIZE, SYSIZE, SX, SY);
379 DrawMaskedBorder(REDRAW_FIELD);
382 BlitBitmap(backbuffer, window,
383 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
388 BlitBitmap(buffer, window, fx, fy, SXSIZE, SYSIZE, SX, SY);
393 printf("redrawing all (ScreenGfxPos == %d) because %s\n",
395 (setup.soft_scrolling ?
396 "setup.soft_scrolling" :
397 ABS(ScreenGfxPos) + ScrollStepSize == TILEX ?
398 "ABS(ScreenGfxPos) + ScrollStepSize == TILEX" :
399 ABS(ScreenGfxPos) == ScrollStepSize ?
400 "ABS(ScreenGfxPos) == ScrollStepSize" :
401 "redraw_tiles > REDRAWTILES_THRESHOLD"));
407 redraw_mask &= ~REDRAW_MAIN;
410 if (redraw_mask & REDRAW_DOORS)
412 if (redraw_mask & REDRAW_DOOR_1)
413 BlitBitmap(backbuffer, window, DX, DY, DXSIZE, DYSIZE, DX, DY);
415 if (redraw_mask & REDRAW_DOOR_2)
416 BlitBitmap(backbuffer, window, VX, VY, VXSIZE, VYSIZE, VX, VY);
418 if (redraw_mask & REDRAW_DOOR_3)
419 BlitBitmap(backbuffer, window, EX, EY, EXSIZE, EYSIZE, EX, EY);
421 redraw_mask &= ~REDRAW_DOORS;
424 if (redraw_mask & REDRAW_MICROLEVEL)
426 BlitBitmap(backbuffer, window, SX, SY + 10 * TILEY, SXSIZE, 7 * TILEY,
427 SX, SY + 10 * TILEY);
429 redraw_mask &= ~REDRAW_MICROLEVEL;
432 if (redraw_mask & REDRAW_TILES)
434 for (x = 0; x < SCR_FIELDX; x++)
435 for (y = 0 ; y < SCR_FIELDY; y++)
436 if (redraw[redraw_x1 + x][redraw_y1 + y])
437 BlitBitmap(buffer, window,
438 FX + x * TILEX, FY + y * TILEY, TILEX, TILEY,
439 SX + x * TILEX, SY + y * TILEY);
442 if (redraw_mask & REDRAW_FPS) /* display frames per second */
447 sprintf(info1, " (only every %d. frame)", global.fps_slowdown_factor);
448 if (!global.fps_slowdown)
451 sprintf(text, "%04.1f fps%s", global.frames_per_second, info1);
453 DrawTextExt(window, SX + SXSIZE + SX, 0, text, FONT_TEXT_2, BLIT_OPAQUE);
455 DrawTextExt(window, SX, SY, text, FONT_TEXT_2, BLIT_OPAQUE);
461 for (x = 0; x < MAX_BUF_XSIZE; x++)
462 for (y = 0; y < MAX_BUF_YSIZE; y++)
465 redraw_mask = REDRAW_NONE;
468 static void FadeCrossSaveBackbuffer()
470 BlitBitmap(backbuffer, bitmap_db_cross, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
473 static void FadeExt(int fade_mask, int fade_mode, int fade_type)
475 static int fade_type_skip = FADE_TYPE_NONE;
476 void (*draw_border_function)(void) = NULL;
477 Bitmap *bitmap = (fade_mode & FADE_TYPE_TRANSFORM ? bitmap_db_cross : NULL);
478 int x, y, width, height;
479 int fade_delay, post_delay;
481 if (fade_type == FADE_TYPE_FADE_OUT)
483 if (fade_type_skip != FADE_TYPE_NONE)
486 printf("::: skipping %d ... [%d] (X)\n", fade_mode, fade_type_skip);
489 /* skip all fade operations until specified fade operation */
490 if (fade_type & fade_type_skip)
491 fade_type_skip = FADE_TYPE_NONE;
496 if (fading.fade_mode & FADE_TYPE_TRANSFORM)
498 FadeCrossSaveBackbuffer();
504 redraw_mask |= fade_mask;
506 if (fade_type == FADE_TYPE_SKIP)
509 printf("::: will skip %d ... [%d]\n", fade_mode, fade_type_skip);
512 fade_type_skip = fade_mode;
518 printf("::: !!! FADING %d ... [%d] [%d]\n", fade_mode, fade_type,
523 fade_delay = fading.fade_delay;
524 post_delay = (fade_mode == FADE_MODE_FADE_OUT ? fading.post_delay : 0);
527 if (fade_type_skip != FADE_TYPE_NONE)
530 printf("::: skipping %d ... [%d]\n", fade_mode, fade_type_skip);
533 /* skip all fade operations until specified fade operation */
534 if (fade_type & fade_type_skip)
535 fade_type_skip = FADE_TYPE_NONE;
545 if (global.autoplay_leveldir)
547 // fading.fade_mode = FADE_MODE_NONE;
554 if (fading.fade_mode == FADE_MODE_NONE)
562 /* !!! what about fade_mask == REDRAW_FIELD | REDRAW_ALL ??? !!! */
565 printf("::: NOW FADING %d ... [%d]\n", fade_mode, fade_type);
569 if (fade_mask == REDRAW_NONE)
570 fade_mask = REDRAW_FIELD;
573 // if (fade_mask & REDRAW_FIELD)
574 if (fade_mask == REDRAW_FIELD)
579 height = FULL_SYSIZE;
582 fade_delay = fading.fade_delay;
583 post_delay = (fade_mode == FADE_MODE_FADE_OUT ? fading.post_delay : 0);
586 if (border.draw_masked_when_fading)
587 draw_border_function = DrawMaskedBorder_FIELD; /* update when fading */
589 DrawMaskedBorder_FIELD(); /* draw once */
591 else /* REDRAW_ALL */
599 fade_delay = fading.fade_delay;
600 post_delay = (fade_mode == FADE_MODE_FADE_OUT ? fading.post_delay : 0);
605 if (!setup.fade_screens ||
607 fading.fade_mode == FADE_MODE_NONE)
609 if (!setup.fade_screens || fade_delay == 0)
612 if (fade_mode == FADE_MODE_FADE_OUT)
616 if (fade_mode == FADE_MODE_FADE_OUT &&
617 fading.fade_mode != FADE_MODE_NONE)
618 ClearRectangle(backbuffer, x, y, width, height);
622 BlitBitmap(backbuffer, window, x, y, width, height, x, y);
623 redraw_mask = REDRAW_NONE;
631 FadeRectangle(bitmap, x, y, width, height, fade_mode, fade_delay, post_delay,
632 draw_border_function);
634 redraw_mask &= ~fade_mask;
637 void FadeIn(int fade_mask)
639 if (fading.fade_mode & FADE_TYPE_TRANSFORM)
640 FadeExt(fade_mask, fading.fade_mode, FADE_TYPE_FADE_IN);
642 FadeExt(fade_mask, FADE_MODE_FADE_IN, FADE_TYPE_FADE_IN);
645 void FadeOut(int fade_mask)
647 if (fading.fade_mode & FADE_TYPE_TRANSFORM)
648 FadeExt(fade_mask, fading.fade_mode, FADE_TYPE_FADE_OUT);
650 FadeExt(fade_mask, FADE_MODE_FADE_OUT, FADE_TYPE_FADE_OUT);
652 global.border_status = game_status;
655 static void FadeSetLeaveNext(struct TitleFadingInfo fading_leave, boolean set)
657 static struct TitleFadingInfo fading_leave_stored;
660 fading_leave_stored = fading_leave;
662 fading = fading_leave_stored;
665 void FadeSetEnterMenu()
667 fading = menu.enter_menu;
670 printf("::: storing enter_menu\n");
673 FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */
676 void FadeSetLeaveMenu()
678 fading = menu.leave_menu;
681 printf("::: storing leave_menu\n");
684 FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */
687 void FadeSetEnterScreen()
689 fading = menu.enter_screen[game_status];
692 printf("::: storing leave_screen[%d]\n", game_status);
695 FadeSetLeaveNext(menu.leave_screen[game_status], TRUE); /* store */
698 void FadeSetNextScreen()
700 fading = menu.next_screen;
703 printf("::: storing next_screen\n");
706 // (do not overwrite fade mode set by FadeSetEnterScreen)
707 // FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */
710 void FadeSetLeaveScreen()
713 printf("::: recalling last stored value\n");
716 FadeSetLeaveNext(menu.leave_screen[game_status], FALSE); /* recall */
719 void FadeSetFromType(int type)
721 if (type & TYPE_ENTER_SCREEN)
722 FadeSetEnterScreen();
723 else if (type & TYPE_ENTER)
725 else if (type & TYPE_LEAVE)
729 void FadeSetDisabled()
731 static struct TitleFadingInfo fading_none = { FADE_MODE_NONE, -1, -1, -1 };
733 fading = fading_none;
736 void FadeSkipNextFadeIn()
738 FadeExt(0, FADE_MODE_SKIP_FADE_IN, FADE_TYPE_SKIP);
741 void FadeSkipNextFadeOut()
743 FadeExt(0, FADE_MODE_SKIP_FADE_OUT, FADE_TYPE_SKIP);
746 void SetWindowBackgroundImageIfDefined(int graphic)
748 if (graphic_info[graphic].bitmap)
749 SetWindowBackgroundBitmap(graphic_info[graphic].bitmap);
752 void SetMainBackgroundImageIfDefined(int graphic)
754 if (graphic_info[graphic].bitmap)
755 SetMainBackgroundBitmap(graphic_info[graphic].bitmap);
758 void SetDoorBackgroundImageIfDefined(int graphic)
760 if (graphic_info[graphic].bitmap)
761 SetDoorBackgroundBitmap(graphic_info[graphic].bitmap);
764 void SetWindowBackgroundImage(int graphic)
766 SetWindowBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
767 graphic_info[graphic].bitmap ?
768 graphic_info[graphic].bitmap :
769 graphic_info[IMG_BACKGROUND].bitmap);
772 void SetMainBackgroundImage(int graphic)
774 SetMainBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
775 graphic_info[graphic].bitmap ?
776 graphic_info[graphic].bitmap :
777 graphic_info[IMG_BACKGROUND].bitmap);
780 void SetDoorBackgroundImage(int graphic)
782 SetDoorBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
783 graphic_info[graphic].bitmap ?
784 graphic_info[graphic].bitmap :
785 graphic_info[IMG_BACKGROUND].bitmap);
788 void SetPanelBackground()
790 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, bitmap_db_panel,
791 DOOR_GFX_PAGEX5, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE, 0, 0);
793 SetDoorBackgroundBitmap(bitmap_db_panel);
796 void DrawBackground(int x, int y, int width, int height)
798 /* !!! "drawto" might still point to playfield buffer here (see below) !!! */
799 /* (when entering hall of fame after playing) */
801 ClearRectangleOnBackground(drawto, x, y, width, height);
803 ClearRectangleOnBackground(backbuffer, x, y, width, height);
806 redraw_mask |= REDRAW_FIELD;
809 void DrawBackgroundForFont(int x, int y, int width, int height, int font_nr)
811 struct FontBitmapInfo *font = getFontBitmapInfo(font_nr);
813 if (font->bitmap == NULL)
816 DrawBackground(x, y, width, height);
819 void DrawBackgroundForGraphic(int x, int y, int width, int height, int graphic)
821 struct GraphicInfo *g = &graphic_info[graphic];
823 if (g->bitmap == NULL)
826 DrawBackground(x, y, width, height);
831 /* !!! "drawto" might still point to playfield buffer here (see above) !!! */
832 /* (when entering hall of fame after playing) */
833 DrawBackground(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
835 /* !!! maybe this should be done before clearing the background !!! */
836 if (setup.soft_scrolling && game_status == GAME_MODE_PLAYING)
838 ClearRectangle(fieldbuffer, 0, 0, FXSIZE, FYSIZE);
839 SetDrawtoField(DRAW_BUFFERED);
842 SetDrawtoField(DRAW_BACKBUFFER);
845 void MarkTileDirty(int x, int y)
847 int xx = redraw_x1 + x;
848 int yy = redraw_y1 + y;
853 redraw[xx][yy] = TRUE;
854 redraw_mask |= REDRAW_TILES;
857 void SetBorderElement()
861 BorderElement = EL_EMPTY;
863 for (y = 0; y < lev_fieldy && BorderElement == EL_EMPTY; y++)
865 for (x = 0; x < lev_fieldx; x++)
867 if (!IS_INDESTRUCTIBLE(Feld[x][y]))
868 BorderElement = EL_STEELWALL;
870 if (y != 0 && y != lev_fieldy - 1 && x != lev_fieldx - 1)
876 void FloodFillLevel(int from_x, int from_y, int fill_element,
877 short field[MAX_LEV_FIELDX][MAX_LEV_FIELDY],
878 int max_fieldx, int max_fieldy)
882 static int check[4][2] = { { -1, 0 }, { 0, -1 }, { 1, 0 }, { 0, 1 } };
883 static int safety = 0;
885 /* check if starting field still has the desired content */
886 if (field[from_x][from_y] == fill_element)
891 if (safety > max_fieldx * max_fieldy)
892 Error(ERR_EXIT, "Something went wrong in 'FloodFill()'. Please debug.");
894 old_element = field[from_x][from_y];
895 field[from_x][from_y] = fill_element;
897 for (i = 0; i < 4; i++)
899 x = from_x + check[i][0];
900 y = from_y + check[i][1];
902 if (IN_FIELD(x, y, max_fieldx, max_fieldy) && field[x][y] == old_element)
903 FloodFillLevel(x, y, fill_element, field, max_fieldx, max_fieldy);
909 void SetRandomAnimationValue(int x, int y)
911 gfx.anim_random_frame = GfxRandom[x][y];
914 inline int getGraphicAnimationFrame(int graphic, int sync_frame)
916 /* animation synchronized with global frame counter, not move position */
917 if (graphic_info[graphic].anim_global_sync || sync_frame < 0)
918 sync_frame = FrameCounter;
920 return getAnimationFrame(graphic_info[graphic].anim_frames,
921 graphic_info[graphic].anim_delay,
922 graphic_info[graphic].anim_mode,
923 graphic_info[graphic].anim_start_frame,
927 void getSizedGraphicSource(int graphic, int frame, int tilesize_raw,
928 Bitmap **bitmap, int *x, int *y)
932 int width_mult, width_div;
933 int height_mult, height_div;
937 { 15, 16, 2, 3 }, /* 1 x 1 */
938 { 7, 8, 2, 3 }, /* 2 x 2 */
939 { 3, 4, 2, 3 }, /* 4 x 4 */
940 { 1, 2, 2, 3 }, /* 8 x 8 */
941 { 0, 1, 2, 3 }, /* 16 x 16 */
942 { 0, 1, 0, 1 }, /* 32 x 32 */
944 struct GraphicInfo *g = &graphic_info[graphic];
945 Bitmap *src_bitmap = g->bitmap;
946 int tilesize = MIN(MAX(1, tilesize_raw), TILESIZE);
947 int offset_calc_pos = log_2(tilesize);
948 int width_mult = offset_calc[offset_calc_pos].width_mult;
949 int width_div = offset_calc[offset_calc_pos].width_div;
950 int height_mult = offset_calc[offset_calc_pos].height_mult;
951 int height_div = offset_calc[offset_calc_pos].height_div;
952 int startx = src_bitmap->width * width_mult / width_div;
953 int starty = src_bitmap->height * height_mult / height_div;
954 int src_x = g->src_x * tilesize / TILESIZE;
955 int src_y = g->src_y * tilesize / TILESIZE;
956 int width = g->width * tilesize / TILESIZE;
957 int height = g->height * tilesize / TILESIZE;
958 int offset_x = g->offset_x * tilesize / TILESIZE;
959 int offset_y = g->offset_y * tilesize / TILESIZE;
961 if (g->offset_y == 0) /* frames are ordered horizontally */
963 int max_width = g->anim_frames_per_line * width;
964 int pos = (src_y / height) * max_width + src_x + frame * offset_x;
966 src_x = pos % max_width;
967 src_y = src_y % height + pos / max_width * height;
969 else if (g->offset_x == 0) /* frames are ordered vertically */
971 int max_height = g->anim_frames_per_line * height;
972 int pos = (src_x / width) * max_height + src_y + frame * offset_y;
974 src_x = src_x % width + pos / max_height * width;
975 src_y = pos % max_height;
977 else /* frames are ordered diagonally */
979 src_x = src_x + frame * offset_x;
980 src_y = src_y + frame * offset_y;
983 *bitmap = src_bitmap;
988 void getMiniGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
991 getSizedGraphicSource(graphic, 0, MINI_TILESIZE, bitmap, x, y);
993 struct GraphicInfo *g = &graphic_info[graphic];
995 int mini_starty = g->bitmap->height * 2 / 3;
998 *x = mini_startx + g->src_x / 2;
999 *y = mini_starty + g->src_y / 2;
1003 inline void getGraphicSourceExt(int graphic, int frame, Bitmap **bitmap,
1004 int *x, int *y, boolean get_backside)
1006 struct GraphicInfo *g = &graphic_info[graphic];
1007 int src_x = g->src_x + (get_backside ? g->offset2_x : 0);
1008 int src_y = g->src_y + (get_backside ? g->offset2_y : 0);
1010 *bitmap = g->bitmap;
1012 if (g->offset_y == 0) /* frames are ordered horizontally */
1014 int max_width = g->anim_frames_per_line * g->width;
1015 int pos = (src_y / g->height) * max_width + src_x + frame * g->offset_x;
1017 *x = pos % max_width;
1018 *y = src_y % g->height + pos / max_width * g->height;
1020 else if (g->offset_x == 0) /* frames are ordered vertically */
1022 int max_height = g->anim_frames_per_line * g->height;
1023 int pos = (src_x / g->width) * max_height + src_y + frame * g->offset_y;
1025 *x = src_x % g->width + pos / max_height * g->width;
1026 *y = pos % max_height;
1028 else /* frames are ordered diagonally */
1030 *x = src_x + frame * g->offset_x;
1031 *y = src_y + frame * g->offset_y;
1035 void getGraphicSource(int graphic, int frame, Bitmap **bitmap, int *x, int *y)
1037 getGraphicSourceExt(graphic, frame, bitmap, x, y, FALSE);
1040 void DrawGraphic(int x, int y, int graphic, int frame)
1043 if (!IN_SCR_FIELD(x, y))
1045 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
1046 printf("DrawGraphic(): This should never happen!\n");
1051 DrawGraphicExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic, frame);
1052 MarkTileDirty(x, y);
1055 void DrawGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
1061 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1062 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
1065 void DrawGraphicThruMask(int x, int y, int graphic, int frame)
1068 if (!IN_SCR_FIELD(x, y))
1070 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
1071 printf("DrawGraphicThruMask(): This should never happen!\n");
1076 DrawGraphicThruMaskExt(drawto_field, FX + x * TILEX, FY + y *TILEY, graphic,
1078 MarkTileDirty(x, y);
1081 void DrawGraphicThruMaskExt(DrawBuffer *d, int dst_x, int dst_y, int graphic,
1087 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1089 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1090 dst_x - src_x, dst_y - src_y);
1091 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX, TILEY, dst_x, dst_y);
1094 void DrawSizedGraphic(int x, int y, int graphic, int frame, int tilesize)
1096 DrawSizedGraphicExt(drawto, SX + x * tilesize, SY + y * tilesize, graphic,
1098 MarkTileDirty(x / tilesize, y / tilesize);
1101 void DrawSizedGraphicExt(DrawBuffer *d, int x, int y, int graphic, int frame,
1107 getSizedGraphicSource(graphic, frame, tilesize, &src_bitmap, &src_x, &src_y);
1108 BlitBitmap(src_bitmap, d, src_x, src_y, tilesize, tilesize, x, y);
1111 void DrawMiniGraphic(int x, int y, int graphic)
1113 DrawMiniGraphicExt(drawto, SX + x * MINI_TILEX,SY + y * MINI_TILEY, graphic);
1114 MarkTileDirty(x / 2, y / 2);
1117 void DrawMiniGraphicExt(DrawBuffer *d, int x, int y, int graphic)
1122 getMiniGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
1123 BlitBitmap(src_bitmap, d, src_x, src_y, MINI_TILEX, MINI_TILEY, x, y);
1126 inline static void DrawGraphicShiftedNormal(int x, int y, int dx, int dy,
1127 int graphic, int frame,
1128 int cut_mode, int mask_mode)
1133 int width = TILEX, height = TILEY;
1136 if (dx || dy) /* shifted graphic */
1138 if (x < BX1) /* object enters playfield from the left */
1145 else if (x > BX2) /* object enters playfield from the right */
1151 else if (x==BX1 && dx < 0) /* object leaves playfield to the left */
1157 else if (x==BX2 && dx > 0) /* object leaves playfield to the right */
1159 else if (dx) /* general horizontal movement */
1160 MarkTileDirty(x + SIGN(dx), y);
1162 if (y < BY1) /* object enters playfield from the top */
1164 if (cut_mode==CUT_BELOW) /* object completely above top border */
1172 else if (y > BY2) /* object enters playfield from the bottom */
1178 else if (y==BY1 && dy < 0) /* object leaves playfield to the top */
1184 else if (dy > 0 && cut_mode == CUT_ABOVE)
1186 if (y == BY2) /* object completely above bottom border */
1192 MarkTileDirty(x, y + 1);
1193 } /* object leaves playfield to the bottom */
1194 else if (dy > 0 && (y == BY2 || cut_mode == CUT_BELOW))
1196 else if (dy) /* general vertical movement */
1197 MarkTileDirty(x, y + SIGN(dy));
1201 if (!IN_SCR_FIELD(x, y))
1203 printf("DrawGraphicShifted(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
1204 printf("DrawGraphicShifted(): This should never happen!\n");
1209 if (width > 0 && height > 0)
1211 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1216 dst_x = FX + x * TILEX + dx;
1217 dst_y = FY + y * TILEY + dy;
1219 if (mask_mode == USE_MASKING)
1221 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1222 dst_x - src_x, dst_y - src_y);
1223 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1227 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1230 MarkTileDirty(x, y);
1234 inline static void DrawGraphicShiftedDouble(int x, int y, int dx, int dy,
1235 int graphic, int frame,
1236 int cut_mode, int mask_mode)
1241 int width = TILEX, height = TILEY;
1244 int x2 = x + SIGN(dx);
1245 int y2 = y + SIGN(dy);
1247 /* !!! DOES NOT WORK FOR SLOW MOVEMENT !!! */
1248 int sync_frame = GfxFrame[LEVELX(x)][LEVELY(y)];
1250 /* movement with two-tile animations must be sync'ed with movement position,
1251 not with current GfxFrame (which can be higher when using slow movement) */
1252 int anim_pos = (dx ? ABS(dx) : ABS(dy));
1253 int anim_frames = graphic_info[graphic].anim_frames;
1255 /* (we also need anim_delay here for movement animations with less frames) */
1256 int anim_delay = graphic_info[graphic].anim_delay;
1257 int sync_frame = anim_pos * anim_frames * anim_delay / TILESIZE;
1259 int sync_frame = anim_pos * anim_frames / TILESIZE;
1262 boolean draw_start_tile = (cut_mode != CUT_ABOVE); /* only for falling! */
1263 boolean draw_end_tile = (cut_mode != CUT_BELOW); /* only for falling! */
1265 /* re-calculate animation frame for two-tile movement animation */
1266 frame = getGraphicAnimationFrame(graphic, sync_frame);
1270 printf("::: %d, %d, %d => %d [%d]\n",
1271 anim_pos, anim_frames, anim_delay, sync_frame, graphic);
1273 printf("::: %d, %d => %d\n",
1274 anim_pos, anim_frames, sync_frame);
1279 printf("::: %d [%d, %d] [%d] [%d]\n", frame, sync_frame, dy,
1280 GfxFrame[LEVELX(x)][LEVELY(y)], mask_mode);
1283 /* check if movement start graphic inside screen area and should be drawn */
1284 if (draw_start_tile && IN_SCR_FIELD(x1, y1))
1286 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, TRUE);
1288 dst_x = FX + x1 * TILEX;
1289 dst_y = FY + y1 * TILEY;
1291 if (mask_mode == USE_MASKING)
1293 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1294 dst_x - src_x, dst_y - src_y);
1295 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1299 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1302 MarkTileDirty(x1, y1);
1305 /* check if movement end graphic inside screen area and should be drawn */
1306 if (draw_end_tile && IN_SCR_FIELD(x2, y2))
1308 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
1310 dst_x = FX + x2 * TILEX;
1311 dst_y = FY + y2 * TILEY;
1313 if (mask_mode == USE_MASKING)
1315 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1316 dst_x - src_x, dst_y - src_y);
1317 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1321 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1324 MarkTileDirty(x2, y2);
1328 static void DrawGraphicShifted(int x, int y, int dx, int dy,
1329 int graphic, int frame,
1330 int cut_mode, int mask_mode)
1334 DrawGraphic(x, y, graphic, frame);
1339 if (graphic_info[graphic].double_movement) /* EM style movement images */
1340 DrawGraphicShiftedDouble(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
1342 DrawGraphicShiftedNormal(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
1345 void DrawGraphicShiftedThruMask(int x, int y, int dx, int dy, int graphic,
1346 int frame, int cut_mode)
1348 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, USE_MASKING);
1351 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
1352 int cut_mode, int mask_mode)
1354 int lx = LEVELX(x), ly = LEVELY(y);
1358 if (IN_LEV_FIELD(lx, ly))
1360 SetRandomAnimationValue(lx, ly);
1362 graphic = el_act_dir2img(element, GfxAction[lx][ly], GfxDir[lx][ly]);
1363 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1365 /* do not use double (EM style) movement graphic when not moving */
1366 if (graphic_info[graphic].double_movement && !dx && !dy)
1368 graphic = el_act_dir2img(element, ACTION_DEFAULT, GfxDir[lx][ly]);
1369 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1372 else /* border element */
1374 graphic = el2img(element);
1375 frame = getGraphicAnimationFrame(graphic, -1);
1378 if (element == EL_EXPANDABLE_WALL)
1380 boolean left_stopped = FALSE, right_stopped = FALSE;
1382 if (!IN_LEV_FIELD(lx - 1, ly) || IS_WALL(Feld[lx - 1][ly]))
1383 left_stopped = TRUE;
1384 if (!IN_LEV_FIELD(lx + 1, ly) || IS_WALL(Feld[lx + 1][ly]))
1385 right_stopped = TRUE;
1387 if (left_stopped && right_stopped)
1389 else if (left_stopped)
1391 graphic = IMG_EXPANDABLE_WALL_GROWING_RIGHT;
1392 frame = graphic_info[graphic].anim_frames - 1;
1394 else if (right_stopped)
1396 graphic = IMG_EXPANDABLE_WALL_GROWING_LEFT;
1397 frame = graphic_info[graphic].anim_frames - 1;
1402 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, mask_mode);
1403 else if (mask_mode == USE_MASKING)
1404 DrawGraphicThruMask(x, y, graphic, frame);
1406 DrawGraphic(x, y, graphic, frame);
1409 void DrawLevelElementExt(int x, int y, int dx, int dy, int element,
1410 int cut_mode, int mask_mode)
1412 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1413 DrawScreenElementExt(SCREENX(x), SCREENY(y), dx, dy, element,
1414 cut_mode, mask_mode);
1417 void DrawScreenElementShifted(int x, int y, int dx, int dy, int element,
1420 DrawScreenElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1423 void DrawLevelElementShifted(int x, int y, int dx, int dy, int element,
1426 DrawLevelElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1429 void DrawLevelElementThruMask(int x, int y, int element)
1431 DrawLevelElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1434 void DrawLevelFieldThruMask(int x, int y)
1436 DrawLevelElementExt(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
1439 /* !!! implementation of quicksand is totally broken !!! */
1440 #define IS_CRUMBLED_TILE(x, y, e) \
1441 (GFX_CRUMBLED(e) && (!IN_LEV_FIELD(x, y) || \
1442 !IS_MOVING(x, y) || \
1443 (e) == EL_QUICKSAND_EMPTYING || \
1444 (e) == EL_QUICKSAND_FAST_EMPTYING))
1446 static void DrawLevelFieldCrumbledInnerCorners(int x, int y, int dx, int dy,
1451 int width, height, cx, cy;
1452 int sx = SCREENX(x), sy = SCREENY(y);
1453 int crumbled_border_size = graphic_info[graphic].border_size;
1456 getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
1458 for (i = 1; i < 4; i++)
1460 int dxx = (i & 1 ? dx : 0);
1461 int dyy = (i & 2 ? dy : 0);
1464 int element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1467 /* check if neighbour field is of same crumble type */
1468 boolean same = (IS_CRUMBLED_TILE(xx, yy, element) &&
1469 graphic_info[graphic].class ==
1470 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class);
1472 /* return if check prevents inner corner */
1473 if (same == (dxx == dx && dyy == dy))
1477 /* if we reach this point, we have an inner corner */
1479 getGraphicSource(graphic, 1, &src_bitmap, &src_x, &src_y);
1481 width = crumbled_border_size;
1482 height = crumbled_border_size;
1483 cx = (dx > 0 ? TILEX - crumbled_border_size : 0);
1484 cy = (dy > 0 ? TILEY - crumbled_border_size : 0);
1486 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1487 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
1490 static void DrawLevelFieldCrumbledBorders(int x, int y, int graphic, int frame,
1495 int width, height, bx, by, cx, cy;
1496 int sx = SCREENX(x), sy = SCREENY(y);
1497 int crumbled_border_size = graphic_info[graphic].border_size;
1500 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1502 /* draw simple, sloppy, non-corner-accurate crumbled border */
1505 width = (dir == 1 || dir == 2 ? crumbled_border_size : TILEX);
1506 height = (dir == 0 || dir == 3 ? crumbled_border_size : TILEY);
1507 cx = (dir == 2 ? TILEX - crumbled_border_size : 0);
1508 cy = (dir == 3 ? TILEY - crumbled_border_size : 0);
1510 if (dir == 1 || dir == 2) /* left or right crumbled border */
1512 width = crumbled_border_size;
1514 cx = (dir == 2 ? TILEX - crumbled_border_size : 0);
1517 else /* top or bottom crumbled border */
1520 height = crumbled_border_size;
1522 cy = (dir == 3 ? TILEY - crumbled_border_size : 0);
1526 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1527 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
1529 /* (remaining middle border part must be at least as big as corner part) */
1530 if (!(graphic_info[graphic].style & STYLE_ACCURATE_BORDERS) ||
1531 crumbled_border_size >= TILESIZE / 3)
1534 /* correct corners of crumbled border, if needed */
1537 for (i = -1; i <= 1; i+=2)
1539 int xx = x + (dir == 0 || dir == 3 ? i : 0);
1540 int yy = y + (dir == 1 || dir == 2 ? i : 0);
1541 int element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1544 /* check if neighbour field is of same crumble type */
1545 if (IS_CRUMBLED_TILE(xx, yy, element) &&
1546 graphic_info[graphic].class ==
1547 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class)
1549 /* no crumbled corner, but continued crumbled border */
1551 int c1 = (dir == 2 || dir == 3 ? TILESIZE - crumbled_border_size : 0);
1552 int c2 = (i == 1 ? TILESIZE - crumbled_border_size : 0);
1553 int b1 = (i == 1 ? crumbled_border_size :
1554 TILESIZE - 2 * crumbled_border_size);
1556 width = crumbled_border_size;
1557 height = crumbled_border_size;
1559 if (dir == 1 || dir == 2)
1574 BlitBitmap(src_bitmap, drawto_field, src_x + bx, src_y + by,
1575 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
1579 if (dir == 1 || dir == 2) /* left or right crumbled border */
1581 for (i = -1; i <= 1; i+=2)
1585 int element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1588 /* check if neighbour field is of same crumble type */
1589 if (IS_CRUMBLED_TILE(xx, yy, element) &&
1590 graphic_info[graphic].class ==
1591 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class)
1593 /* no crumbled corner, but continued crumbled border */
1595 width = crumbled_border_size;
1596 height = crumbled_border_size;
1597 cx = (dir == 2 ? TILEX - crumbled_border_size : 0);
1598 cy = (i == 1 ? TILEY - crumbled_border_size : 0);
1600 by = (i == 1 ? crumbled_border_size :
1601 TILEY - 2 * crumbled_border_size);
1603 BlitBitmap(src_bitmap, drawto_field, src_x + bx, src_y + by,
1604 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
1608 else /* top or bottom crumbled border */
1610 for (i = -1; i <= 1; i+=2)
1614 int element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1617 /* check if neighbour field is of same crumble type */
1618 if (IS_CRUMBLED_TILE(xx, yy, element) &&
1619 graphic_info[graphic].class ==
1620 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class)
1622 /* no crumbled corner, but continued crumbled border */
1624 width = crumbled_border_size;
1625 height = crumbled_border_size;
1626 cx = (i == 1 ? TILEX - crumbled_border_size : 0);
1627 cy = (dir == 3 ? TILEY - crumbled_border_size : 0);
1628 bx = (i == 1 ? crumbled_border_size :
1629 TILEX - 2 * crumbled_border_size);
1632 BlitBitmap(src_bitmap, drawto_field, src_x + bx, src_y + by,
1633 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
1640 static void DrawLevelFieldCrumbledExt(int x, int y, int graphic, int frame)
1642 int sx = SCREENX(x), sy = SCREENY(y);
1645 static int xy[4][2] =
1653 if (!IN_LEV_FIELD(x, y))
1656 element = TILE_GFX_ELEMENT(x, y);
1658 /* crumble field itself */
1659 if (IS_CRUMBLED_TILE(x, y, element))
1661 if (!IN_SCR_FIELD(sx, sy))
1664 for (i = 0; i < 4; i++)
1666 int xx = x + xy[i][0];
1667 int yy = y + xy[i][1];
1669 element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1672 /* check if neighbour field is of same crumble type */
1674 if (IS_CRUMBLED_TILE(xx, yy, element) &&
1675 graphic_info[graphic].class ==
1676 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class)
1679 if (IS_CRUMBLED_TILE(xx, yy, element))
1683 DrawLevelFieldCrumbledBorders(x, y, graphic, frame, i);
1686 if ((graphic_info[graphic].style & STYLE_INNER_CORNERS) &&
1687 graphic_info[graphic].anim_frames == 2)
1689 for (i = 0; i < 4; i++)
1691 int dx = (i & 1 ? +1 : -1);
1692 int dy = (i & 2 ? +1 : -1);
1694 DrawLevelFieldCrumbledInnerCorners(x, y, dx, dy, graphic);
1698 MarkTileDirty(sx, sy);
1700 else /* center field not crumbled -- crumble neighbour fields */
1702 for (i = 0; i < 4; i++)
1704 int xx = x + xy[i][0];
1705 int yy = y + xy[i][1];
1706 int sxx = sx + xy[i][0];
1707 int syy = sy + xy[i][1];
1709 if (!IN_LEV_FIELD(xx, yy) ||
1710 !IN_SCR_FIELD(sxx, syy))
1713 if (Feld[xx][yy] == EL_ELEMENT_SNAPPING)
1716 element = TILE_GFX_ELEMENT(xx, yy);
1718 if (!IS_CRUMBLED_TILE(xx, yy, element))
1721 graphic = el_act2crm(element, ACTION_DEFAULT);
1723 DrawLevelFieldCrumbledBorders(xx, yy, graphic, 0, 3 - i);
1725 MarkTileDirty(sxx, syy);
1730 void DrawLevelFieldCrumbled(int x, int y)
1734 if (!IN_LEV_FIELD(x, y))
1738 /* !!! CHECK THIS !!! */
1741 if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
1742 GFX_CRUMBLED(GfxElement[x][y]))
1745 if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
1746 GfxElement[x][y] != EL_UNDEFINED &&
1747 GFX_CRUMBLED(GfxElement[x][y]))
1749 DrawLevelFieldCrumbledDigging(x, y, GfxDir[x][y], GfxFrame[x][y]);
1756 graphic = el_act2crm(TILE_GFX_ELEMENT(x, y), ACTION_DEFAULT);
1758 graphic = el_act2crm(Feld[x][y], ACTION_DEFAULT);
1761 DrawLevelFieldCrumbledExt(x, y, graphic, 0);
1764 void DrawLevelFieldCrumbledDigging(int x, int y, int direction,
1767 int graphic1 = el_act_dir2img(GfxElement[x][y], ACTION_DIGGING, direction);
1768 int graphic2 = el_act_dir2crm(GfxElement[x][y], ACTION_DIGGING, direction);
1769 int frame1 = getGraphicAnimationFrame(graphic1, step_frame);
1770 int frame2 = getGraphicAnimationFrame(graphic2, step_frame);
1771 int sx = SCREENX(x), sy = SCREENY(y);
1773 DrawGraphic(sx, sy, graphic1, frame1);
1774 DrawLevelFieldCrumbledExt(x, y, graphic2, frame2);
1777 void DrawLevelFieldCrumbledNeighbours(int x, int y)
1779 int sx = SCREENX(x), sy = SCREENY(y);
1780 static int xy[4][2] =
1789 for (i = 0; i < 4; i++)
1791 int xx = x + xy[i][0];
1792 int yy = y + xy[i][1];
1793 int sxx = sx + xy[i][0];
1794 int syy = sy + xy[i][1];
1796 if (!IN_LEV_FIELD(xx, yy) ||
1797 !IN_SCR_FIELD(sxx, syy) ||
1798 !GFX_CRUMBLED(Feld[xx][yy]) ||
1802 DrawLevelField(xx, yy);
1806 static int getBorderElement(int x, int y)
1810 { EL_STEELWALL_TOPLEFT, EL_INVISIBLE_STEELWALL_TOPLEFT },
1811 { EL_STEELWALL_TOPRIGHT, EL_INVISIBLE_STEELWALL_TOPRIGHT },
1812 { EL_STEELWALL_BOTTOMLEFT, EL_INVISIBLE_STEELWALL_BOTTOMLEFT },
1813 { EL_STEELWALL_BOTTOMRIGHT, EL_INVISIBLE_STEELWALL_BOTTOMRIGHT },
1814 { EL_STEELWALL_VERTICAL, EL_INVISIBLE_STEELWALL_VERTICAL },
1815 { EL_STEELWALL_HORIZONTAL, EL_INVISIBLE_STEELWALL_HORIZONTAL },
1816 { EL_STEELWALL, EL_INVISIBLE_STEELWALL }
1818 int steel_type = (BorderElement == EL_STEELWALL ? 0 : 1);
1819 int steel_position = (x == -1 && y == -1 ? 0 :
1820 x == lev_fieldx && y == -1 ? 1 :
1821 x == -1 && y == lev_fieldy ? 2 :
1822 x == lev_fieldx && y == lev_fieldy ? 3 :
1823 x == -1 || x == lev_fieldx ? 4 :
1824 y == -1 || y == lev_fieldy ? 5 : 6);
1826 return border[steel_position][steel_type];
1829 void DrawScreenElement(int x, int y, int element)
1831 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
1832 DrawLevelFieldCrumbled(LEVELX(x), LEVELY(y));
1835 void DrawLevelElement(int x, int y, int element)
1837 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1838 DrawScreenElement(SCREENX(x), SCREENY(y), element);
1841 void DrawScreenField(int x, int y)
1843 int lx = LEVELX(x), ly = LEVELY(y);
1844 int element, content;
1846 if (!IN_LEV_FIELD(lx, ly))
1848 if (lx < -1 || lx > lev_fieldx || ly < -1 || ly > lev_fieldy)
1851 element = getBorderElement(lx, ly);
1853 DrawScreenElement(x, y, element);
1858 element = Feld[lx][ly];
1859 content = Store[lx][ly];
1861 if (IS_MOVING(lx, ly))
1863 int horiz_move = (MovDir[lx][ly] == MV_LEFT || MovDir[lx][ly] == MV_RIGHT);
1864 boolean cut_mode = NO_CUTTING;
1866 if (element == EL_QUICKSAND_EMPTYING ||
1867 element == EL_QUICKSAND_FAST_EMPTYING ||
1868 element == EL_MAGIC_WALL_EMPTYING ||
1869 element == EL_BD_MAGIC_WALL_EMPTYING ||
1870 element == EL_DC_MAGIC_WALL_EMPTYING ||
1871 element == EL_AMOEBA_DROPPING)
1872 cut_mode = CUT_ABOVE;
1873 else if (element == EL_QUICKSAND_FILLING ||
1874 element == EL_QUICKSAND_FAST_FILLING ||
1875 element == EL_MAGIC_WALL_FILLING ||
1876 element == EL_BD_MAGIC_WALL_FILLING ||
1877 element == EL_DC_MAGIC_WALL_FILLING)
1878 cut_mode = CUT_BELOW;
1881 if (lx == 9 && ly == 1)
1882 printf("::: %s [%d] [%d, %d] [%d]\n",
1883 EL_NAME(TILE_GFX_ELEMENT(lx, ly)),
1884 el_act2crm(TILE_GFX_ELEMENT(lx, ly), ACTION_DEFAULT),
1885 element_info[EL_QUICKSAND_EMPTYING].graphic[ACTION_DEFAULT],
1886 element_info[EL_QUICKSAND_EMPTYING].crumbled[ACTION_DEFAULT],
1887 GFX_CRUMBLED(TILE_GFX_ELEMENT(lx, ly)));
1890 if (cut_mode == CUT_ABOVE)
1892 DrawScreenElement(x, y, element);
1894 DrawScreenElementShifted(x, y, 0, 0, element, NO_CUTTING);
1897 DrawScreenElement(x, y, EL_EMPTY);
1900 DrawScreenElementShifted(x, y, MovPos[lx][ly], 0, element, NO_CUTTING);
1901 else if (cut_mode == NO_CUTTING)
1902 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], element, cut_mode);
1905 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], content, cut_mode);
1908 if (cut_mode == CUT_BELOW &&
1909 IN_LEV_FIELD(lx, ly + 1) && IN_SCR_FIELD(x, y + 1))
1910 DrawLevelElement(lx, ly + 1, element);
1914 if (content == EL_ACID)
1916 int dir = MovDir[lx][ly];
1917 int newlx = lx + (dir == MV_LEFT ? -1 : dir == MV_RIGHT ? +1 : 0);
1918 int newly = ly + (dir == MV_UP ? -1 : dir == MV_DOWN ? +1 : 0);
1920 DrawLevelElementThruMask(newlx, newly, EL_ACID);
1923 else if (IS_BLOCKED(lx, ly))
1928 boolean cut_mode = NO_CUTTING;
1929 int element_old, content_old;
1931 Blocked2Moving(lx, ly, &oldx, &oldy);
1934 horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
1935 MovDir[oldx][oldy] == MV_RIGHT);
1937 element_old = Feld[oldx][oldy];
1938 content_old = Store[oldx][oldy];
1940 if (element_old == EL_QUICKSAND_EMPTYING ||
1941 element_old == EL_QUICKSAND_FAST_EMPTYING ||
1942 element_old == EL_MAGIC_WALL_EMPTYING ||
1943 element_old == EL_BD_MAGIC_WALL_EMPTYING ||
1944 element_old == EL_DC_MAGIC_WALL_EMPTYING ||
1945 element_old == EL_AMOEBA_DROPPING)
1946 cut_mode = CUT_ABOVE;
1948 DrawScreenElement(x, y, EL_EMPTY);
1951 DrawScreenElementShifted(sx, sy, MovPos[oldx][oldy], 0, element_old,
1953 else if (cut_mode == NO_CUTTING)
1954 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], element_old,
1957 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], content_old,
1960 else if (IS_DRAWABLE(element))
1961 DrawScreenElement(x, y, element);
1963 DrawScreenElement(x, y, EL_EMPTY);
1966 void DrawLevelField(int x, int y)
1968 if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1969 DrawScreenField(SCREENX(x), SCREENY(y));
1970 else if (IS_MOVING(x, y))
1974 Moving2Blocked(x, y, &newx, &newy);
1975 if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
1976 DrawScreenField(SCREENX(newx), SCREENY(newy));
1978 else if (IS_BLOCKED(x, y))
1982 Blocked2Moving(x, y, &oldx, &oldy);
1983 if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
1984 DrawScreenField(SCREENX(oldx), SCREENY(oldy));
1988 void DrawMiniElement(int x, int y, int element)
1992 graphic = el2edimg(element);
1993 DrawMiniGraphic(x, y, graphic);
1996 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
1998 int x = sx + scroll_x, y = sy + scroll_y;
2000 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
2001 DrawMiniElement(sx, sy, EL_EMPTY);
2002 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
2003 DrawMiniElement(sx, sy, Feld[x][y]);
2005 DrawMiniGraphic(sx, sy, el2edimg(getBorderElement(x, y)));
2008 void DrawEnvelopeBackground(int envelope_nr, int startx, int starty,
2009 int x, int y, int xsize, int ysize, int font_nr)
2011 int font_width = getFontWidth(font_nr);
2012 int font_height = getFontHeight(font_nr);
2013 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
2016 int dst_x = SX + startx + x * font_width;
2017 int dst_y = SY + starty + y * font_height;
2018 int width = graphic_info[graphic].width;
2019 int height = graphic_info[graphic].height;
2020 int inner_width = MAX(width - 2 * font_width, font_width);
2021 int inner_height = MAX(height - 2 * font_height, font_height);
2022 int inner_sx = (width >= 3 * font_width ? font_width : 0);
2023 int inner_sy = (height >= 3 * font_height ? font_height : 0);
2024 boolean draw_masked = graphic_info[graphic].draw_masked;
2026 getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
2028 if (src_bitmap == NULL || width < font_width || height < font_height)
2030 ClearRectangle(drawto, dst_x, dst_y, font_width, font_height);
2034 src_x += (x == 0 ? 0 : x == xsize - 1 ? width - font_width :
2035 inner_sx + (x - 1) * font_width % inner_width);
2036 src_y += (y == 0 ? 0 : y == ysize - 1 ? height - font_height :
2037 inner_sy + (y - 1) * font_height % inner_height);
2041 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
2042 dst_x - src_x, dst_y - src_y);
2043 BlitBitmapMasked(src_bitmap, drawto, src_x, src_y, font_width, font_height,
2047 BlitBitmap(src_bitmap, drawto, src_x, src_y, font_width, font_height,
2051 void AnimateEnvelope(int envelope_nr, int anim_mode, int action)
2053 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
2054 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
2055 int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
2056 boolean ffwd_delay = (tape.playing && tape.fast_forward);
2057 boolean no_delay = (tape.warp_forward);
2058 unsigned long anim_delay = 0;
2059 int frame_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
2060 int anim_delay_value = (no_delay ? 0 : frame_delay_value);
2061 int font_nr = FONT_ENVELOPE_1 + envelope_nr;
2062 int font_width = getFontWidth(font_nr);
2063 int font_height = getFontHeight(font_nr);
2064 int max_xsize = level.envelope[envelope_nr].xsize;
2065 int max_ysize = level.envelope[envelope_nr].ysize;
2066 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize : 0);
2067 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize : 0);
2068 int xend = max_xsize;
2069 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize : 0);
2070 int xstep = (xstart < xend ? 1 : 0);
2071 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
2074 for (x = xstart, y = ystart; x <= xend && y <= yend; x += xstep, y += ystep)
2076 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
2077 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
2078 int sx = (SXSIZE - xsize * font_width) / 2;
2079 int sy = (SYSIZE - ysize * font_height) / 2;
2082 SetDrawtoField(DRAW_BUFFERED);
2084 BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
2086 SetDrawtoField(DRAW_BACKBUFFER);
2088 for (yy = 0; yy < ysize; yy++) for (xx = 0; xx < xsize; xx++)
2089 DrawEnvelopeBackground(envelope_nr, sx,sy, xx,yy, xsize, ysize, font_nr);
2092 DrawTextBuffer(SX + sx + font_width, SY + sy + font_height,
2093 level.envelope[envelope_nr].text, font_nr, max_xsize,
2094 xsize - 2, ysize - 2, mask_mode,
2095 level.envelope[envelope_nr].autowrap,
2096 level.envelope[envelope_nr].centered, FALSE);
2098 DrawTextToTextArea(SX + sx + font_width, SY + sy + font_height,
2099 level.envelope[envelope_nr].text, font_nr, max_xsize,
2100 xsize - 2, ysize - 2, mask_mode);
2103 redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
2106 WaitUntilDelayReached(&anim_delay, anim_delay_value / 2);
2110 void ShowEnvelope(int envelope_nr)
2112 int element = EL_ENVELOPE_1 + envelope_nr;
2113 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
2114 int sound_opening = element_info[element].sound[ACTION_OPENING];
2115 int sound_closing = element_info[element].sound[ACTION_CLOSING];
2116 boolean ffwd_delay = (tape.playing && tape.fast_forward);
2117 boolean no_delay = (tape.warp_forward);
2118 int normal_delay_value = ONE_SECOND_DELAY / (ffwd_delay ? 2 : 1);
2119 int wait_delay_value = (no_delay ? 0 : normal_delay_value);
2120 int anim_mode = graphic_info[graphic].anim_mode;
2121 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
2122 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
2124 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
2126 PlayMenuSoundStereo(sound_opening, SOUND_MIDDLE);
2128 if (anim_mode == ANIM_DEFAULT)
2129 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_OPENING);
2131 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_OPENING);
2134 Delay(wait_delay_value);
2136 WaitForEventToContinue();
2138 PlayMenuSoundStereo(sound_closing, SOUND_MIDDLE);
2140 if (anim_mode != ANIM_NONE)
2141 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_CLOSING);
2143 if (anim_mode == ANIM_DEFAULT)
2144 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_CLOSING);
2146 game.envelope_active = FALSE;
2148 SetDrawtoField(DRAW_BUFFERED);
2150 redraw_mask |= REDRAW_FIELD;
2154 void DrawPreviewElement(int dst_x, int dst_y, int element, int tilesize)
2158 int graphic = el2preimg(element);
2160 getSizedGraphicSource(graphic, 0, tilesize, &src_bitmap, &src_x, &src_y);
2161 BlitBitmap(src_bitmap, drawto, src_x, src_y, tilesize, tilesize, dst_x,dst_y);
2169 SetMainBackgroundImage(IMG_BACKGROUND_PLAYING);
2170 SetDrawBackgroundMask(REDRAW_FIELD);
2172 SetDrawBackgroundMask(REDRAW_NONE);
2177 for (x = BX1; x <= BX2; x++)
2178 for (y = BY1; y <= BY2; y++)
2179 DrawScreenField(x, y);
2181 redraw_mask |= REDRAW_FIELD;
2184 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
2188 for (x = 0; x < size_x; x++)
2189 for (y = 0; y < size_y; y++)
2190 DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
2192 redraw_mask |= REDRAW_FIELD;
2195 static void DrawPreviewLevelExt(int from_x, int from_y)
2197 boolean show_level_border = (BorderElement != EL_EMPTY);
2198 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
2199 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
2200 int tile_size = preview.tile_size;
2201 int preview_width = preview.xsize * tile_size;
2202 int preview_height = preview.ysize * tile_size;
2203 int real_preview_xsize = MIN(level_xsize, preview.xsize);
2204 int real_preview_ysize = MIN(level_ysize, preview.ysize);
2205 int dst_x = SX + ALIGNED_XPOS(preview.x, preview_width, preview.align);
2206 int dst_y = SY + ALIGNED_YPOS(preview.y, preview_height, preview.valign);
2209 DrawBackground(dst_x, dst_y, preview_width, preview_height);
2211 dst_x += (preview_width - real_preview_xsize * tile_size) / 2;
2212 dst_y += (preview_height - real_preview_ysize * tile_size) / 2;
2214 for (x = 0; x < real_preview_xsize; x++)
2216 for (y = 0; y < real_preview_ysize; y++)
2218 int lx = from_x + x + (show_level_border ? -1 : 0);
2219 int ly = from_y + y + (show_level_border ? -1 : 0);
2220 int element = (IN_LEV_FIELD(lx, ly) ? level.field[lx][ly] :
2221 getBorderElement(lx, ly));
2223 DrawPreviewElement(dst_x + x * tile_size, dst_y + y * tile_size,
2224 element, tile_size);
2228 redraw_mask |= REDRAW_MICROLEVEL;
2231 #define MICROLABEL_EMPTY 0
2232 #define MICROLABEL_LEVEL_NAME 1
2233 #define MICROLABEL_LEVEL_AUTHOR_HEAD 2
2234 #define MICROLABEL_LEVEL_AUTHOR 3
2235 #define MICROLABEL_IMPORTED_FROM_HEAD 4
2236 #define MICROLABEL_IMPORTED_FROM 5
2237 #define MICROLABEL_IMPORTED_BY_HEAD 6
2238 #define MICROLABEL_IMPORTED_BY 7
2240 static int getMaxTextLength(struct TextPosInfo *pos, int font_nr)
2242 int max_text_width = SXSIZE;
2243 int font_width = getFontWidth(font_nr);
2245 if (pos->align == ALIGN_CENTER)
2246 max_text_width = (pos->x < SXSIZE / 2 ? pos->x * 2 : (SXSIZE - pos->x) * 2);
2247 else if (pos->align == ALIGN_RIGHT)
2248 max_text_width = pos->x;
2250 max_text_width = SXSIZE - pos->x;
2252 return max_text_width / font_width;
2255 static void DrawPreviewLevelLabelExt(int mode)
2257 struct TextPosInfo *pos = &menu.main.text.level_info_2;
2258 char label_text[MAX_OUTPUT_LINESIZE + 1];
2259 int max_len_label_text;
2261 int font_nr = pos->font;
2264 if (mode == MICROLABEL_LEVEL_AUTHOR_HEAD ||
2265 mode == MICROLABEL_IMPORTED_FROM_HEAD ||
2266 mode == MICROLABEL_IMPORTED_BY_HEAD)
2267 font_nr = pos->font_alt;
2269 int font_nr = FONT_TEXT_2;
2272 if (mode == MICROLABEL_LEVEL_AUTHOR_HEAD ||
2273 mode == MICROLABEL_IMPORTED_FROM_HEAD ||
2274 mode == MICROLABEL_IMPORTED_BY_HEAD)
2275 font_nr = FONT_TEXT_3;
2279 max_len_label_text = getMaxTextLength(pos, font_nr);
2281 max_len_label_text = SXSIZE / getFontWidth(font_nr);
2285 if (pos->size != -1)
2286 max_len_label_text = pos->size;
2289 for (i = 0; i < max_len_label_text; i++)
2290 label_text[i] = ' ';
2291 label_text[max_len_label_text] = '\0';
2293 if (strlen(label_text) > 0)
2296 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
2298 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
2299 int lypos = MICROLABEL2_YPOS;
2301 DrawText(lxpos, lypos, label_text, font_nr);
2306 (mode == MICROLABEL_LEVEL_NAME ? level.name :
2307 mode == MICROLABEL_LEVEL_AUTHOR_HEAD ? "created by" :
2308 mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
2309 mode == MICROLABEL_IMPORTED_FROM_HEAD ? "imported from" :
2310 mode == MICROLABEL_IMPORTED_FROM ? leveldir_current->imported_from :
2311 mode == MICROLABEL_IMPORTED_BY_HEAD ? "imported by" :
2312 mode == MICROLABEL_IMPORTED_BY ? leveldir_current->imported_by :""),
2313 max_len_label_text);
2314 label_text[max_len_label_text] = '\0';
2316 if (strlen(label_text) > 0)
2319 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
2321 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
2322 int lypos = MICROLABEL2_YPOS;
2324 DrawText(lxpos, lypos, label_text, font_nr);
2328 redraw_mask |= REDRAW_MICROLEVEL;
2331 void DrawPreviewLevel(boolean restart)
2333 static unsigned long scroll_delay = 0;
2334 static unsigned long label_delay = 0;
2335 static int from_x, from_y, scroll_direction;
2336 static int label_state, label_counter;
2337 unsigned long scroll_delay_value = preview.step_delay;
2338 boolean show_level_border = (BorderElement != EL_EMPTY);
2339 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
2340 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
2341 int last_game_status = game_status; /* save current game status */
2344 /* force PREVIEW font on preview level */
2345 game_status = GAME_MODE_PSEUDO_PREVIEW;
2353 if (preview.anim_mode == ANIM_CENTERED)
2355 if (level_xsize > preview.xsize)
2356 from_x = (level_xsize - preview.xsize) / 2;
2357 if (level_ysize > preview.ysize)
2358 from_y = (level_ysize - preview.ysize) / 2;
2361 from_x += preview.xoffset;
2362 from_y += preview.yoffset;
2364 scroll_direction = MV_RIGHT;
2368 DrawPreviewLevelExt(from_x, from_y);
2369 DrawPreviewLevelLabelExt(label_state);
2371 /* initialize delay counters */
2372 DelayReached(&scroll_delay, 0);
2373 DelayReached(&label_delay, 0);
2375 if (leveldir_current->name)
2377 struct TextPosInfo *pos = &menu.main.text.level_info_1;
2378 char label_text[MAX_OUTPUT_LINESIZE + 1];
2380 int font_nr = pos->font;
2382 int font_nr = FONT_TEXT_1;
2385 int max_len_label_text = getMaxTextLength(pos, font_nr);
2387 int max_len_label_text = SXSIZE / getFontWidth(font_nr);
2395 if (pos->size != -1)
2396 max_len_label_text = pos->size;
2399 strncpy(label_text, leveldir_current->name, max_len_label_text);
2400 label_text[max_len_label_text] = '\0';
2403 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
2405 lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
2406 lypos = SY + MICROLABEL1_YPOS;
2408 DrawText(lxpos, lypos, label_text, font_nr);
2412 game_status = last_game_status; /* restore current game status */
2417 /* scroll preview level, if needed */
2418 if (preview.anim_mode != ANIM_NONE &&
2419 (level_xsize > preview.xsize || level_ysize > preview.ysize) &&
2420 DelayReached(&scroll_delay, scroll_delay_value))
2422 switch (scroll_direction)
2427 from_x -= preview.step_offset;
2428 from_x = (from_x < 0 ? 0 : from_x);
2431 scroll_direction = MV_UP;
2435 if (from_x < level_xsize - preview.xsize)
2437 from_x += preview.step_offset;
2438 from_x = (from_x > level_xsize - preview.xsize ?
2439 level_xsize - preview.xsize : from_x);
2442 scroll_direction = MV_DOWN;
2448 from_y -= preview.step_offset;
2449 from_y = (from_y < 0 ? 0 : from_y);
2452 scroll_direction = MV_RIGHT;
2456 if (from_y < level_ysize - preview.ysize)
2458 from_y += preview.step_offset;
2459 from_y = (from_y > level_ysize - preview.ysize ?
2460 level_ysize - preview.ysize : from_y);
2463 scroll_direction = MV_LEFT;
2470 DrawPreviewLevelExt(from_x, from_y);
2473 /* !!! THIS ALL SUCKS -- SHOULD BE CLEANLY REWRITTEN !!! */
2474 /* redraw micro level label, if needed */
2475 if (!strEqual(level.name, NAMELESS_LEVEL_NAME) &&
2476 !strEqual(level.author, ANONYMOUS_NAME) &&
2477 !strEqual(level.author, leveldir_current->name) &&
2478 DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
2480 int max_label_counter = 23;
2482 if (leveldir_current->imported_from != NULL &&
2483 strlen(leveldir_current->imported_from) > 0)
2484 max_label_counter += 14;
2485 if (leveldir_current->imported_by != NULL &&
2486 strlen(leveldir_current->imported_by) > 0)
2487 max_label_counter += 14;
2489 label_counter = (label_counter + 1) % max_label_counter;
2490 label_state = (label_counter >= 0 && label_counter <= 7 ?
2491 MICROLABEL_LEVEL_NAME :
2492 label_counter >= 9 && label_counter <= 12 ?
2493 MICROLABEL_LEVEL_AUTHOR_HEAD :
2494 label_counter >= 14 && label_counter <= 21 ?
2495 MICROLABEL_LEVEL_AUTHOR :
2496 label_counter >= 23 && label_counter <= 26 ?
2497 MICROLABEL_IMPORTED_FROM_HEAD :
2498 label_counter >= 28 && label_counter <= 35 ?
2499 MICROLABEL_IMPORTED_FROM :
2500 label_counter >= 37 && label_counter <= 40 ?
2501 MICROLABEL_IMPORTED_BY_HEAD :
2502 label_counter >= 42 && label_counter <= 49 ?
2503 MICROLABEL_IMPORTED_BY : MICROLABEL_EMPTY);
2505 if (leveldir_current->imported_from == NULL &&
2506 (label_state == MICROLABEL_IMPORTED_FROM_HEAD ||
2507 label_state == MICROLABEL_IMPORTED_FROM))
2508 label_state = (label_state == MICROLABEL_IMPORTED_FROM_HEAD ?
2509 MICROLABEL_IMPORTED_BY_HEAD : MICROLABEL_IMPORTED_BY);
2511 DrawPreviewLevelLabelExt(label_state);
2514 game_status = last_game_status; /* restore current game status */
2517 inline void DrawGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
2518 int graphic, int sync_frame, int mask_mode)
2520 int frame = getGraphicAnimationFrame(graphic, sync_frame);
2522 if (mask_mode == USE_MASKING)
2523 DrawGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
2525 DrawGraphicExt(dst_bitmap, x, y, graphic, frame);
2528 inline void DrawGraphicAnimation(int x, int y, int graphic)
2530 int lx = LEVELX(x), ly = LEVELY(y);
2532 if (!IN_SCR_FIELD(x, y))
2535 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
2536 graphic, GfxFrame[lx][ly], NO_MASKING);
2537 MarkTileDirty(x, y);
2540 void DrawLevelGraphicAnimation(int x, int y, int graphic)
2542 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
2545 void DrawLevelElementAnimation(int x, int y, int element)
2547 int graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
2549 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
2552 inline void DrawLevelGraphicAnimationIfNeeded(int x, int y, int graphic)
2554 int sx = SCREENX(x), sy = SCREENY(y);
2556 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
2559 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
2562 DrawGraphicAnimation(sx, sy, graphic);
2565 if (GFX_CRUMBLED(TILE_GFX_ELEMENT(x, y)))
2566 DrawLevelFieldCrumbled(x, y);
2568 if (GFX_CRUMBLED(Feld[x][y]))
2569 DrawLevelFieldCrumbled(x, y);
2573 void DrawLevelElementAnimationIfNeeded(int x, int y, int element)
2575 int sx = SCREENX(x), sy = SCREENY(y);
2578 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
2581 graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
2583 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
2586 DrawGraphicAnimation(sx, sy, graphic);
2588 if (GFX_CRUMBLED(element))
2589 DrawLevelFieldCrumbled(x, y);
2592 static int getPlayerGraphic(struct PlayerInfo *player, int move_dir)
2594 if (player->use_murphy)
2596 /* this works only because currently only one player can be "murphy" ... */
2597 static int last_horizontal_dir = MV_LEFT;
2598 int graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, move_dir);
2600 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
2601 last_horizontal_dir = move_dir;
2603 if (graphic == IMG_SP_MURPHY) /* undefined => use special graphic */
2605 int direction = (player->is_snapping ? move_dir : last_horizontal_dir);
2607 graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, direction);
2613 return el_act_dir2img(player->artwork_element, player->GfxAction,move_dir);
2616 static boolean equalGraphics(int graphic1, int graphic2)
2618 struct GraphicInfo *g1 = &graphic_info[graphic1];
2619 struct GraphicInfo *g2 = &graphic_info[graphic2];
2621 return (g1->bitmap == g2->bitmap &&
2622 g1->src_x == g2->src_x &&
2623 g1->src_y == g2->src_y &&
2624 g1->anim_frames == g2->anim_frames &&
2625 g1->anim_delay == g2->anim_delay &&
2626 g1->anim_mode == g2->anim_mode);
2629 void DrawAllPlayers()
2633 for (i = 0; i < MAX_PLAYERS; i++)
2634 if (stored_player[i].active)
2635 DrawPlayer(&stored_player[i]);
2638 void DrawPlayerField(int x, int y)
2640 if (!IS_PLAYER(x, y))
2643 DrawPlayer(PLAYERINFO(x, y));
2646 #define DRAW_PLAYER_OVER_PUSHED_ELEMENT 1
2648 void DrawPlayer(struct PlayerInfo *player)
2650 int jx = player->jx;
2651 int jy = player->jy;
2652 int move_dir = player->MovDir;
2653 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? +1 : 0);
2654 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? +1 : 0);
2655 int last_jx = (player->is_moving ? jx - dx : jx);
2656 int last_jy = (player->is_moving ? jy - dy : jy);
2657 int next_jx = jx + dx;
2658 int next_jy = jy + dy;
2659 boolean player_is_moving = (player->MovPos ? TRUE : FALSE);
2660 boolean player_is_opaque = FALSE;
2661 int sx = SCREENX(jx), sy = SCREENY(jy);
2662 int sxx = 0, syy = 0;
2663 int element = Feld[jx][jy], last_element = Feld[last_jx][last_jy];
2665 int action = ACTION_DEFAULT;
2666 int last_player_graphic = getPlayerGraphic(player, move_dir);
2667 int last_player_frame = player->Frame;
2670 /* GfxElement[][] is set to the element the player is digging or collecting;
2671 remove also for off-screen player if the player is not moving anymore */
2672 if (IN_LEV_FIELD(jx, jy) && !player_is_moving)
2673 GfxElement[jx][jy] = EL_UNDEFINED;
2675 if (!player->active || !IN_SCR_FIELD(SCREENX(last_jx), SCREENY(last_jy)))
2679 if (!IN_LEV_FIELD(jx, jy))
2681 printf("DrawPlayerField(): x = %d, y = %d\n",jx,jy);
2682 printf("DrawPlayerField(): sx = %d, sy = %d\n",sx,sy);
2683 printf("DrawPlayerField(): This should never happen!\n");
2688 if (element == EL_EXPLOSION)
2691 action = (player->is_pushing ? ACTION_PUSHING :
2692 player->is_digging ? ACTION_DIGGING :
2693 player->is_collecting ? ACTION_COLLECTING :
2694 player->is_moving ? ACTION_MOVING :
2695 player->is_snapping ? ACTION_SNAPPING :
2696 player->is_dropping ? ACTION_DROPPING :
2697 player->is_waiting ? player->action_waiting : ACTION_DEFAULT);
2699 if (player->is_waiting)
2700 move_dir = player->dir_waiting;
2702 InitPlayerGfxAnimation(player, action, move_dir);
2704 /* ----------------------------------------------------------------------- */
2705 /* draw things in the field the player is leaving, if needed */
2706 /* ----------------------------------------------------------------------- */
2708 if (player->is_moving)
2710 if (Back[last_jx][last_jy] && IS_DRAWABLE(last_element))
2712 DrawLevelElement(last_jx, last_jy, Back[last_jx][last_jy]);
2714 if (last_element == EL_DYNAMITE_ACTIVE ||
2715 last_element == EL_EM_DYNAMITE_ACTIVE ||
2716 last_element == EL_SP_DISK_RED_ACTIVE)
2717 DrawDynamite(last_jx, last_jy);
2719 DrawLevelFieldThruMask(last_jx, last_jy);
2721 else if (last_element == EL_DYNAMITE_ACTIVE ||
2722 last_element == EL_EM_DYNAMITE_ACTIVE ||
2723 last_element == EL_SP_DISK_RED_ACTIVE)
2724 DrawDynamite(last_jx, last_jy);
2726 /* !!! this is not enough to prevent flickering of players which are
2727 moving next to each others without a free tile between them -- this
2728 can only be solved by drawing all players layer by layer (first the
2729 background, then the foreground etc.) !!! => TODO */
2730 else if (!IS_PLAYER(last_jx, last_jy))
2731 DrawLevelField(last_jx, last_jy);
2734 DrawLevelField(last_jx, last_jy);
2737 if (player->is_pushing && IN_SCR_FIELD(SCREENX(next_jx), SCREENY(next_jy)))
2738 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
2741 if (!IN_SCR_FIELD(sx, sy))
2744 /* ----------------------------------------------------------------------- */
2745 /* draw things behind the player, if needed */
2746 /* ----------------------------------------------------------------------- */
2749 DrawLevelElement(jx, jy, Back[jx][jy]);
2750 else if (IS_ACTIVE_BOMB(element))
2751 DrawLevelElement(jx, jy, EL_EMPTY);
2754 if (player_is_moving && GfxElement[jx][jy] != EL_UNDEFINED)
2756 int old_element = GfxElement[jx][jy];
2757 int old_graphic = el_act_dir2img(old_element, action, move_dir);
2758 int frame = getGraphicAnimationFrame(old_graphic, player->StepFrame);
2760 if (GFX_CRUMBLED(old_element))
2761 DrawLevelFieldCrumbledDigging(jx, jy, move_dir, player->StepFrame);
2763 DrawGraphic(sx, sy, old_graphic, frame);
2765 if (graphic_info[old_graphic].anim_mode & ANIM_OPAQUE_PLAYER)
2766 player_is_opaque = TRUE;
2770 GfxElement[jx][jy] = EL_UNDEFINED;
2772 /* make sure that pushed elements are drawn with correct frame rate */
2774 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
2776 if (player->is_pushing && player->is_moving && !IS_ANIM_MODE_CE(graphic))
2777 GfxFrame[jx][jy] = player->StepFrame;
2779 if (player->is_pushing && player->is_moving)
2780 GfxFrame[jx][jy] = player->StepFrame;
2783 DrawLevelField(jx, jy);
2787 #if !DRAW_PLAYER_OVER_PUSHED_ELEMENT
2788 /* ----------------------------------------------------------------------- */
2789 /* draw player himself */
2790 /* ----------------------------------------------------------------------- */
2792 graphic = getPlayerGraphic(player, move_dir);
2794 /* in the case of changed player action or direction, prevent the current
2795 animation frame from being restarted for identical animations */
2796 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
2797 player->Frame = last_player_frame;
2799 frame = getGraphicAnimationFrame(graphic, player->Frame);
2803 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
2804 sxx = player->GfxPos;
2806 syy = player->GfxPos;
2809 if (!setup.soft_scrolling && ScreenMovPos)
2812 if (player_is_opaque)
2813 DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
2815 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
2817 if (SHIELD_ON(player))
2819 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
2820 IMG_SHIELD_NORMAL_ACTIVE);
2821 int frame = getGraphicAnimationFrame(graphic, -1);
2823 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
2827 #if DRAW_PLAYER_OVER_PUSHED_ELEMENT
2830 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
2831 sxx = player->GfxPos;
2833 syy = player->GfxPos;
2837 /* ----------------------------------------------------------------------- */
2838 /* draw things the player is pushing, if needed */
2839 /* ----------------------------------------------------------------------- */
2842 printf("::: %d, %d [%d, %d] [%d]\n",
2843 player->is_pushing, player_is_moving, player->GfxAction,
2844 player->is_moving, player_is_moving);
2848 if (player->is_pushing && player->is_moving)
2850 int px = SCREENX(jx), py = SCREENY(jy);
2851 int pxx = (TILEX - ABS(sxx)) * dx;
2852 int pyy = (TILEY - ABS(syy)) * dy;
2853 int gfx_frame = GfxFrame[jx][jy];
2859 if (!IS_MOVING(jx, jy)) /* push movement already finished */
2861 element = Feld[next_jx][next_jy];
2862 gfx_frame = GfxFrame[next_jx][next_jy];
2865 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
2868 sync_frame = (IS_ANIM_MODE_CE(graphic) ? gfx_frame : player->StepFrame);
2869 frame = getGraphicAnimationFrame(graphic, sync_frame);
2871 frame = getGraphicAnimationFrame(graphic, player->StepFrame);
2874 /* draw background element under pushed element (like the Sokoban field) */
2876 if (game.use_masked_pushing && IS_MOVING(jx, jy))
2878 /* this allows transparent pushing animation over non-black background */
2881 DrawLevelElement(jx, jy, Back[jx][jy]);
2883 DrawLevelElement(jx, jy, EL_EMPTY);
2885 if (Back[next_jx][next_jy])
2886 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
2888 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
2890 else if (Back[next_jx][next_jy])
2891 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
2893 if (Back[next_jx][next_jy])
2894 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
2898 printf("::: %d, %d, %d, %d [%d] [%d, %d, %d] [%d] [%d, %d] [%d, %d]\n",
2899 jx, px, player->GfxPos, player->StepFrame,
2904 GfxFrame[jx][jy], GfxFrame[next_jx][next_jy]);
2908 /* do not draw (EM style) pushing animation when pushing is finished */
2909 /* (two-tile animations usually do not contain start and end frame) */
2910 if (graphic_info[graphic].double_movement && !IS_MOVING(jx, jy))
2911 DrawLevelElement(next_jx, next_jy, Feld[next_jx][next_jy]);
2913 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
2915 /* masked drawing is needed for EMC style (double) movement graphics */
2916 /* !!! (ONLY WHEN DRAWING PUSHED ELEMENT OVER THE PLAYER) !!! */
2917 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
2922 #if DRAW_PLAYER_OVER_PUSHED_ELEMENT
2923 /* ----------------------------------------------------------------------- */
2924 /* draw player himself */
2925 /* ----------------------------------------------------------------------- */
2927 graphic = getPlayerGraphic(player, move_dir);
2929 /* in the case of changed player action or direction, prevent the current
2930 animation frame from being restarted for identical animations */
2931 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
2932 player->Frame = last_player_frame;
2934 frame = getGraphicAnimationFrame(graphic, player->Frame);
2938 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
2939 sxx = player->GfxPos;
2941 syy = player->GfxPos;
2944 if (!setup.soft_scrolling && ScreenMovPos)
2947 if (player_is_opaque)
2948 DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
2950 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
2952 if (SHIELD_ON(player))
2954 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
2955 IMG_SHIELD_NORMAL_ACTIVE);
2956 int frame = getGraphicAnimationFrame(graphic, -1);
2958 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
2962 /* ----------------------------------------------------------------------- */
2963 /* draw things in front of player (active dynamite or dynabombs) */
2964 /* ----------------------------------------------------------------------- */
2966 if (IS_ACTIVE_BOMB(element))
2968 graphic = el2img(element);
2969 frame = getGraphicAnimationFrame(graphic, GfxFrame[jx][jy]);
2971 if (game.emulation == EMU_SUPAPLEX)
2972 DrawGraphic(sx, sy, IMG_SP_DISK_RED, frame);
2974 DrawGraphicThruMask(sx, sy, graphic, frame);
2977 if (player_is_moving && last_element == EL_EXPLOSION)
2979 int element = (GfxElement[last_jx][last_jy] != EL_UNDEFINED ?
2980 GfxElement[last_jx][last_jy] : EL_EMPTY);
2981 int graphic = el_act2img(element, ACTION_EXPLODING);
2982 int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
2983 int phase = ExplodePhase[last_jx][last_jy] - 1;
2984 int frame = getGraphicAnimationFrame(graphic, phase - delay);
2987 DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy), graphic, frame);
2990 /* ----------------------------------------------------------------------- */
2991 /* draw elements the player is just walking/passing through/under */
2992 /* ----------------------------------------------------------------------- */
2994 if (player_is_moving)
2996 /* handle the field the player is leaving ... */
2997 if (IS_ACCESSIBLE_INSIDE(last_element))
2998 DrawLevelField(last_jx, last_jy);
2999 else if (IS_ACCESSIBLE_UNDER(last_element))
3000 DrawLevelFieldThruMask(last_jx, last_jy);
3003 /* do not redraw accessible elements if the player is just pushing them */
3004 if (!player_is_moving || !player->is_pushing)
3006 /* ... and the field the player is entering */
3007 if (IS_ACCESSIBLE_INSIDE(element))
3008 DrawLevelField(jx, jy);
3009 else if (IS_ACCESSIBLE_UNDER(element))
3010 DrawLevelFieldThruMask(jx, jy);
3013 MarkTileDirty(sx, sy);
3016 /* ------------------------------------------------------------------------- */
3018 void WaitForEventToContinue()
3020 boolean still_wait = TRUE;
3022 /* simulate releasing mouse button over last gadget, if still pressed */
3024 HandleGadgets(-1, -1, 0);
3026 button_status = MB_RELEASED;
3042 case EVENT_BUTTONPRESS:
3043 case EVENT_KEYPRESS:
3047 case EVENT_KEYRELEASE:
3048 ClearPlayerAction();
3052 HandleOtherEvents(&event);
3056 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
3063 /* don't eat all CPU time */
3068 #define MAX_REQUEST_LINES 13
3069 #define MAX_REQUEST_LINE_FONT1_LEN 7
3070 #define MAX_REQUEST_LINE_FONT2_LEN 10
3072 boolean Request(char *text, unsigned int req_state)
3074 int mx, my, ty, result = -1;
3075 unsigned int old_door_state;
3076 int last_game_status = game_status; /* save current game status */
3077 int max_request_line_len = MAX_REQUEST_LINE_FONT1_LEN;
3078 int font_nr = FONT_TEXT_2;
3079 int max_word_len = 0;
3082 for (text_ptr = text; *text_ptr; text_ptr++)
3084 max_word_len = (*text_ptr != ' ' ? max_word_len + 1 : 0);
3086 if (max_word_len > MAX_REQUEST_LINE_FONT1_LEN)
3088 max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
3090 font_nr = FONT_TEXT_1;
3092 font_nr = FONT_LEVEL_NUMBER;
3099 if (game_status == GAME_MODE_PLAYING)
3101 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
3102 BlitScreenToBitmap_EM(backbuffer);
3103 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
3104 BlitScreenToBitmap_SP(backbuffer);
3107 /* disable deactivated drawing when quick-loading level tape recording */
3108 if (tape.playing && tape.deactivate_display)
3109 TapeDeactivateDisplayOff(TRUE);
3111 SetMouseCursor(CURSOR_DEFAULT);
3113 #if defined(NETWORK_AVALIABLE)
3114 /* pause network game while waiting for request to answer */
3115 if (options.network &&
3116 game_status == GAME_MODE_PLAYING &&
3117 req_state & REQUEST_WAIT_FOR_INPUT)
3118 SendToServer_PausePlaying();
3121 old_door_state = GetDoorState();
3123 /* simulate releasing mouse button over last gadget, if still pressed */
3125 HandleGadgets(-1, -1, 0);
3129 if (old_door_state & DOOR_OPEN_1)
3131 CloseDoor(DOOR_CLOSE_1);
3133 /* save old door content */
3134 BlitBitmap(bitmap_db_door, bitmap_db_door,
3135 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
3136 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
3140 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
3143 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
3145 /* clear door drawing field */
3146 DrawBackground(DX, DY, DXSIZE, DYSIZE);
3148 /* force DOOR font inside door area */
3149 game_status = GAME_MODE_PSEUDO_DOOR;
3151 /* write text for request */
3152 for (ty = 0; ty < MAX_REQUEST_LINES; ty++)
3154 char text_line[max_request_line_len + 1];
3160 for (tl = 0, tx = 0; tx < max_request_line_len; tl++, tx++)
3163 if (!tc || tc == ' ')
3174 strncpy(text_line, text, tl);
3177 DrawText(DX + (DXSIZE - tl * getFontWidth(font_nr)) / 2,
3178 DY + 8 + ty * (getFontHeight(font_nr) + 2),
3179 text_line, font_nr);
3181 text += tl + (tc == ' ' ? 1 : 0);
3184 game_status = last_game_status; /* restore current game status */
3186 if (req_state & REQ_ASK)
3188 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
3189 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
3191 else if (req_state & REQ_CONFIRM)
3193 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
3195 else if (req_state & REQ_PLAYER)
3197 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
3198 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
3199 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
3200 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
3203 /* copy request gadgets to door backbuffer */
3204 BlitBitmap(drawto, bitmap_db_door,
3205 DX, DY, DXSIZE, DYSIZE,
3206 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
3208 OpenDoor(DOOR_OPEN_1);
3210 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
3212 if (game_status == GAME_MODE_PLAYING)
3214 SetPanelBackground();
3215 SetDrawBackgroundMask(REDRAW_DOOR_1);
3219 SetDrawBackgroundMask(REDRAW_FIELD);
3225 if (game_status != GAME_MODE_MAIN)
3228 button_status = MB_RELEASED;
3230 request_gadget_id = -1;
3232 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
3244 case EVENT_BUTTONPRESS:
3245 case EVENT_BUTTONRELEASE:
3246 case EVENT_MOTIONNOTIFY:
3248 if (event.type == EVENT_MOTIONNOTIFY)
3250 if (!PointerInWindow(window))
3251 continue; /* window and pointer are on different screens */
3256 motion_status = TRUE;
3257 mx = ((MotionEvent *) &event)->x;
3258 my = ((MotionEvent *) &event)->y;
3262 motion_status = FALSE;
3263 mx = ((ButtonEvent *) &event)->x;
3264 my = ((ButtonEvent *) &event)->y;
3265 if (event.type == EVENT_BUTTONPRESS)
3266 button_status = ((ButtonEvent *) &event)->button;
3268 button_status = MB_RELEASED;
3271 /* this sets 'request_gadget_id' */
3272 HandleGadgets(mx, my, button_status);
3274 switch (request_gadget_id)
3276 case TOOL_CTRL_ID_YES:
3279 case TOOL_CTRL_ID_NO:
3282 case TOOL_CTRL_ID_CONFIRM:
3283 result = TRUE | FALSE;
3286 case TOOL_CTRL_ID_PLAYER_1:
3289 case TOOL_CTRL_ID_PLAYER_2:
3292 case TOOL_CTRL_ID_PLAYER_3:
3295 case TOOL_CTRL_ID_PLAYER_4:
3306 case EVENT_KEYPRESS:
3307 switch (GetEventKey((KeyEvent *)&event, TRUE))
3310 if (req_state & REQ_CONFIRM)
3326 if (req_state & REQ_PLAYER)
3330 case EVENT_KEYRELEASE:
3331 ClearPlayerAction();
3335 HandleOtherEvents(&event);
3339 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
3341 int joy = AnyJoystick();
3343 if (joy & JOY_BUTTON_1)
3345 else if (joy & JOY_BUTTON_2)
3351 if (game_status == GAME_MODE_PLAYING && local_player->LevelSolved_GameEnd)
3353 HandleGameActions();
3359 if (!PendingEvent()) /* delay only if no pending events */
3370 if (!PendingEvent()) /* delay only if no pending events */
3373 /* don't eat all CPU time */
3380 if (game_status != GAME_MODE_MAIN)
3385 if (!(req_state & REQ_STAY_OPEN))
3387 CloseDoor(DOOR_CLOSE_1);
3389 if (((old_door_state & DOOR_OPEN_1) && !(req_state & REQ_STAY_CLOSED)) ||
3390 (req_state & REQ_REOPEN))
3391 OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
3396 if (game_status == GAME_MODE_PLAYING)
3398 SetPanelBackground();
3399 SetDrawBackgroundMask(REDRAW_DOOR_1);
3403 SetDrawBackgroundMask(REDRAW_FIELD);
3406 #if defined(NETWORK_AVALIABLE)
3407 /* continue network game after request */
3408 if (options.network &&
3409 game_status == GAME_MODE_PLAYING &&
3410 req_state & REQUEST_WAIT_FOR_INPUT)
3411 SendToServer_ContinuePlaying();
3414 /* restore deactivated drawing when quick-loading level tape recording */
3415 if (tape.playing && tape.deactivate_display)
3416 TapeDeactivateDisplayOn();
3421 unsigned int OpenDoor(unsigned int door_state)
3423 if (door_state & DOOR_COPY_BACK)
3425 if (door_state & DOOR_OPEN_1)
3426 BlitBitmap(bitmap_db_door, bitmap_db_door,
3427 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
3428 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
3430 if (door_state & DOOR_OPEN_2)
3431 BlitBitmap(bitmap_db_door, bitmap_db_door,
3432 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY2, VXSIZE, VYSIZE,
3433 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
3435 door_state &= ~DOOR_COPY_BACK;
3438 return MoveDoor(door_state);
3441 unsigned int CloseDoor(unsigned int door_state)
3443 unsigned int old_door_state = GetDoorState();
3445 if (!(door_state & DOOR_NO_COPY_BACK))
3447 if (old_door_state & DOOR_OPEN_1)
3448 BlitBitmap(backbuffer, bitmap_db_door,
3449 DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
3451 if (old_door_state & DOOR_OPEN_2)
3452 BlitBitmap(backbuffer, bitmap_db_door,
3453 VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
3455 door_state &= ~DOOR_NO_COPY_BACK;
3458 return MoveDoor(door_state);
3461 unsigned int GetDoorState()
3463 return MoveDoor(DOOR_GET_STATE);
3466 unsigned int SetDoorState(unsigned int door_state)
3468 return MoveDoor(door_state | DOOR_SET_STATE);
3471 unsigned int MoveDoor(unsigned int door_state)
3473 static int door1 = DOOR_OPEN_1;
3474 static int door2 = DOOR_CLOSE_2;
3475 unsigned long door_delay = 0;
3476 unsigned long door_delay_value;
3479 if (door_1.width < 0 || door_1.width > DXSIZE)
3480 door_1.width = DXSIZE;
3481 if (door_1.height < 0 || door_1.height > DYSIZE)
3482 door_1.height = DYSIZE;
3483 if (door_2.width < 0 || door_2.width > VXSIZE)
3484 door_2.width = VXSIZE;
3485 if (door_2.height < 0 || door_2.height > VYSIZE)
3486 door_2.height = VYSIZE;
3488 if (door_state == DOOR_GET_STATE)
3489 return (door1 | door2);
3491 if (door_state & DOOR_SET_STATE)
3493 if (door_state & DOOR_ACTION_1)
3494 door1 = door_state & DOOR_ACTION_1;
3495 if (door_state & DOOR_ACTION_2)
3496 door2 = door_state & DOOR_ACTION_2;
3498 return (door1 | door2);
3501 if (!(door_state & DOOR_FORCE_REDRAW))
3503 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
3504 door_state &= ~DOOR_OPEN_1;
3505 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
3506 door_state &= ~DOOR_CLOSE_1;
3507 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
3508 door_state &= ~DOOR_OPEN_2;
3509 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
3510 door_state &= ~DOOR_CLOSE_2;
3513 door_delay_value = (door_state & DOOR_ACTION_1 ? door_1.step_delay :
3516 if (setup.quick_doors)
3518 stepsize = 20; /* must be chosen to always draw last frame */
3519 door_delay_value = 0;
3522 if (global.autoplay_leveldir)
3524 door_state |= DOOR_NO_DELAY;
3525 door_state &= ~DOOR_CLOSE_ALL;
3529 if (game_status == GAME_MODE_EDITOR)
3530 door_state |= DOOR_NO_DELAY;
3533 if (door_state & DOOR_ACTION)
3535 boolean handle_door_1 = (door_state & DOOR_ACTION_1);
3536 boolean handle_door_2 = (door_state & DOOR_ACTION_2);
3537 boolean door_1_done = (!handle_door_1);
3538 boolean door_2_done = (!handle_door_2);
3539 boolean door_1_vertical = (door_1.anim_mode & ANIM_VERTICAL);
3540 boolean door_2_vertical = (door_2.anim_mode & ANIM_VERTICAL);
3541 int door_size_1 = (door_1_vertical ? door_1.height : door_1.width);
3542 int door_size_2 = (door_2_vertical ? door_2.height : door_2.width);
3543 int max_door_size_1 = (door_1_vertical ? DYSIZE : DXSIZE);
3544 int max_door_size_2 = (door_2_vertical ? VYSIZE : VXSIZE);
3545 int door_size = (handle_door_1 ? door_size_1 : door_size_2);
3546 int max_door_size = (handle_door_1 ? max_door_size_1 : max_door_size_2);
3547 int door_skip = max_door_size - door_size;
3548 int end = door_size;
3549 int start = ((door_state & DOOR_NO_DELAY) ? end : 0);
3552 if (!(door_state & DOOR_NO_DELAY) && !setup.quick_doors)
3554 /* opening door sound has priority over simultaneously closing door */
3555 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
3556 PlayMenuSoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
3557 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
3558 PlayMenuSoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
3561 for (k = start; k <= end && !(door_1_done && door_2_done); k += stepsize)
3564 Bitmap *bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
3565 GC gc = bitmap->stored_clip_gc;
3567 if (door_state & DOOR_ACTION_1)
3569 int a = MIN(x * door_1.step_offset, end);
3570 int p = (door_state & DOOR_OPEN_1 ? end - a : a);
3571 int i = p + door_skip;
3573 if (door_1.anim_mode & ANIM_STATIC_PANEL)
3575 BlitBitmap(bitmap_db_door, drawto,
3576 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1,
3577 DXSIZE, DYSIZE, DX, DY);
3581 BlitBitmap(bitmap_db_door, drawto,
3582 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + p / 2,
3583 DXSIZE, DYSIZE - p / 2, DX, DY);
3585 ClearRectangle(drawto, DX, DY + DYSIZE - p / 2, DXSIZE, p / 2);
3588 if (door_1.anim_mode & ANIM_HORIZONTAL && x <= DXSIZE)
3590 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
3591 int dst1_x = DX + DXSIZE - i, dst1_y = DY;
3592 int src2_x = DXSIZE - i, src2_y = DOOR_GFX_PAGEY1;
3593 int dst2_x = DX, dst2_y = DY;
3594 int width = i, height = DYSIZE;
3596 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
3597 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
3600 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
3601 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
3604 else if (door_1.anim_mode & ANIM_VERTICAL && x <= DYSIZE)
3606 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
3607 int dst1_x = DX, dst1_y = DY + DYSIZE - i;
3608 int src2_x = 0, src2_y = DOOR_GFX_PAGEY1 + DYSIZE - i;
3609 int dst2_x = DX, dst2_y = DY;
3610 int width = DXSIZE, height = i;
3612 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
3613 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
3616 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
3617 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
3620 else if (x <= DXSIZE) /* ANIM_DEFAULT */
3622 int j = (door_1.anim_mode == ANIM_DEFAULT ? (DXSIZE - i) / 3 : 0);
3624 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
3625 BlitBitmapMasked(bitmap, drawto,
3626 DXSIZE, DOOR_GFX_PAGEY1, i, 77,
3627 DX + DXSIZE - i, DY + j);
3628 BlitBitmapMasked(bitmap, drawto,
3629 DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63,
3630 DX + DXSIZE - i, DY + 140 + j);
3631 SetClipOrigin(bitmap, gc, DX - DXSIZE + i,
3632 DY - (DOOR_GFX_PAGEY1 + j));
3633 BlitBitmapMasked(bitmap, drawto,
3634 DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j,
3636 BlitBitmapMasked(bitmap, drawto,
3637 DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63,
3640 BlitBitmapMasked(bitmap, drawto,
3641 DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
3643 BlitBitmapMasked(bitmap, drawto,
3644 DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
3646 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
3647 BlitBitmapMasked(bitmap, drawto,
3648 DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
3649 DX + DXSIZE - i, DY + 77 + j);
3650 BlitBitmapMasked(bitmap, drawto,
3651 DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
3652 DX + DXSIZE - i, DY + 203 + j);
3655 redraw_mask |= REDRAW_DOOR_1;
3656 door_1_done = (a == end);
3659 if (door_state & DOOR_ACTION_2)
3661 int a = MIN(x * door_2.step_offset, door_size);
3662 int p = (door_state & DOOR_OPEN_2 ? door_size - a : a);
3663 int i = p + door_skip;
3665 if (door_2.anim_mode & ANIM_STATIC_PANEL)
3667 BlitBitmap(bitmap_db_door, drawto,
3668 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2,
3669 VXSIZE, VYSIZE, VX, VY);
3671 else if (x <= VYSIZE)
3673 BlitBitmap(bitmap_db_door, drawto,
3674 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + p / 2,
3675 VXSIZE, VYSIZE - p / 2, VX, VY);
3677 ClearRectangle(drawto, VX, VY + VYSIZE - p / 2, VXSIZE, p / 2);
3680 if (door_2.anim_mode & ANIM_HORIZONTAL && x <= VXSIZE)
3682 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
3683 int dst1_x = VX + VXSIZE - i, dst1_y = VY;
3684 int src2_x = VXSIZE - i, src2_y = DOOR_GFX_PAGEY2;
3685 int dst2_x = VX, dst2_y = VY;
3686 int width = i, height = VYSIZE;
3688 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
3689 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
3692 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
3693 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
3696 else if (door_2.anim_mode & ANIM_VERTICAL && x <= VYSIZE)
3698 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
3699 int dst1_x = VX, dst1_y = VY + VYSIZE - i;
3700 int src2_x = 0, src2_y = DOOR_GFX_PAGEY2 + VYSIZE - i;
3701 int dst2_x = VX, dst2_y = VY;
3702 int width = VXSIZE, height = i;
3704 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
3705 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
3708 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
3709 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
3712 else if (x <= VXSIZE) /* ANIM_DEFAULT */
3714 int j = (door_2.anim_mode == ANIM_DEFAULT ? (VXSIZE - i) / 3 : 0);
3716 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
3717 BlitBitmapMasked(bitmap, drawto,
3718 VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2,
3719 VX + VXSIZE - i, VY + j);
3720 SetClipOrigin(bitmap, gc,
3721 VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
3722 BlitBitmapMasked(bitmap, drawto,
3723 VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j,
3726 BlitBitmapMasked(bitmap, drawto,
3727 VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2,
3728 i, VYSIZE / 2, VX, VY + VYSIZE / 2 - j);
3729 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
3730 BlitBitmapMasked(bitmap, drawto,
3731 VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2,
3733 VX + VXSIZE - i, VY + VYSIZE / 2 + j);
3736 redraw_mask |= REDRAW_DOOR_2;
3737 door_2_done = (a == VXSIZE);
3740 if (!(door_state & DOOR_NO_DELAY))
3744 if (game_status == GAME_MODE_MAIN)
3747 WaitUntilDelayReached(&door_delay, door_delay_value);
3752 if (door_state & DOOR_ACTION_1)
3753 door1 = door_state & DOOR_ACTION_1;
3754 if (door_state & DOOR_ACTION_2)
3755 door2 = door_state & DOOR_ACTION_2;
3757 return (door1 | door2);
3760 void DrawSpecialEditorDoor()
3762 /* draw bigger toolbox window */
3763 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
3764 DOOR_GFX_PAGEX7, 0, EXSIZE + 8, 8,
3766 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
3767 EX - 6, VY - 4, EXSIZE + 12, EYSIZE - VYSIZE + 4,
3770 redraw_mask |= REDRAW_ALL;
3773 void UndrawSpecialEditorDoor()
3775 /* draw normal tape recorder window */
3776 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
3777 EX - 6, EY - 12, EXSIZE + 12, EYSIZE - VYSIZE + 12,
3780 redraw_mask |= REDRAW_ALL;
3784 /* ---------- new tool button stuff ---------------------------------------- */
3786 /* graphic position values for tool buttons */
3787 #define TOOL_BUTTON_YES_XPOS 2
3788 #define TOOL_BUTTON_YES_YPOS 250
3789 #define TOOL_BUTTON_YES_GFX_YPOS 0
3790 #define TOOL_BUTTON_YES_XSIZE 46
3791 #define TOOL_BUTTON_YES_YSIZE 28
3792 #define TOOL_BUTTON_NO_XPOS 52
3793 #define TOOL_BUTTON_NO_YPOS TOOL_BUTTON_YES_YPOS
3794 #define TOOL_BUTTON_NO_GFX_YPOS TOOL_BUTTON_YES_GFX_YPOS
3795 #define TOOL_BUTTON_NO_XSIZE TOOL_BUTTON_YES_XSIZE
3796 #define TOOL_BUTTON_NO_YSIZE TOOL_BUTTON_YES_YSIZE
3797 #define TOOL_BUTTON_CONFIRM_XPOS TOOL_BUTTON_YES_XPOS
3798 #define TOOL_BUTTON_CONFIRM_YPOS TOOL_BUTTON_YES_YPOS
3799 #define TOOL_BUTTON_CONFIRM_GFX_YPOS 30
3800 #define TOOL_BUTTON_CONFIRM_XSIZE 96
3801 #define TOOL_BUTTON_CONFIRM_YSIZE TOOL_BUTTON_YES_YSIZE
3802 #define TOOL_BUTTON_PLAYER_XSIZE 30
3803 #define TOOL_BUTTON_PLAYER_YSIZE 30
3804 #define TOOL_BUTTON_PLAYER_GFX_XPOS 5
3805 #define TOOL_BUTTON_PLAYER_GFX_YPOS 185
3806 #define TOOL_BUTTON_PLAYER_XPOS (5 + TOOL_BUTTON_PLAYER_XSIZE / 2)
3807 #define TOOL_BUTTON_PLAYER_YPOS (215 - TOOL_BUTTON_PLAYER_YSIZE / 2)
3808 #define TOOL_BUTTON_PLAYER1_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3809 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
3810 #define TOOL_BUTTON_PLAYER2_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3811 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
3812 #define TOOL_BUTTON_PLAYER3_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3813 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
3814 #define TOOL_BUTTON_PLAYER4_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3815 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
3816 #define TOOL_BUTTON_PLAYER1_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3817 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
3818 #define TOOL_BUTTON_PLAYER2_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3819 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
3820 #define TOOL_BUTTON_PLAYER3_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3821 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
3822 #define TOOL_BUTTON_PLAYER4_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3823 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
3832 } toolbutton_info[NUM_TOOL_BUTTONS] =
3835 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_GFX_YPOS,
3836 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_YPOS,
3837 TOOL_BUTTON_YES_XSIZE, TOOL_BUTTON_YES_YSIZE,
3842 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_GFX_YPOS,
3843 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_YPOS,
3844 TOOL_BUTTON_NO_XSIZE, TOOL_BUTTON_NO_YSIZE,
3849 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_GFX_YPOS,
3850 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_YPOS,
3851 TOOL_BUTTON_CONFIRM_XSIZE, TOOL_BUTTON_CONFIRM_YSIZE,
3852 TOOL_CTRL_ID_CONFIRM,
3856 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3857 TOOL_BUTTON_PLAYER1_XPOS, TOOL_BUTTON_PLAYER1_YPOS,
3858 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3859 TOOL_CTRL_ID_PLAYER_1,
3863 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3864 TOOL_BUTTON_PLAYER2_XPOS, TOOL_BUTTON_PLAYER2_YPOS,
3865 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3866 TOOL_CTRL_ID_PLAYER_2,
3870 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3871 TOOL_BUTTON_PLAYER3_XPOS, TOOL_BUTTON_PLAYER3_YPOS,
3872 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3873 TOOL_CTRL_ID_PLAYER_3,
3877 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3878 TOOL_BUTTON_PLAYER4_XPOS, TOOL_BUTTON_PLAYER4_YPOS,
3879 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3880 TOOL_CTRL_ID_PLAYER_4,
3885 void CreateToolButtons()
3889 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3891 Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
3892 Bitmap *deco_bitmap = None;
3893 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
3894 struct GadgetInfo *gi;
3895 unsigned long event_mask;
3896 int gd_xoffset, gd_yoffset;
3897 int gd_x1, gd_x2, gd_y;
3900 event_mask = GD_EVENT_RELEASED;
3902 gd_xoffset = toolbutton_info[i].xpos;
3903 gd_yoffset = toolbutton_info[i].ypos;
3904 gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
3905 gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
3906 gd_y = DOOR_GFX_PAGEY1 + gd_yoffset;
3908 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
3910 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
3912 getMiniGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr),
3913 &deco_bitmap, &deco_x, &deco_y);
3914 deco_xpos = (toolbutton_info[i].width - MINI_TILEX) / 2;
3915 deco_ypos = (toolbutton_info[i].height - MINI_TILEY) / 2;
3918 gi = CreateGadget(GDI_CUSTOM_ID, id,
3919 GDI_INFO_TEXT, toolbutton_info[i].infotext,
3920 GDI_X, DX + toolbutton_info[i].x,
3921 GDI_Y, DY + toolbutton_info[i].y,
3922 GDI_WIDTH, toolbutton_info[i].width,
3923 GDI_HEIGHT, toolbutton_info[i].height,
3924 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
3925 GDI_STATE, GD_BUTTON_UNPRESSED,
3926 GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
3927 GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
3928 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
3929 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
3930 GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
3931 GDI_DECORATION_SHIFTING, 1, 1,
3932 GDI_DIRECT_DRAW, FALSE,
3933 GDI_EVENT_MASK, event_mask,
3934 GDI_CALLBACK_ACTION, HandleToolButtons,
3938 Error(ERR_EXIT, "cannot create gadget");
3940 tool_gadget[id] = gi;
3944 void FreeToolButtons()
3948 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3949 FreeGadget(tool_gadget[i]);
3952 static void UnmapToolButtons()
3956 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3957 UnmapGadget(tool_gadget[i]);
3960 static void HandleToolButtons(struct GadgetInfo *gi)
3962 request_gadget_id = gi->custom_id;
3965 static struct Mapping_EM_to_RND_object
3968 boolean is_rnd_to_em_mapping; /* unique mapping EM <-> RND */
3969 boolean is_backside; /* backside of moving element */
3975 em_object_mapping_list[] =
3978 Xblank, TRUE, FALSE,
3982 Yacid_splash_eB, FALSE, FALSE,
3983 EL_ACID_SPLASH_RIGHT, -1, -1
3986 Yacid_splash_wB, FALSE, FALSE,
3987 EL_ACID_SPLASH_LEFT, -1, -1
3990 #ifdef EM_ENGINE_BAD_ROLL
3992 Xstone_force_e, FALSE, FALSE,
3993 EL_ROCK, -1, MV_BIT_RIGHT
3996 Xstone_force_w, FALSE, FALSE,
3997 EL_ROCK, -1, MV_BIT_LEFT
4000 Xnut_force_e, FALSE, FALSE,
4001 EL_NUT, -1, MV_BIT_RIGHT
4004 Xnut_force_w, FALSE, FALSE,
4005 EL_NUT, -1, MV_BIT_LEFT
4008 Xspring_force_e, FALSE, FALSE,
4009 EL_SPRING, -1, MV_BIT_RIGHT
4012 Xspring_force_w, FALSE, FALSE,
4013 EL_SPRING, -1, MV_BIT_LEFT
4016 Xemerald_force_e, FALSE, FALSE,
4017 EL_EMERALD, -1, MV_BIT_RIGHT
4020 Xemerald_force_w, FALSE, FALSE,
4021 EL_EMERALD, -1, MV_BIT_LEFT
4024 Xdiamond_force_e, FALSE, FALSE,
4025 EL_DIAMOND, -1, MV_BIT_RIGHT
4028 Xdiamond_force_w, FALSE, FALSE,
4029 EL_DIAMOND, -1, MV_BIT_LEFT
4032 Xbomb_force_e, FALSE, FALSE,
4033 EL_BOMB, -1, MV_BIT_RIGHT
4036 Xbomb_force_w, FALSE, FALSE,
4037 EL_BOMB, -1, MV_BIT_LEFT
4039 #endif /* EM_ENGINE_BAD_ROLL */
4042 Xstone, TRUE, FALSE,
4046 Xstone_pause, FALSE, FALSE,
4050 Xstone_fall, FALSE, FALSE,
4054 Ystone_s, FALSE, FALSE,
4055 EL_ROCK, ACTION_FALLING, -1
4058 Ystone_sB, FALSE, TRUE,
4059 EL_ROCK, ACTION_FALLING, -1
4062 Ystone_e, FALSE, FALSE,
4063 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
4066 Ystone_eB, FALSE, TRUE,
4067 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
4070 Ystone_w, FALSE, FALSE,
4071 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
4074 Ystone_wB, FALSE, TRUE,
4075 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
4082 Xnut_pause, FALSE, FALSE,
4086 Xnut_fall, FALSE, FALSE,
4090 Ynut_s, FALSE, FALSE,
4091 EL_NUT, ACTION_FALLING, -1
4094 Ynut_sB, FALSE, TRUE,
4095 EL_NUT, ACTION_FALLING, -1
4098 Ynut_e, FALSE, FALSE,
4099 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
4102 Ynut_eB, FALSE, TRUE,
4103 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
4106 Ynut_w, FALSE, FALSE,
4107 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
4110 Ynut_wB, FALSE, TRUE,
4111 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
4114 Xbug_n, TRUE, FALSE,
4118 Xbug_e, TRUE, FALSE,
4119 EL_BUG_RIGHT, -1, -1
4122 Xbug_s, TRUE, FALSE,
4126 Xbug_w, TRUE, FALSE,
4130 Xbug_gon, FALSE, FALSE,
4134 Xbug_goe, FALSE, FALSE,
4135 EL_BUG_RIGHT, -1, -1
4138 Xbug_gos, FALSE, FALSE,
4142 Xbug_gow, FALSE, FALSE,
4146 Ybug_n, FALSE, FALSE,
4147 EL_BUG, ACTION_MOVING, MV_BIT_UP
4150 Ybug_nB, FALSE, TRUE,
4151 EL_BUG, ACTION_MOVING, MV_BIT_UP
4154 Ybug_e, FALSE, FALSE,
4155 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
4158 Ybug_eB, FALSE, TRUE,
4159 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
4162 Ybug_s, FALSE, FALSE,
4163 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
4166 Ybug_sB, FALSE, TRUE,
4167 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
4170 Ybug_w, FALSE, FALSE,
4171 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
4174 Ybug_wB, FALSE, TRUE,
4175 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
4178 Ybug_w_n, FALSE, FALSE,
4179 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
4182 Ybug_n_e, FALSE, FALSE,
4183 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
4186 Ybug_e_s, FALSE, FALSE,
4187 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
4190 Ybug_s_w, FALSE, FALSE,
4191 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
4194 Ybug_e_n, FALSE, FALSE,
4195 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
4198 Ybug_s_e, FALSE, FALSE,
4199 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
4202 Ybug_w_s, FALSE, FALSE,
4203 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
4206 Ybug_n_w, FALSE, FALSE,
4207 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
4210 Ybug_stone, FALSE, FALSE,
4211 EL_BUG, ACTION_SMASHED_BY_ROCK, -1
4214 Ybug_spring, FALSE, FALSE,
4215 EL_BUG, ACTION_SMASHED_BY_SPRING, -1
4218 Xtank_n, TRUE, FALSE,
4219 EL_SPACESHIP_UP, -1, -1
4222 Xtank_e, TRUE, FALSE,
4223 EL_SPACESHIP_RIGHT, -1, -1
4226 Xtank_s, TRUE, FALSE,
4227 EL_SPACESHIP_DOWN, -1, -1
4230 Xtank_w, TRUE, FALSE,
4231 EL_SPACESHIP_LEFT, -1, -1
4234 Xtank_gon, FALSE, FALSE,
4235 EL_SPACESHIP_UP, -1, -1
4238 Xtank_goe, FALSE, FALSE,
4239 EL_SPACESHIP_RIGHT, -1, -1
4242 Xtank_gos, FALSE, FALSE,
4243 EL_SPACESHIP_DOWN, -1, -1
4246 Xtank_gow, FALSE, FALSE,
4247 EL_SPACESHIP_LEFT, -1, -1
4250 Ytank_n, FALSE, FALSE,
4251 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
4254 Ytank_nB, FALSE, TRUE,
4255 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
4258 Ytank_e, FALSE, FALSE,
4259 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
4262 Ytank_eB, FALSE, TRUE,
4263 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
4266 Ytank_s, FALSE, FALSE,
4267 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
4270 Ytank_sB, FALSE, TRUE,
4271 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
4274 Ytank_w, FALSE, FALSE,
4275 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
4278 Ytank_wB, FALSE, TRUE,
4279 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
4282 Ytank_w_n, FALSE, FALSE,
4283 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
4286 Ytank_n_e, FALSE, FALSE,
4287 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
4290 Ytank_e_s, FALSE, FALSE,
4291 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
4294 Ytank_s_w, FALSE, FALSE,
4295 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
4298 Ytank_e_n, FALSE, FALSE,
4299 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
4302 Ytank_s_e, FALSE, FALSE,
4303 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
4306 Ytank_w_s, FALSE, FALSE,
4307 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
4310 Ytank_n_w, FALSE, FALSE,
4311 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
4314 Ytank_stone, FALSE, FALSE,
4315 EL_SPACESHIP, ACTION_SMASHED_BY_ROCK, -1
4318 Ytank_spring, FALSE, FALSE,
4319 EL_SPACESHIP, ACTION_SMASHED_BY_SPRING, -1
4322 Xandroid, TRUE, FALSE,
4323 EL_EMC_ANDROID, ACTION_ACTIVE, -1
4326 Xandroid_1_n, FALSE, FALSE,
4327 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
4330 Xandroid_2_n, FALSE, FALSE,
4331 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
4334 Xandroid_1_e, FALSE, FALSE,
4335 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
4338 Xandroid_2_e, FALSE, FALSE,
4339 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
4342 Xandroid_1_w, FALSE, FALSE,
4343 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
4346 Xandroid_2_w, FALSE, FALSE,
4347 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
4350 Xandroid_1_s, FALSE, FALSE,
4351 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
4354 Xandroid_2_s, FALSE, FALSE,
4355 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
4358 Yandroid_n, FALSE, FALSE,
4359 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
4362 Yandroid_nB, FALSE, TRUE,
4363 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
4366 Yandroid_ne, FALSE, FALSE,
4367 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPRIGHT
4370 Yandroid_neB, FALSE, TRUE,
4371 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPRIGHT
4374 Yandroid_e, FALSE, FALSE,
4375 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
4378 Yandroid_eB, FALSE, TRUE,
4379 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
4382 Yandroid_se, FALSE, FALSE,
4383 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNRIGHT
4386 Yandroid_seB, FALSE, TRUE,
4387 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNRIGHT
4390 Yandroid_s, FALSE, FALSE,
4391 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
4394 Yandroid_sB, FALSE, TRUE,
4395 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
4398 Yandroid_sw, FALSE, FALSE,
4399 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNLEFT
4402 Yandroid_swB, FALSE, TRUE,
4403 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNLEFT
4406 Yandroid_w, FALSE, FALSE,
4407 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
4410 Yandroid_wB, FALSE, TRUE,
4411 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
4414 Yandroid_nw, FALSE, FALSE,
4415 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPLEFT
4418 Yandroid_nwB, FALSE, TRUE,
4419 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPLEFT
4422 Xspring, TRUE, FALSE,
4426 Xspring_pause, FALSE, FALSE,
4430 Xspring_e, FALSE, FALSE,
4434 Xspring_w, FALSE, FALSE,
4438 Xspring_fall, FALSE, FALSE,
4442 Yspring_s, FALSE, FALSE,
4443 EL_SPRING, ACTION_FALLING, -1
4446 Yspring_sB, FALSE, TRUE,
4447 EL_SPRING, ACTION_FALLING, -1
4450 Yspring_e, FALSE, FALSE,
4451 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
4454 Yspring_eB, FALSE, TRUE,
4455 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
4458 Yspring_w, FALSE, FALSE,
4459 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
4462 Yspring_wB, FALSE, TRUE,
4463 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
4466 Yspring_kill_e, FALSE, FALSE,
4467 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
4470 Yspring_kill_eB, FALSE, TRUE,
4471 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
4474 Yspring_kill_w, FALSE, FALSE,
4475 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
4478 Yspring_kill_wB, FALSE, TRUE,
4479 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
4482 Xeater_n, TRUE, FALSE,
4483 EL_YAMYAM_UP, -1, -1
4486 Xeater_e, TRUE, FALSE,
4487 EL_YAMYAM_RIGHT, -1, -1
4490 Xeater_w, TRUE, FALSE,
4491 EL_YAMYAM_LEFT, -1, -1
4494 Xeater_s, TRUE, FALSE,
4495 EL_YAMYAM_DOWN, -1, -1
4498 Yeater_n, FALSE, FALSE,
4499 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
4502 Yeater_nB, FALSE, TRUE,
4503 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
4506 Yeater_e, FALSE, FALSE,
4507 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
4510 Yeater_eB, FALSE, TRUE,
4511 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
4514 Yeater_s, FALSE, FALSE,
4515 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
4518 Yeater_sB, FALSE, TRUE,
4519 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
4522 Yeater_w, FALSE, FALSE,
4523 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
4526 Yeater_wB, FALSE, TRUE,
4527 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
4530 Yeater_stone, FALSE, FALSE,
4531 EL_YAMYAM, ACTION_SMASHED_BY_ROCK, -1
4534 Yeater_spring, FALSE, FALSE,
4535 EL_YAMYAM, ACTION_SMASHED_BY_SPRING, -1
4538 Xalien, TRUE, FALSE,
4542 Xalien_pause, FALSE, FALSE,
4546 Yalien_n, FALSE, FALSE,
4547 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
4550 Yalien_nB, FALSE, TRUE,
4551 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
4554 Yalien_e, FALSE, FALSE,
4555 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
4558 Yalien_eB, FALSE, TRUE,
4559 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
4562 Yalien_s, FALSE, FALSE,
4563 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
4566 Yalien_sB, FALSE, TRUE,
4567 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
4570 Yalien_w, FALSE, FALSE,
4571 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
4574 Yalien_wB, FALSE, TRUE,
4575 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
4578 Yalien_stone, FALSE, FALSE,
4579 EL_ROBOT, ACTION_SMASHED_BY_ROCK, -1
4582 Yalien_spring, FALSE, FALSE,
4583 EL_ROBOT, ACTION_SMASHED_BY_SPRING, -1
4586 Xemerald, TRUE, FALSE,
4590 Xemerald_pause, FALSE, FALSE,
4594 Xemerald_fall, FALSE, FALSE,
4598 Xemerald_shine, FALSE, FALSE,
4599 EL_EMERALD, ACTION_TWINKLING, -1
4602 Yemerald_s, FALSE, FALSE,
4603 EL_EMERALD, ACTION_FALLING, -1
4606 Yemerald_sB, FALSE, TRUE,
4607 EL_EMERALD, ACTION_FALLING, -1
4610 Yemerald_e, FALSE, FALSE,
4611 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
4614 Yemerald_eB, FALSE, TRUE,
4615 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
4618 Yemerald_w, FALSE, FALSE,
4619 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
4622 Yemerald_wB, FALSE, TRUE,
4623 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
4626 Yemerald_eat, FALSE, FALSE,
4627 EL_EMERALD, ACTION_COLLECTING, -1
4630 Yemerald_stone, FALSE, FALSE,
4631 EL_NUT, ACTION_BREAKING, -1
4634 Xdiamond, TRUE, FALSE,
4638 Xdiamond_pause, FALSE, FALSE,
4642 Xdiamond_fall, FALSE, FALSE,
4646 Xdiamond_shine, FALSE, FALSE,
4647 EL_DIAMOND, ACTION_TWINKLING, -1
4650 Ydiamond_s, FALSE, FALSE,
4651 EL_DIAMOND, ACTION_FALLING, -1
4654 Ydiamond_sB, FALSE, TRUE,
4655 EL_DIAMOND, ACTION_FALLING, -1
4658 Ydiamond_e, FALSE, FALSE,
4659 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
4662 Ydiamond_eB, FALSE, TRUE,
4663 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
4666 Ydiamond_w, FALSE, FALSE,
4667 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
4670 Ydiamond_wB, FALSE, TRUE,
4671 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
4674 Ydiamond_eat, FALSE, FALSE,
4675 EL_DIAMOND, ACTION_COLLECTING, -1
4678 Ydiamond_stone, FALSE, FALSE,
4679 EL_DIAMOND, ACTION_SMASHED_BY_ROCK, -1
4682 Xdrip_fall, TRUE, FALSE,
4683 EL_AMOEBA_DROP, -1, -1
4686 Xdrip_stretch, FALSE, FALSE,
4687 EL_AMOEBA_DROP, ACTION_FALLING, -1
4690 Xdrip_stretchB, FALSE, TRUE,
4691 EL_AMOEBA_DROP, ACTION_FALLING, -1
4694 Xdrip_eat, FALSE, FALSE,
4695 EL_AMOEBA_DROP, ACTION_GROWING, -1
4698 Ydrip_s1, FALSE, FALSE,
4699 EL_AMOEBA_DROP, ACTION_FALLING, -1
4702 Ydrip_s1B, FALSE, TRUE,
4703 EL_AMOEBA_DROP, ACTION_FALLING, -1
4706 Ydrip_s2, FALSE, FALSE,
4707 EL_AMOEBA_DROP, ACTION_FALLING, -1
4710 Ydrip_s2B, FALSE, TRUE,
4711 EL_AMOEBA_DROP, ACTION_FALLING, -1
4718 Xbomb_pause, FALSE, FALSE,
4722 Xbomb_fall, FALSE, FALSE,
4726 Ybomb_s, FALSE, FALSE,
4727 EL_BOMB, ACTION_FALLING, -1
4730 Ybomb_sB, FALSE, TRUE,
4731 EL_BOMB, ACTION_FALLING, -1
4734 Ybomb_e, FALSE, FALSE,
4735 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
4738 Ybomb_eB, FALSE, TRUE,
4739 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
4742 Ybomb_w, FALSE, FALSE,
4743 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
4746 Ybomb_wB, FALSE, TRUE,
4747 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
4750 Ybomb_eat, FALSE, FALSE,
4751 EL_BOMB, ACTION_ACTIVATING, -1
4754 Xballoon, TRUE, FALSE,
4758 Yballoon_n, FALSE, FALSE,
4759 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
4762 Yballoon_nB, FALSE, TRUE,
4763 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
4766 Yballoon_e, FALSE, FALSE,
4767 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
4770 Yballoon_eB, FALSE, TRUE,
4771 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
4774 Yballoon_s, FALSE, FALSE,
4775 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
4778 Yballoon_sB, FALSE, TRUE,
4779 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
4782 Yballoon_w, FALSE, FALSE,
4783 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
4786 Yballoon_wB, FALSE, TRUE,
4787 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
4790 Xgrass, TRUE, FALSE,
4791 EL_EMC_GRASS, -1, -1
4794 Ygrass_nB, FALSE, FALSE,
4795 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_UP
4798 Ygrass_eB, FALSE, FALSE,
4799 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_RIGHT
4802 Ygrass_sB, FALSE, FALSE,
4803 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_DOWN
4806 Ygrass_wB, FALSE, FALSE,
4807 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_LEFT
4814 Ydirt_nB, FALSE, FALSE,
4815 EL_SAND, ACTION_DIGGING, MV_BIT_UP
4818 Ydirt_eB, FALSE, FALSE,
4819 EL_SAND, ACTION_DIGGING, MV_BIT_RIGHT
4822 Ydirt_sB, FALSE, FALSE,
4823 EL_SAND, ACTION_DIGGING, MV_BIT_DOWN
4826 Ydirt_wB, FALSE, FALSE,
4827 EL_SAND, ACTION_DIGGING, MV_BIT_LEFT
4830 Xacid_ne, TRUE, FALSE,
4831 EL_ACID_POOL_TOPRIGHT, -1, -1
4834 Xacid_se, TRUE, FALSE,
4835 EL_ACID_POOL_BOTTOMRIGHT, -1, -1
4838 Xacid_s, TRUE, FALSE,
4839 EL_ACID_POOL_BOTTOM, -1, -1
4842 Xacid_sw, TRUE, FALSE,
4843 EL_ACID_POOL_BOTTOMLEFT, -1, -1
4846 Xacid_nw, TRUE, FALSE,
4847 EL_ACID_POOL_TOPLEFT, -1, -1
4850 Xacid_1, TRUE, FALSE,
4854 Xacid_2, FALSE, FALSE,
4858 Xacid_3, FALSE, FALSE,
4862 Xacid_4, FALSE, FALSE,
4866 Xacid_5, FALSE, FALSE,
4870 Xacid_6, FALSE, FALSE,
4874 Xacid_7, FALSE, FALSE,
4878 Xacid_8, FALSE, FALSE,
4882 Xball_1, TRUE, FALSE,
4883 EL_EMC_MAGIC_BALL, -1, -1
4886 Xball_1B, FALSE, FALSE,
4887 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
4890 Xball_2, FALSE, FALSE,
4891 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
4894 Xball_2B, FALSE, FALSE,
4895 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
4898 Yball_eat, FALSE, FALSE,
4899 EL_EMC_MAGIC_BALL, ACTION_DROPPING, -1
4902 Ykey_1_eat, FALSE, FALSE,
4903 EL_EM_KEY_1, ACTION_COLLECTING, -1
4906 Ykey_2_eat, FALSE, FALSE,
4907 EL_EM_KEY_2, ACTION_COLLECTING, -1
4910 Ykey_3_eat, FALSE, FALSE,
4911 EL_EM_KEY_3, ACTION_COLLECTING, -1
4914 Ykey_4_eat, FALSE, FALSE,
4915 EL_EM_KEY_4, ACTION_COLLECTING, -1
4918 Ykey_5_eat, FALSE, FALSE,
4919 EL_EMC_KEY_5, ACTION_COLLECTING, -1
4922 Ykey_6_eat, FALSE, FALSE,
4923 EL_EMC_KEY_6, ACTION_COLLECTING, -1
4926 Ykey_7_eat, FALSE, FALSE,
4927 EL_EMC_KEY_7, ACTION_COLLECTING, -1
4930 Ykey_8_eat, FALSE, FALSE,
4931 EL_EMC_KEY_8, ACTION_COLLECTING, -1
4934 Ylenses_eat, FALSE, FALSE,
4935 EL_EMC_LENSES, ACTION_COLLECTING, -1
4938 Ymagnify_eat, FALSE, FALSE,
4939 EL_EMC_MAGNIFIER, ACTION_COLLECTING, -1
4942 Ygrass_eat, FALSE, FALSE,
4943 EL_EMC_GRASS, ACTION_SNAPPING, -1
4946 Ydirt_eat, FALSE, FALSE,
4947 EL_SAND, ACTION_SNAPPING, -1
4950 Xgrow_ns, TRUE, FALSE,
4951 EL_EXPANDABLE_WALL_VERTICAL, -1, -1
4954 Ygrow_ns_eat, FALSE, FALSE,
4955 EL_EXPANDABLE_WALL_VERTICAL, ACTION_GROWING, -1
4958 Xgrow_ew, TRUE, FALSE,
4959 EL_EXPANDABLE_WALL_HORIZONTAL, -1, -1
4962 Ygrow_ew_eat, FALSE, FALSE,
4963 EL_EXPANDABLE_WALL_HORIZONTAL, ACTION_GROWING, -1
4966 Xwonderwall, TRUE, FALSE,
4967 EL_MAGIC_WALL, -1, -1
4970 XwonderwallB, FALSE, FALSE,
4971 EL_MAGIC_WALL, ACTION_ACTIVE, -1
4974 Xamoeba_1, TRUE, FALSE,
4975 EL_AMOEBA_DRY, ACTION_OTHER, -1
4978 Xamoeba_2, FALSE, FALSE,
4979 EL_AMOEBA_DRY, ACTION_OTHER, -1
4982 Xamoeba_3, FALSE, FALSE,
4983 EL_AMOEBA_DRY, ACTION_OTHER, -1
4986 Xamoeba_4, FALSE, FALSE,
4987 EL_AMOEBA_DRY, ACTION_OTHER, -1
4990 Xamoeba_5, TRUE, FALSE,
4991 EL_AMOEBA_WET, ACTION_OTHER, -1
4994 Xamoeba_6, FALSE, FALSE,
4995 EL_AMOEBA_WET, ACTION_OTHER, -1
4998 Xamoeba_7, FALSE, FALSE,
4999 EL_AMOEBA_WET, ACTION_OTHER, -1
5002 Xamoeba_8, FALSE, FALSE,
5003 EL_AMOEBA_WET, ACTION_OTHER, -1
5006 Xdoor_1, TRUE, FALSE,
5007 EL_EM_GATE_1, -1, -1
5010 Xdoor_2, TRUE, FALSE,
5011 EL_EM_GATE_2, -1, -1
5014 Xdoor_3, TRUE, FALSE,
5015 EL_EM_GATE_3, -1, -1
5018 Xdoor_4, TRUE, FALSE,
5019 EL_EM_GATE_4, -1, -1
5022 Xdoor_5, TRUE, FALSE,
5023 EL_EMC_GATE_5, -1, -1
5026 Xdoor_6, TRUE, FALSE,
5027 EL_EMC_GATE_6, -1, -1
5030 Xdoor_7, TRUE, FALSE,
5031 EL_EMC_GATE_7, -1, -1
5034 Xdoor_8, TRUE, FALSE,
5035 EL_EMC_GATE_8, -1, -1
5038 Xkey_1, TRUE, FALSE,
5042 Xkey_2, TRUE, FALSE,
5046 Xkey_3, TRUE, FALSE,
5050 Xkey_4, TRUE, FALSE,
5054 Xkey_5, TRUE, FALSE,
5055 EL_EMC_KEY_5, -1, -1
5058 Xkey_6, TRUE, FALSE,
5059 EL_EMC_KEY_6, -1, -1
5062 Xkey_7, TRUE, FALSE,
5063 EL_EMC_KEY_7, -1, -1
5066 Xkey_8, TRUE, FALSE,
5067 EL_EMC_KEY_8, -1, -1
5070 Xwind_n, TRUE, FALSE,
5071 EL_BALLOON_SWITCH_UP, -1, -1
5074 Xwind_e, TRUE, FALSE,
5075 EL_BALLOON_SWITCH_RIGHT, -1, -1
5078 Xwind_s, TRUE, FALSE,
5079 EL_BALLOON_SWITCH_DOWN, -1, -1
5082 Xwind_w, TRUE, FALSE,
5083 EL_BALLOON_SWITCH_LEFT, -1, -1
5086 Xwind_nesw, TRUE, FALSE,
5087 EL_BALLOON_SWITCH_ANY, -1, -1
5090 Xwind_stop, TRUE, FALSE,
5091 EL_BALLOON_SWITCH_NONE, -1, -1
5095 EL_EM_EXIT_CLOSED, -1, -1
5098 Xexit_1, TRUE, FALSE,
5099 EL_EM_EXIT_OPEN, -1, -1
5102 Xexit_2, FALSE, FALSE,
5103 EL_EM_EXIT_OPEN, -1, -1
5106 Xexit_3, FALSE, FALSE,
5107 EL_EM_EXIT_OPEN, -1, -1
5110 Xdynamite, TRUE, FALSE,
5111 EL_EM_DYNAMITE, -1, -1
5114 Ydynamite_eat, FALSE, FALSE,
5115 EL_EM_DYNAMITE, ACTION_COLLECTING, -1
5118 Xdynamite_1, TRUE, FALSE,
5119 EL_EM_DYNAMITE_ACTIVE, -1, -1
5122 Xdynamite_2, FALSE, FALSE,
5123 EL_EM_DYNAMITE_ACTIVE, -1, -1
5126 Xdynamite_3, FALSE, FALSE,
5127 EL_EM_DYNAMITE_ACTIVE, -1, -1
5130 Xdynamite_4, FALSE, FALSE,
5131 EL_EM_DYNAMITE_ACTIVE, -1, -1
5134 Xbumper, TRUE, FALSE,
5135 EL_EMC_SPRING_BUMPER, -1, -1
5138 XbumperB, FALSE, FALSE,
5139 EL_EMC_SPRING_BUMPER, ACTION_ACTIVE, -1
5142 Xwheel, TRUE, FALSE,
5143 EL_ROBOT_WHEEL, -1, -1
5146 XwheelB, FALSE, FALSE,
5147 EL_ROBOT_WHEEL, ACTION_ACTIVE, -1
5150 Xswitch, TRUE, FALSE,
5151 EL_EMC_MAGIC_BALL_SWITCH, -1, -1
5154 XswitchB, FALSE, FALSE,
5155 EL_EMC_MAGIC_BALL_SWITCH, ACTION_ACTIVE, -1
5159 EL_QUICKSAND_EMPTY, -1, -1
5162 Xsand_stone, TRUE, FALSE,
5163 EL_QUICKSAND_FULL, -1, -1
5166 Xsand_stonein_1, FALSE, TRUE,
5167 EL_ROCK, ACTION_FILLING, -1
5170 Xsand_stonein_2, FALSE, TRUE,
5171 EL_ROCK, ACTION_FILLING, -1
5174 Xsand_stonein_3, FALSE, TRUE,
5175 EL_ROCK, ACTION_FILLING, -1
5178 Xsand_stonein_4, FALSE, TRUE,
5179 EL_ROCK, ACTION_FILLING, -1
5183 Xsand_stonesand_1, FALSE, FALSE,
5184 EL_QUICKSAND_EMPTYING, -1, -1
5187 Xsand_stonesand_2, FALSE, FALSE,
5188 EL_QUICKSAND_EMPTYING, -1, -1
5191 Xsand_stonesand_3, FALSE, FALSE,
5192 EL_QUICKSAND_EMPTYING, -1, -1
5195 Xsand_stonesand_4, FALSE, FALSE,
5196 EL_QUICKSAND_EMPTYING, -1, -1
5199 Xsand_stonesand_quickout_1, FALSE, FALSE,
5200 EL_QUICKSAND_EMPTYING, -1, -1
5203 Xsand_stonesand_quickout_2, FALSE, FALSE,
5204 EL_QUICKSAND_EMPTYING, -1, -1
5208 Xsand_stonesand_1, FALSE, FALSE,
5209 EL_QUICKSAND_FULL, -1, -1
5212 Xsand_stonesand_2, FALSE, FALSE,
5213 EL_QUICKSAND_FULL, -1, -1
5216 Xsand_stonesand_3, FALSE, FALSE,
5217 EL_QUICKSAND_FULL, -1, -1
5220 Xsand_stonesand_4, FALSE, FALSE,
5221 EL_QUICKSAND_FULL, -1, -1
5225 Xsand_stoneout_1, FALSE, FALSE,
5226 EL_ROCK, ACTION_EMPTYING, -1
5229 Xsand_stoneout_2, FALSE, FALSE,
5230 EL_ROCK, ACTION_EMPTYING, -1
5234 Xsand_sandstone_1, FALSE, FALSE,
5235 EL_QUICKSAND_FILLING, -1, -1
5238 Xsand_sandstone_2, FALSE, FALSE,
5239 EL_QUICKSAND_FILLING, -1, -1
5242 Xsand_sandstone_3, FALSE, FALSE,
5243 EL_QUICKSAND_FILLING, -1, -1
5246 Xsand_sandstone_4, FALSE, FALSE,
5247 EL_QUICKSAND_FILLING, -1, -1
5251 Xsand_sandstone_1, FALSE, FALSE,
5252 EL_QUICKSAND_FULL, -1, -1
5255 Xsand_sandstone_2, FALSE, FALSE,
5256 EL_QUICKSAND_FULL, -1, -1
5259 Xsand_sandstone_3, FALSE, FALSE,
5260 EL_QUICKSAND_FULL, -1, -1
5263 Xsand_sandstone_4, FALSE, FALSE,
5264 EL_QUICKSAND_FULL, -1, -1
5268 Xplant, TRUE, FALSE,
5269 EL_EMC_PLANT, -1, -1
5272 Yplant, FALSE, FALSE,
5273 EL_EMC_PLANT, -1, -1
5276 Xlenses, TRUE, FALSE,
5277 EL_EMC_LENSES, -1, -1
5280 Xmagnify, TRUE, FALSE,
5281 EL_EMC_MAGNIFIER, -1, -1
5284 Xdripper, TRUE, FALSE,
5285 EL_EMC_DRIPPER, -1, -1
5288 XdripperB, FALSE, FALSE,
5289 EL_EMC_DRIPPER, ACTION_ACTIVE, -1
5292 Xfake_blank, TRUE, FALSE,
5293 EL_INVISIBLE_WALL, -1, -1
5296 Xfake_blankB, FALSE, FALSE,
5297 EL_INVISIBLE_WALL, ACTION_ACTIVE, -1
5300 Xfake_grass, TRUE, FALSE,
5301 EL_EMC_FAKE_GRASS, -1, -1
5304 Xfake_grassB, FALSE, FALSE,
5305 EL_EMC_FAKE_GRASS, ACTION_ACTIVE, -1
5308 Xfake_door_1, TRUE, FALSE,
5309 EL_EM_GATE_1_GRAY, -1, -1
5312 Xfake_door_2, TRUE, FALSE,
5313 EL_EM_GATE_2_GRAY, -1, -1
5316 Xfake_door_3, TRUE, FALSE,
5317 EL_EM_GATE_3_GRAY, -1, -1
5320 Xfake_door_4, TRUE, FALSE,
5321 EL_EM_GATE_4_GRAY, -1, -1
5324 Xfake_door_5, TRUE, FALSE,
5325 EL_EMC_GATE_5_GRAY, -1, -1
5328 Xfake_door_6, TRUE, FALSE,
5329 EL_EMC_GATE_6_GRAY, -1, -1
5332 Xfake_door_7, TRUE, FALSE,
5333 EL_EMC_GATE_7_GRAY, -1, -1
5336 Xfake_door_8, TRUE, FALSE,
5337 EL_EMC_GATE_8_GRAY, -1, -1
5340 Xfake_acid_1, TRUE, FALSE,
5341 EL_EMC_FAKE_ACID, -1, -1
5344 Xfake_acid_2, FALSE, FALSE,
5345 EL_EMC_FAKE_ACID, -1, -1
5348 Xfake_acid_3, FALSE, FALSE,
5349 EL_EMC_FAKE_ACID, -1, -1
5352 Xfake_acid_4, FALSE, FALSE,
5353 EL_EMC_FAKE_ACID, -1, -1
5356 Xfake_acid_5, FALSE, FALSE,
5357 EL_EMC_FAKE_ACID, -1, -1
5360 Xfake_acid_6, FALSE, FALSE,
5361 EL_EMC_FAKE_ACID, -1, -1
5364 Xfake_acid_7, FALSE, FALSE,
5365 EL_EMC_FAKE_ACID, -1, -1
5368 Xfake_acid_8, FALSE, FALSE,
5369 EL_EMC_FAKE_ACID, -1, -1
5372 Xsteel_1, TRUE, FALSE,
5373 EL_STEELWALL, -1, -1
5376 Xsteel_2, TRUE, FALSE,
5377 EL_EMC_STEELWALL_2, -1, -1
5380 Xsteel_3, TRUE, FALSE,
5381 EL_EMC_STEELWALL_3, -1, -1
5384 Xsteel_4, TRUE, FALSE,
5385 EL_EMC_STEELWALL_4, -1, -1
5388 Xwall_1, TRUE, FALSE,
5392 Xwall_2, TRUE, FALSE,
5393 EL_EMC_WALL_14, -1, -1
5396 Xwall_3, TRUE, FALSE,
5397 EL_EMC_WALL_15, -1, -1
5400 Xwall_4, TRUE, FALSE,
5401 EL_EMC_WALL_16, -1, -1
5404 Xround_wall_1, TRUE, FALSE,
5405 EL_WALL_SLIPPERY, -1, -1
5408 Xround_wall_2, TRUE, FALSE,
5409 EL_EMC_WALL_SLIPPERY_2, -1, -1
5412 Xround_wall_3, TRUE, FALSE,
5413 EL_EMC_WALL_SLIPPERY_3, -1, -1
5416 Xround_wall_4, TRUE, FALSE,
5417 EL_EMC_WALL_SLIPPERY_4, -1, -1
5420 Xdecor_1, TRUE, FALSE,
5421 EL_EMC_WALL_8, -1, -1
5424 Xdecor_2, TRUE, FALSE,
5425 EL_EMC_WALL_6, -1, -1
5428 Xdecor_3, TRUE, FALSE,
5429 EL_EMC_WALL_4, -1, -1
5432 Xdecor_4, TRUE, FALSE,
5433 EL_EMC_WALL_7, -1, -1
5436 Xdecor_5, TRUE, FALSE,
5437 EL_EMC_WALL_5, -1, -1
5440 Xdecor_6, TRUE, FALSE,
5441 EL_EMC_WALL_9, -1, -1
5444 Xdecor_7, TRUE, FALSE,
5445 EL_EMC_WALL_10, -1, -1
5448 Xdecor_8, TRUE, FALSE,
5449 EL_EMC_WALL_1, -1, -1
5452 Xdecor_9, TRUE, FALSE,
5453 EL_EMC_WALL_2, -1, -1
5456 Xdecor_10, TRUE, FALSE,
5457 EL_EMC_WALL_3, -1, -1
5460 Xdecor_11, TRUE, FALSE,
5461 EL_EMC_WALL_11, -1, -1
5464 Xdecor_12, TRUE, FALSE,
5465 EL_EMC_WALL_12, -1, -1
5468 Xalpha_0, TRUE, FALSE,
5469 EL_CHAR('0'), -1, -1
5472 Xalpha_1, TRUE, FALSE,
5473 EL_CHAR('1'), -1, -1
5476 Xalpha_2, TRUE, FALSE,
5477 EL_CHAR('2'), -1, -1
5480 Xalpha_3, TRUE, FALSE,
5481 EL_CHAR('3'), -1, -1
5484 Xalpha_4, TRUE, FALSE,
5485 EL_CHAR('4'), -1, -1
5488 Xalpha_5, TRUE, FALSE,
5489 EL_CHAR('5'), -1, -1
5492 Xalpha_6, TRUE, FALSE,
5493 EL_CHAR('6'), -1, -1
5496 Xalpha_7, TRUE, FALSE,
5497 EL_CHAR('7'), -1, -1
5500 Xalpha_8, TRUE, FALSE,
5501 EL_CHAR('8'), -1, -1
5504 Xalpha_9, TRUE, FALSE,
5505 EL_CHAR('9'), -1, -1
5508 Xalpha_excla, TRUE, FALSE,
5509 EL_CHAR('!'), -1, -1
5512 Xalpha_quote, TRUE, FALSE,
5513 EL_CHAR('"'), -1, -1
5516 Xalpha_comma, TRUE, FALSE,
5517 EL_CHAR(','), -1, -1
5520 Xalpha_minus, TRUE, FALSE,
5521 EL_CHAR('-'), -1, -1
5524 Xalpha_perio, TRUE, FALSE,
5525 EL_CHAR('.'), -1, -1
5528 Xalpha_colon, TRUE, FALSE,
5529 EL_CHAR(':'), -1, -1
5532 Xalpha_quest, TRUE, FALSE,
5533 EL_CHAR('?'), -1, -1
5536 Xalpha_a, TRUE, FALSE,
5537 EL_CHAR('A'), -1, -1
5540 Xalpha_b, TRUE, FALSE,
5541 EL_CHAR('B'), -1, -1
5544 Xalpha_c, TRUE, FALSE,
5545 EL_CHAR('C'), -1, -1
5548 Xalpha_d, TRUE, FALSE,
5549 EL_CHAR('D'), -1, -1
5552 Xalpha_e, TRUE, FALSE,
5553 EL_CHAR('E'), -1, -1
5556 Xalpha_f, TRUE, FALSE,
5557 EL_CHAR('F'), -1, -1
5560 Xalpha_g, TRUE, FALSE,
5561 EL_CHAR('G'), -1, -1
5564 Xalpha_h, TRUE, FALSE,
5565 EL_CHAR('H'), -1, -1
5568 Xalpha_i, TRUE, FALSE,
5569 EL_CHAR('I'), -1, -1
5572 Xalpha_j, TRUE, FALSE,
5573 EL_CHAR('J'), -1, -1
5576 Xalpha_k, TRUE, FALSE,
5577 EL_CHAR('K'), -1, -1
5580 Xalpha_l, TRUE, FALSE,
5581 EL_CHAR('L'), -1, -1
5584 Xalpha_m, TRUE, FALSE,
5585 EL_CHAR('M'), -1, -1
5588 Xalpha_n, TRUE, FALSE,
5589 EL_CHAR('N'), -1, -1
5592 Xalpha_o, TRUE, FALSE,
5593 EL_CHAR('O'), -1, -1
5596 Xalpha_p, TRUE, FALSE,
5597 EL_CHAR('P'), -1, -1
5600 Xalpha_q, TRUE, FALSE,
5601 EL_CHAR('Q'), -1, -1
5604 Xalpha_r, TRUE, FALSE,
5605 EL_CHAR('R'), -1, -1
5608 Xalpha_s, TRUE, FALSE,
5609 EL_CHAR('S'), -1, -1
5612 Xalpha_t, TRUE, FALSE,
5613 EL_CHAR('T'), -1, -1
5616 Xalpha_u, TRUE, FALSE,
5617 EL_CHAR('U'), -1, -1
5620 Xalpha_v, TRUE, FALSE,
5621 EL_CHAR('V'), -1, -1
5624 Xalpha_w, TRUE, FALSE,
5625 EL_CHAR('W'), -1, -1
5628 Xalpha_x, TRUE, FALSE,
5629 EL_CHAR('X'), -1, -1
5632 Xalpha_y, TRUE, FALSE,
5633 EL_CHAR('Y'), -1, -1
5636 Xalpha_z, TRUE, FALSE,
5637 EL_CHAR('Z'), -1, -1
5640 Xalpha_arrow_e, TRUE, FALSE,
5641 EL_CHAR('>'), -1, -1
5644 Xalpha_arrow_w, TRUE, FALSE,
5645 EL_CHAR('<'), -1, -1
5648 Xalpha_copyr, TRUE, FALSE,
5649 EL_CHAR('©'), -1, -1
5653 Xboom_bug, FALSE, FALSE,
5654 EL_BUG, ACTION_EXPLODING, -1
5657 Xboom_bomb, FALSE, FALSE,
5658 EL_BOMB, ACTION_EXPLODING, -1
5661 Xboom_android, FALSE, FALSE,
5662 EL_EMC_ANDROID, ACTION_OTHER, -1
5665 Xboom_1, FALSE, FALSE,
5666 EL_DEFAULT, ACTION_EXPLODING, -1
5669 Xboom_2, FALSE, FALSE,
5670 EL_DEFAULT, ACTION_EXPLODING, -1
5673 Znormal, FALSE, FALSE,
5677 Zdynamite, FALSE, FALSE,
5681 Zplayer, FALSE, FALSE,
5685 ZBORDER, FALSE, FALSE,
5695 static struct Mapping_EM_to_RND_player
5704 em_player_mapping_list[] =
5708 EL_PLAYER_1, ACTION_MOVING, MV_BIT_UP,
5712 EL_PLAYER_1, ACTION_MOVING, MV_BIT_RIGHT,
5716 EL_PLAYER_1, ACTION_MOVING, MV_BIT_DOWN,
5720 EL_PLAYER_1, ACTION_MOVING, MV_BIT_LEFT,
5724 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_UP,
5728 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_RIGHT,
5732 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_DOWN,
5736 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_LEFT,
5740 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_UP,
5744 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_RIGHT,
5748 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_DOWN,
5752 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_LEFT,
5756 EL_PLAYER_2, ACTION_MOVING, MV_BIT_UP,
5760 EL_PLAYER_2, ACTION_MOVING, MV_BIT_RIGHT,
5764 EL_PLAYER_2, ACTION_MOVING, MV_BIT_DOWN,
5768 EL_PLAYER_2, ACTION_MOVING, MV_BIT_LEFT,
5772 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_UP,
5776 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_RIGHT,
5780 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_DOWN,
5784 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_LEFT,
5788 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_UP,
5792 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_RIGHT,
5796 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_DOWN,
5800 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_LEFT,
5804 EL_PLAYER_1, ACTION_DEFAULT, -1,
5808 EL_PLAYER_2, ACTION_DEFAULT, -1,
5812 EL_PLAYER_3, ACTION_MOVING, MV_BIT_UP,
5816 EL_PLAYER_3, ACTION_MOVING, MV_BIT_RIGHT,
5820 EL_PLAYER_3, ACTION_MOVING, MV_BIT_DOWN,
5824 EL_PLAYER_3, ACTION_MOVING, MV_BIT_LEFT,
5828 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_UP,
5832 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_RIGHT,
5836 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_DOWN,
5840 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_LEFT,
5844 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_UP,
5848 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_RIGHT,
5852 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_DOWN,
5856 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_LEFT,
5860 EL_PLAYER_4, ACTION_MOVING, MV_BIT_UP,
5864 EL_PLAYER_4, ACTION_MOVING, MV_BIT_RIGHT,
5868 EL_PLAYER_4, ACTION_MOVING, MV_BIT_DOWN,
5872 EL_PLAYER_4, ACTION_MOVING, MV_BIT_LEFT,
5876 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_UP,
5880 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_RIGHT,
5884 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_DOWN,
5888 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_LEFT,
5892 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_UP,
5896 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_RIGHT,
5900 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_DOWN,
5904 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_LEFT,
5908 EL_PLAYER_3, ACTION_DEFAULT, -1,
5912 EL_PLAYER_4, ACTION_DEFAULT, -1,
5921 int map_element_RND_to_EM(int element_rnd)
5923 static unsigned short mapping_RND_to_EM[NUM_FILE_ELEMENTS];
5924 static boolean mapping_initialized = FALSE;
5926 if (!mapping_initialized)
5930 /* return "Xalpha_quest" for all undefined elements in mapping array */
5931 for (i = 0; i < NUM_FILE_ELEMENTS; i++)
5932 mapping_RND_to_EM[i] = Xalpha_quest;
5934 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5935 if (em_object_mapping_list[i].is_rnd_to_em_mapping)
5936 mapping_RND_to_EM[em_object_mapping_list[i].element_rnd] =
5937 em_object_mapping_list[i].element_em;
5939 mapping_initialized = TRUE;
5942 if (element_rnd >= 0 && element_rnd < NUM_FILE_ELEMENTS)
5943 return mapping_RND_to_EM[element_rnd];
5945 Error(ERR_WARN, "invalid RND level element %d", element_rnd);
5950 int map_element_EM_to_RND(int element_em)
5952 static unsigned short mapping_EM_to_RND[TILE_MAX];
5953 static boolean mapping_initialized = FALSE;
5955 if (!mapping_initialized)
5959 /* return "EL_UNKNOWN" for all undefined elements in mapping array */
5960 for (i = 0; i < TILE_MAX; i++)
5961 mapping_EM_to_RND[i] = EL_UNKNOWN;
5963 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5964 mapping_EM_to_RND[em_object_mapping_list[i].element_em] =
5965 em_object_mapping_list[i].element_rnd;
5967 mapping_initialized = TRUE;
5970 if (element_em >= 0 && element_em < TILE_MAX)
5971 return mapping_EM_to_RND[element_em];
5973 Error(ERR_WARN, "invalid EM level element %d", element_em);
5978 void map_android_clone_elements_RND_to_EM(struct LevelInfo *level)
5980 struct LevelInfo_EM *level_em = level->native_em_level;
5981 struct LEVEL *lev = level_em->lev;
5984 for (i = 0; i < TILE_MAX; i++)
5985 lev->android_array[i] = Xblank;
5987 for (i = 0; i < level->num_android_clone_elements; i++)
5989 int element_rnd = level->android_clone_element[i];
5990 int element_em = map_element_RND_to_EM(element_rnd);
5992 for (j = 0; em_object_mapping_list[j].element_em != -1; j++)
5993 if (em_object_mapping_list[j].element_rnd == element_rnd)
5994 lev->android_array[em_object_mapping_list[j].element_em] = element_em;
5998 void map_android_clone_elements_EM_to_RND(struct LevelInfo *level)
6000 struct LevelInfo_EM *level_em = level->native_em_level;
6001 struct LEVEL *lev = level_em->lev;
6004 level->num_android_clone_elements = 0;
6006 for (i = 0; i < TILE_MAX; i++)
6008 int element_em = lev->android_array[i];
6010 boolean element_found = FALSE;
6012 if (element_em == Xblank)
6015 element_rnd = map_element_EM_to_RND(element_em);
6017 for (j = 0; j < level->num_android_clone_elements; j++)
6018 if (level->android_clone_element[j] == element_rnd)
6019 element_found = TRUE;
6023 level->android_clone_element[level->num_android_clone_elements++] =
6026 if (level->num_android_clone_elements == MAX_ANDROID_ELEMENTS)
6031 if (level->num_android_clone_elements == 0)
6033 level->num_android_clone_elements = 1;
6034 level->android_clone_element[0] = EL_EMPTY;
6038 int map_direction_RND_to_EM(int direction)
6040 return (direction == MV_UP ? 0 :
6041 direction == MV_RIGHT ? 1 :
6042 direction == MV_DOWN ? 2 :
6043 direction == MV_LEFT ? 3 :
6047 int map_direction_EM_to_RND(int direction)
6049 return (direction == 0 ? MV_UP :
6050 direction == 1 ? MV_RIGHT :
6051 direction == 2 ? MV_DOWN :
6052 direction == 3 ? MV_LEFT :
6056 int map_element_RND_to_SP(int element_rnd)
6058 int element_sp = 0x20; /* map unknown elements to yellow "hardware" */
6060 if (element_rnd >= EL_SP_START &&
6061 element_rnd <= EL_SP_END)
6062 element_sp = element_rnd - EL_SP_START;
6063 else if (element_rnd == EL_EMPTY_SPACE)
6065 else if (element_rnd == EL_INVISIBLE_WALL)
6071 int map_element_SP_to_RND(int element_sp)
6073 int element_rnd = EL_UNKNOWN;
6075 if (element_sp >= 0x00 &&
6077 element_rnd = EL_SP_START + element_sp;
6078 else if (element_sp == 0x28)
6079 element_rnd = EL_INVISIBLE_WALL;
6084 int map_action_SP_to_RND(int action_sp)
6088 case actActive: return ACTION_ACTIVE;
6089 case actImpact: return ACTION_IMPACT;
6090 case actExploding: return ACTION_EXPLODING;
6091 case actDigging: return ACTION_DIGGING;
6092 case actSnapping: return ACTION_SNAPPING;
6093 case actCollecting: return ACTION_COLLECTING;
6094 case actPassing: return ACTION_PASSING;
6095 case actPushing: return ACTION_PUSHING;
6096 case actDropping: return ACTION_DROPPING;
6098 default: return ACTION_DEFAULT;
6102 int get_next_element(int element)
6106 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
6107 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
6108 case EL_QUICKSAND_FAST_FILLING: return EL_QUICKSAND_FAST_FULL;
6109 case EL_QUICKSAND_FAST_EMPTYING: return EL_QUICKSAND_FAST_EMPTY;
6110 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
6111 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
6112 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
6113 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
6114 case EL_DC_MAGIC_WALL_FILLING: return EL_DC_MAGIC_WALL_FULL;
6115 case EL_DC_MAGIC_WALL_EMPTYING: return EL_DC_MAGIC_WALL_ACTIVE;
6116 case EL_AMOEBA_DROPPING: return EL_AMOEBA_WET;
6118 default: return element;
6123 int el_act_dir2img(int element, int action, int direction)
6125 element = GFX_ELEMENT(element);
6127 if (direction == MV_NONE)
6128 return element_info[element].graphic[action];
6130 direction = MV_DIR_TO_BIT(direction);
6132 return element_info[element].direction_graphic[action][direction];
6135 int el_act_dir2img(int element, int action, int direction)
6137 element = GFX_ELEMENT(element);
6138 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
6140 /* direction_graphic[][] == graphic[] for undefined direction graphics */
6141 return element_info[element].direction_graphic[action][direction];
6146 static int el_act_dir2crm(int element, int action, int direction)
6148 element = GFX_ELEMENT(element);
6150 if (direction == MV_NONE)
6151 return element_info[element].crumbled[action];
6153 direction = MV_DIR_TO_BIT(direction);
6155 return element_info[element].direction_crumbled[action][direction];
6158 static int el_act_dir2crm(int element, int action, int direction)
6160 element = GFX_ELEMENT(element);
6161 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
6163 /* direction_graphic[][] == graphic[] for undefined direction graphics */
6164 return element_info[element].direction_crumbled[action][direction];
6168 int el_act2img(int element, int action)
6170 element = GFX_ELEMENT(element);
6172 return element_info[element].graphic[action];
6175 int el_act2crm(int element, int action)
6177 element = GFX_ELEMENT(element);
6179 return element_info[element].crumbled[action];
6182 int el_dir2img(int element, int direction)
6184 element = GFX_ELEMENT(element);
6186 return el_act_dir2img(element, ACTION_DEFAULT, direction);
6189 int el2baseimg(int element)
6191 return element_info[element].graphic[ACTION_DEFAULT];
6194 int el2img(int element)
6196 element = GFX_ELEMENT(element);
6198 return element_info[element].graphic[ACTION_DEFAULT];
6201 int el2edimg(int element)
6203 element = GFX_ELEMENT(element);
6205 return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
6208 int el2preimg(int element)
6210 element = GFX_ELEMENT(element);
6212 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];
6215 int el2panelimg(int element)
6217 element = GFX_ELEMENT(element);
6219 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PANEL];
6222 int font2baseimg(int font_nr)
6224 return font_info[font_nr].special_graphic[GFX_SPECIAL_ARG_DEFAULT];
6227 int getBeltNrFromBeltElement(int element)
6229 return (element < EL_CONVEYOR_BELT_2_LEFT ? 0 :
6230 element < EL_CONVEYOR_BELT_3_LEFT ? 1 :
6231 element < EL_CONVEYOR_BELT_4_LEFT ? 2 : 3);
6234 int getBeltNrFromBeltActiveElement(int element)
6236 return (element < EL_CONVEYOR_BELT_2_LEFT_ACTIVE ? 0 :
6237 element < EL_CONVEYOR_BELT_3_LEFT_ACTIVE ? 1 :
6238 element < EL_CONVEYOR_BELT_4_LEFT_ACTIVE ? 2 : 3);
6241 int getBeltNrFromBeltSwitchElement(int element)
6243 return (element < EL_CONVEYOR_BELT_2_SWITCH_LEFT ? 0 :
6244 element < EL_CONVEYOR_BELT_3_SWITCH_LEFT ? 1 :
6245 element < EL_CONVEYOR_BELT_4_SWITCH_LEFT ? 2 : 3);
6248 int getBeltDirNrFromBeltElement(int element)
6250 static int belt_base_element[4] =
6252 EL_CONVEYOR_BELT_1_LEFT,
6253 EL_CONVEYOR_BELT_2_LEFT,
6254 EL_CONVEYOR_BELT_3_LEFT,
6255 EL_CONVEYOR_BELT_4_LEFT
6258 int belt_nr = getBeltNrFromBeltElement(element);
6259 int belt_dir_nr = element - belt_base_element[belt_nr];
6261 return (belt_dir_nr % 3);
6264 int getBeltDirNrFromBeltSwitchElement(int element)
6266 static int belt_base_element[4] =
6268 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
6269 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
6270 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
6271 EL_CONVEYOR_BELT_4_SWITCH_LEFT
6274 int belt_nr = getBeltNrFromBeltSwitchElement(element);
6275 int belt_dir_nr = element - belt_base_element[belt_nr];
6277 return (belt_dir_nr % 3);
6280 int getBeltDirFromBeltElement(int element)
6282 static int belt_move_dir[3] =
6289 int belt_dir_nr = getBeltDirNrFromBeltElement(element);
6291 return belt_move_dir[belt_dir_nr];
6294 int getBeltDirFromBeltSwitchElement(int element)
6296 static int belt_move_dir[3] =
6303 int belt_dir_nr = getBeltDirNrFromBeltSwitchElement(element);
6305 return belt_move_dir[belt_dir_nr];
6308 int getBeltElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
6310 static int belt_base_element[4] =
6312 EL_CONVEYOR_BELT_1_LEFT,
6313 EL_CONVEYOR_BELT_2_LEFT,
6314 EL_CONVEYOR_BELT_3_LEFT,
6315 EL_CONVEYOR_BELT_4_LEFT
6318 return belt_base_element[belt_nr] + belt_dir_nr;
6321 int getBeltElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
6323 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
6325 return getBeltElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
6328 int getBeltSwitchElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
6330 static int belt_base_element[4] =
6332 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
6333 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
6334 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
6335 EL_CONVEYOR_BELT_4_SWITCH_LEFT
6338 return belt_base_element[belt_nr] + belt_dir_nr;
6341 int getBeltSwitchElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
6343 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
6345 return getBeltSwitchElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
6348 int getNumActivePlayers_EM()
6350 int num_players = 0;
6356 for (i = 0; i < MAX_PLAYERS; i++)
6357 if (tape.player_participates[i])
6363 int getGameFrameDelay_EM(int native_em_game_frame_delay)
6365 int game_frame_delay_value;
6367 game_frame_delay_value =
6368 (tape.playing && tape.fast_forward ? FfwdFrameDelay :
6369 GameFrameDelay == GAME_FRAME_DELAY ? native_em_game_frame_delay :
6372 if (tape.playing && tape.warp_forward && !tape.pausing)
6373 game_frame_delay_value = 0;
6375 return game_frame_delay_value;
6378 unsigned int InitRND(long seed)
6380 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
6381 return InitEngineRandom_EM(seed);
6382 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
6383 return InitEngineRandom_SP(seed);
6385 return InitEngineRandom_RND(seed);
6389 static struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
6390 static struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
6393 inline static int get_effective_element_EM(int tile, int frame_em)
6395 int element = object_mapping[tile].element_rnd;
6396 int action = object_mapping[tile].action;
6397 boolean is_backside = object_mapping[tile].is_backside;
6398 boolean action_removing = (action == ACTION_DIGGING ||
6399 action == ACTION_SNAPPING ||
6400 action == ACTION_COLLECTING);
6406 case Yacid_splash_eB:
6407 case Yacid_splash_wB:
6408 return (frame_em > 5 ? EL_EMPTY : element);
6414 else /* frame_em == 7 */
6418 case Yacid_splash_eB:
6419 case Yacid_splash_wB:
6422 case Yemerald_stone:
6425 case Ydiamond_stone:
6429 case Xdrip_stretchB:
6448 case Xsand_stonein_1:
6449 case Xsand_stonein_2:
6450 case Xsand_stonein_3:
6451 case Xsand_stonein_4:
6455 return (is_backside || action_removing ? EL_EMPTY : element);
6460 inline static boolean check_linear_animation_EM(int tile)
6464 case Xsand_stonesand_1:
6465 case Xsand_stonesand_quickout_1:
6466 case Xsand_sandstone_1:
6467 case Xsand_stonein_1:
6468 case Xsand_stoneout_1:
6493 inline static void set_crumbled_graphics_EM(struct GraphicInfo_EM *g_em,
6494 boolean has_crumbled_graphics,
6495 int crumbled, int sync_frame)
6497 /* if element can be crumbled, but certain action graphics are just empty
6498 space (like instantly snapping sand to empty space in 1 frame), do not
6499 treat these empty space graphics as crumbled graphics in EMC engine */
6500 if (crumbled == IMG_EMPTY_SPACE)
6501 has_crumbled_graphics = FALSE;
6503 if (has_crumbled_graphics)
6505 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
6506 int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
6507 g_crumbled->anim_delay,
6508 g_crumbled->anim_mode,
6509 g_crumbled->anim_start_frame,
6512 getGraphicSource(crumbled, frame_crumbled, &g_em->crumbled_bitmap,
6513 &g_em->crumbled_src_x, &g_em->crumbled_src_y);
6515 g_em->crumbled_border_size = graphic_info[crumbled].border_size;
6517 g_em->has_crumbled_graphics = TRUE;
6521 g_em->crumbled_bitmap = NULL;
6522 g_em->crumbled_src_x = 0;
6523 g_em->crumbled_src_y = 0;
6524 g_em->crumbled_border_size = 0;
6526 g_em->has_crumbled_graphics = FALSE;
6530 void ResetGfxAnimation_EM(int x, int y, int tile)
6535 void SetGfxAnimation_EM(struct GraphicInfo_EM *g_em,
6536 int tile, int frame_em, int x, int y)
6538 int action = object_mapping[tile].action;
6540 int direction = object_mapping[tile].direction;
6541 int effective_element = get_effective_element_EM(tile, frame_em);
6542 int graphic = (direction == MV_NONE ?
6543 el_act2img(effective_element, action) :
6544 el_act_dir2img(effective_element, action, direction));
6545 struct GraphicInfo *g = &graphic_info[graphic];
6548 boolean action_removing = (action == ACTION_DIGGING ||
6549 action == ACTION_SNAPPING ||
6550 action == ACTION_COLLECTING);
6551 boolean action_moving = (action == ACTION_FALLING ||
6552 action == ACTION_MOVING ||
6553 action == ACTION_PUSHING ||
6554 action == ACTION_EATING ||
6555 action == ACTION_FILLING ||
6556 action == ACTION_EMPTYING);
6557 boolean action_falling = (action == ACTION_FALLING ||
6558 action == ACTION_FILLING ||
6559 action == ACTION_EMPTYING);
6561 /* special case: graphic uses "2nd movement tile" and has defined
6562 7 frames for movement animation (or less) => use default graphic
6563 for last (8th) frame which ends the movement animation */
6564 if (g->double_movement && g->anim_frames < 8 && frame_em == 7)
6566 action = ACTION_DEFAULT; /* (keep action_* unchanged for now) */
6567 graphic = (direction == MV_NONE ?
6568 el_act2img(effective_element, action) :
6569 el_act_dir2img(effective_element, action, direction));
6571 g = &graphic_info[graphic];
6575 if (tile == Xsand_stonesand_1 ||
6576 tile == Xsand_stonesand_2 ||
6577 tile == Xsand_stonesand_3 ||
6578 tile == Xsand_stonesand_4)
6579 printf("::: 1: quicksand frame %d [%d]\n", GfxFrame[x][y], tile);
6583 if ((action_removing || check_linear_animation_EM(tile)) && frame_em == 0)
6587 // printf("::: resetting... [%d]\n", tile);
6590 if (action_removing || check_linear_animation_EM(tile))
6592 GfxFrame[x][y] = frame_em;
6594 // printf("::: resetting... [%d]\n", tile);
6597 else if (action_moving)
6599 boolean is_backside = object_mapping[tile].is_backside;
6603 int direction = object_mapping[tile].direction;
6604 int move_dir = (action_falling ? MV_DOWN : direction);
6609 /* !!! TEST !!! NEW !!! DOES NOT WORK RIGHT YET !!! */
6610 if (g->double_movement && frame_em == 0)
6614 // printf("::: resetting... [%d]\n", tile);
6618 if (move_dir == MV_LEFT)
6619 GfxFrame[x - 1][y] = GfxFrame[x][y];
6620 else if (move_dir == MV_RIGHT)
6621 GfxFrame[x + 1][y] = GfxFrame[x][y];
6622 else if (move_dir == MV_UP)
6623 GfxFrame[x][y - 1] = GfxFrame[x][y];
6624 else if (move_dir == MV_DOWN)
6625 GfxFrame[x][y + 1] = GfxFrame[x][y];
6632 /* special case: animation for Xsand_stonesand_quickout_1/2 twice as fast */
6633 if (tile == Xsand_stonesand_quickout_1 ||
6634 tile == Xsand_stonesand_quickout_2)
6639 if (tile == Xsand_stonesand_1 ||
6640 tile == Xsand_stonesand_2 ||
6641 tile == Xsand_stonesand_3 ||
6642 tile == Xsand_stonesand_4)
6643 printf("::: 2: quicksand frame %d [%d]\n", GfxFrame[x][y], tile);
6647 if (graphic_info[graphic].anim_global_sync)
6648 sync_frame = FrameCounter;
6649 else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY))
6650 sync_frame = GfxFrame[x][y];
6652 sync_frame = 0; /* playfield border (pseudo steel) */
6654 SetRandomAnimationValue(x, y);
6656 int frame = getAnimationFrame(g->anim_frames,
6659 g->anim_start_frame,
6662 g_em->unique_identifier =
6663 (graphic << 16) | ((frame % 8) << 12) | (g_em->width << 6) | g_em->height;
6667 void getGraphicSourceObjectExt_EM(struct GraphicInfo_EM *g_em,
6668 int tile, int frame_em, int x, int y)
6670 int action = object_mapping[tile].action;
6671 int direction = object_mapping[tile].direction;
6672 boolean is_backside = object_mapping[tile].is_backside;
6673 int effective_element = get_effective_element_EM(tile, frame_em);
6675 int effective_action = action;
6677 int effective_action = (frame_em < 7 ? action : ACTION_DEFAULT);
6679 int graphic = (direction == MV_NONE ?
6680 el_act2img(effective_element, effective_action) :
6681 el_act_dir2img(effective_element, effective_action,
6683 int crumbled = (direction == MV_NONE ?
6684 el_act2crm(effective_element, effective_action) :
6685 el_act_dir2crm(effective_element, effective_action,
6687 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
6688 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
6689 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
6690 struct GraphicInfo *g = &graphic_info[graphic];
6692 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
6696 /* special case: graphic uses "2nd movement tile" and has defined
6697 7 frames for movement animation (or less) => use default graphic
6698 for last (8th) frame which ends the movement animation */
6699 if (g->double_movement && g->anim_frames < 8 && frame_em == 7)
6701 effective_action = ACTION_DEFAULT;
6702 graphic = (direction == MV_NONE ?
6703 el_act2img(effective_element, effective_action) :
6704 el_act_dir2img(effective_element, effective_action,
6706 crumbled = (direction == MV_NONE ?
6707 el_act2crm(effective_element, effective_action) :
6708 el_act_dir2crm(effective_element, effective_action,
6711 g = &graphic_info[graphic];
6721 if (frame_em == 0) /* reset animation frame for certain elements */
6723 if (check_linear_animation_EM(tile))
6728 if (graphic_info[graphic].anim_global_sync)
6729 sync_frame = FrameCounter;
6730 else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY))
6731 sync_frame = GfxFrame[x][y];
6733 sync_frame = 0; /* playfield border (pseudo steel) */
6735 SetRandomAnimationValue(x, y);
6740 int xxx_sync_frame = (i == Xdrip_stretch ? 7 :
6741 i == Xdrip_stretchB ? 7 :
6742 i == Ydrip_s2 ? j + 8 :
6743 i == Ydrip_s2B ? j + 8 :
6752 i == Xfake_acid_1 ? 0 :
6753 i == Xfake_acid_2 ? 10 :
6754 i == Xfake_acid_3 ? 20 :
6755 i == Xfake_acid_4 ? 30 :
6756 i == Xfake_acid_5 ? 40 :
6757 i == Xfake_acid_6 ? 50 :
6758 i == Xfake_acid_7 ? 60 :
6759 i == Xfake_acid_8 ? 70 :
6761 i == Xball_2B ? j + 8 :
6762 i == Yball_eat ? j + 1 :
6763 i == Ykey_1_eat ? j + 1 :
6764 i == Ykey_2_eat ? j + 1 :
6765 i == Ykey_3_eat ? j + 1 :
6766 i == Ykey_4_eat ? j + 1 :
6767 i == Ykey_5_eat ? j + 1 :
6768 i == Ykey_6_eat ? j + 1 :
6769 i == Ykey_7_eat ? j + 1 :
6770 i == Ykey_8_eat ? j + 1 :
6771 i == Ylenses_eat ? j + 1 :
6772 i == Ymagnify_eat ? j + 1 :
6773 i == Ygrass_eat ? j + 1 :
6774 i == Ydirt_eat ? j + 1 :
6775 i == Xamoeba_1 ? 0 :
6776 i == Xamoeba_2 ? 1 :
6777 i == Xamoeba_3 ? 2 :
6778 i == Xamoeba_4 ? 3 :
6779 i == Xamoeba_5 ? 0 :
6780 i == Xamoeba_6 ? 1 :
6781 i == Xamoeba_7 ? 2 :
6782 i == Xamoeba_8 ? 3 :
6783 i == Xexit_2 ? j + 8 :
6784 i == Xexit_3 ? j + 16 :
6785 i == Xdynamite_1 ? 0 :
6786 i == Xdynamite_2 ? 8 :
6787 i == Xdynamite_3 ? 16 :
6788 i == Xdynamite_4 ? 24 :
6789 i == Xsand_stonein_1 ? j + 1 :
6790 i == Xsand_stonein_2 ? j + 9 :
6791 i == Xsand_stonein_3 ? j + 17 :
6792 i == Xsand_stonein_4 ? j + 25 :
6793 i == Xsand_stoneout_1 && j == 0 ? 0 :
6794 i == Xsand_stoneout_1 && j == 1 ? 0 :
6795 i == Xsand_stoneout_1 && j == 2 ? 1 :
6796 i == Xsand_stoneout_1 && j == 3 ? 2 :
6797 i == Xsand_stoneout_1 && j == 4 ? 2 :
6798 i == Xsand_stoneout_1 && j == 5 ? 3 :
6799 i == Xsand_stoneout_1 && j == 6 ? 4 :
6800 i == Xsand_stoneout_1 && j == 7 ? 4 :
6801 i == Xsand_stoneout_2 && j == 0 ? 5 :
6802 i == Xsand_stoneout_2 && j == 1 ? 6 :
6803 i == Xsand_stoneout_2 && j == 2 ? 7 :
6804 i == Xsand_stoneout_2 && j == 3 ? 8 :
6805 i == Xsand_stoneout_2 && j == 4 ? 9 :
6806 i == Xsand_stoneout_2 && j == 5 ? 11 :
6807 i == Xsand_stoneout_2 && j == 6 ? 13 :
6808 i == Xsand_stoneout_2 && j == 7 ? 15 :
6809 i == Xboom_bug && j == 1 ? 2 :
6810 i == Xboom_bug && j == 2 ? 2 :
6811 i == Xboom_bug && j == 3 ? 4 :
6812 i == Xboom_bug && j == 4 ? 4 :
6813 i == Xboom_bug && j == 5 ? 2 :
6814 i == Xboom_bug && j == 6 ? 2 :
6815 i == Xboom_bug && j == 7 ? 0 :
6816 i == Xboom_bomb && j == 1 ? 2 :
6817 i == Xboom_bomb && j == 2 ? 2 :
6818 i == Xboom_bomb && j == 3 ? 4 :
6819 i == Xboom_bomb && j == 4 ? 4 :
6820 i == Xboom_bomb && j == 5 ? 2 :
6821 i == Xboom_bomb && j == 6 ? 2 :
6822 i == Xboom_bomb && j == 7 ? 0 :
6823 i == Xboom_android && j == 7 ? 6 :
6824 i == Xboom_1 && j == 1 ? 2 :
6825 i == Xboom_1 && j == 2 ? 2 :
6826 i == Xboom_1 && j == 3 ? 4 :
6827 i == Xboom_1 && j == 4 ? 4 :
6828 i == Xboom_1 && j == 5 ? 6 :
6829 i == Xboom_1 && j == 6 ? 6 :
6830 i == Xboom_1 && j == 7 ? 8 :
6831 i == Xboom_2 && j == 0 ? 8 :
6832 i == Xboom_2 && j == 1 ? 8 :
6833 i == Xboom_2 && j == 2 ? 10 :
6834 i == Xboom_2 && j == 3 ? 10 :
6835 i == Xboom_2 && j == 4 ? 10 :
6836 i == Xboom_2 && j == 5 ? 12 :
6837 i == Xboom_2 && j == 6 ? 12 :
6838 i == Xboom_2 && j == 7 ? 12 :
6840 special_animation && j == 4 ? 3 :
6841 effective_action != action ? 0 :
6847 int xxx_effective_action;
6848 int xxx_has_action_graphics;
6851 int element = object_mapping[i].element_rnd;
6852 int action = object_mapping[i].action;
6853 int direction = object_mapping[i].direction;
6854 boolean is_backside = object_mapping[i].is_backside;
6856 boolean action_removing = (action == ACTION_DIGGING ||
6857 action == ACTION_SNAPPING ||
6858 action == ACTION_COLLECTING);
6860 boolean action_exploding = ((action == ACTION_EXPLODING ||
6861 action == ACTION_SMASHED_BY_ROCK ||
6862 action == ACTION_SMASHED_BY_SPRING) &&
6863 element != EL_DIAMOND);
6864 boolean action_active = (action == ACTION_ACTIVE);
6865 boolean action_other = (action == ACTION_OTHER);
6869 int effective_element = get_effective_element_EM(i, j);
6871 int effective_element = (j > 5 && i == Yacid_splash_eB ? EL_EMPTY :
6872 j > 5 && i == Yacid_splash_wB ? EL_EMPTY :
6874 i == Xdrip_stretch ? element :
6875 i == Xdrip_stretchB ? element :
6876 i == Ydrip_s1 ? element :
6877 i == Ydrip_s1B ? element :
6878 i == Xball_1B ? element :
6879 i == Xball_2 ? element :
6880 i == Xball_2B ? element :
6881 i == Yball_eat ? element :
6882 i == Ykey_1_eat ? element :
6883 i == Ykey_2_eat ? element :
6884 i == Ykey_3_eat ? element :
6885 i == Ykey_4_eat ? element :
6886 i == Ykey_5_eat ? element :
6887 i == Ykey_6_eat ? element :
6888 i == Ykey_7_eat ? element :
6889 i == Ykey_8_eat ? element :
6890 i == Ylenses_eat ? element :
6891 i == Ymagnify_eat ? element :
6892 i == Ygrass_eat ? element :
6893 i == Ydirt_eat ? element :
6894 i == Yemerald_stone ? EL_EMERALD :
6895 i == Ydiamond_stone ? EL_ROCK :
6896 i == Xsand_stonein_1 ? element :
6897 i == Xsand_stonein_2 ? element :
6898 i == Xsand_stonein_3 ? element :
6899 i == Xsand_stonein_4 ? element :
6900 is_backside ? EL_EMPTY :
6901 action_removing ? EL_EMPTY :
6904 int effective_action = (j < 7 ? action :
6905 i == Xdrip_stretch ? action :
6906 i == Xdrip_stretchB ? action :
6907 i == Ydrip_s1 ? action :
6908 i == Ydrip_s1B ? action :
6909 i == Xball_1B ? action :
6910 i == Xball_2 ? action :
6911 i == Xball_2B ? action :
6912 i == Yball_eat ? action :
6913 i == Ykey_1_eat ? action :
6914 i == Ykey_2_eat ? action :
6915 i == Ykey_3_eat ? action :
6916 i == Ykey_4_eat ? action :
6917 i == Ykey_5_eat ? action :
6918 i == Ykey_6_eat ? action :
6919 i == Ykey_7_eat ? action :
6920 i == Ykey_8_eat ? action :
6921 i == Ylenses_eat ? action :
6922 i == Ymagnify_eat ? action :
6923 i == Ygrass_eat ? action :
6924 i == Ydirt_eat ? action :
6925 i == Xsand_stonein_1 ? action :
6926 i == Xsand_stonein_2 ? action :
6927 i == Xsand_stonein_3 ? action :
6928 i == Xsand_stonein_4 ? action :
6929 i == Xsand_stoneout_1 ? action :
6930 i == Xsand_stoneout_2 ? action :
6931 i == Xboom_android ? ACTION_EXPLODING :
6932 action_exploding ? ACTION_EXPLODING :
6933 action_active ? action :
6934 action_other ? action :
6936 int graphic = (el_act_dir2img(effective_element, effective_action,
6938 int crumbled = (el_act_dir2crm(effective_element, effective_action,
6940 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
6941 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
6942 boolean has_action_graphics = (graphic != base_graphic);
6943 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
6944 struct GraphicInfo *g = &graphic_info[graphic];
6946 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
6948 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
6951 /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
6952 boolean special_animation = (action != ACTION_DEFAULT &&
6953 g->anim_frames == 3 &&
6954 g->anim_delay == 2 &&
6955 g->anim_mode & ANIM_LINEAR);
6956 xxx_sync_frame = (i == Xdrip_stretch ? 7 :
6957 i == Xdrip_stretchB ? 7 :
6958 i == Ydrip_s2 ? j + 8 :
6959 i == Ydrip_s2B ? j + 8 :
6968 i == Xfake_acid_1 ? 0 :
6969 i == Xfake_acid_2 ? 10 :
6970 i == Xfake_acid_3 ? 20 :
6971 i == Xfake_acid_4 ? 30 :
6972 i == Xfake_acid_5 ? 40 :
6973 i == Xfake_acid_6 ? 50 :
6974 i == Xfake_acid_7 ? 60 :
6975 i == Xfake_acid_8 ? 70 :
6977 i == Xball_2B ? j + 8 :
6978 i == Yball_eat ? j + 1 :
6979 i == Ykey_1_eat ? j + 1 :
6980 i == Ykey_2_eat ? j + 1 :
6981 i == Ykey_3_eat ? j + 1 :
6982 i == Ykey_4_eat ? j + 1 :
6983 i == Ykey_5_eat ? j + 1 :
6984 i == Ykey_6_eat ? j + 1 :
6985 i == Ykey_7_eat ? j + 1 :
6986 i == Ykey_8_eat ? j + 1 :
6987 i == Ylenses_eat ? j + 1 :
6988 i == Ymagnify_eat ? j + 1 :
6989 i == Ygrass_eat ? j + 1 :
6990 i == Ydirt_eat ? j + 1 :
6991 i == Xamoeba_1 ? 0 :
6992 i == Xamoeba_2 ? 1 :
6993 i == Xamoeba_3 ? 2 :
6994 i == Xamoeba_4 ? 3 :
6995 i == Xamoeba_5 ? 0 :
6996 i == Xamoeba_6 ? 1 :
6997 i == Xamoeba_7 ? 2 :
6998 i == Xamoeba_8 ? 3 :
6999 i == Xexit_2 ? j + 8 :
7000 i == Xexit_3 ? j + 16 :
7001 i == Xdynamite_1 ? 0 :
7002 i == Xdynamite_2 ? 8 :
7003 i == Xdynamite_3 ? 16 :
7004 i == Xdynamite_4 ? 24 :
7005 i == Xsand_stonein_1 ? j + 1 :
7006 i == Xsand_stonein_2 ? j + 9 :
7007 i == Xsand_stonein_3 ? j + 17 :
7008 i == Xsand_stonein_4 ? j + 25 :
7009 i == Xsand_stoneout_1 && j == 0 ? 0 :
7010 i == Xsand_stoneout_1 && j == 1 ? 0 :
7011 i == Xsand_stoneout_1 && j == 2 ? 1 :
7012 i == Xsand_stoneout_1 && j == 3 ? 2 :
7013 i == Xsand_stoneout_1 && j == 4 ? 2 :
7014 i == Xsand_stoneout_1 && j == 5 ? 3 :
7015 i == Xsand_stoneout_1 && j == 6 ? 4 :
7016 i == Xsand_stoneout_1 && j == 7 ? 4 :
7017 i == Xsand_stoneout_2 && j == 0 ? 5 :
7018 i == Xsand_stoneout_2 && j == 1 ? 6 :
7019 i == Xsand_stoneout_2 && j == 2 ? 7 :
7020 i == Xsand_stoneout_2 && j == 3 ? 8 :
7021 i == Xsand_stoneout_2 && j == 4 ? 9 :
7022 i == Xsand_stoneout_2 && j == 5 ? 11 :
7023 i == Xsand_stoneout_2 && j == 6 ? 13 :
7024 i == Xsand_stoneout_2 && j == 7 ? 15 :
7025 i == Xboom_bug && j == 1 ? 2 :
7026 i == Xboom_bug && j == 2 ? 2 :
7027 i == Xboom_bug && j == 3 ? 4 :
7028 i == Xboom_bug && j == 4 ? 4 :
7029 i == Xboom_bug && j == 5 ? 2 :
7030 i == Xboom_bug && j == 6 ? 2 :
7031 i == Xboom_bug && j == 7 ? 0 :
7032 i == Xboom_bomb && j == 1 ? 2 :
7033 i == Xboom_bomb && j == 2 ? 2 :
7034 i == Xboom_bomb && j == 3 ? 4 :
7035 i == Xboom_bomb && j == 4 ? 4 :
7036 i == Xboom_bomb && j == 5 ? 2 :
7037 i == Xboom_bomb && j == 6 ? 2 :
7038 i == Xboom_bomb && j == 7 ? 0 :
7039 i == Xboom_android && j == 7 ? 6 :
7040 i == Xboom_1 && j == 1 ? 2 :
7041 i == Xboom_1 && j == 2 ? 2 :
7042 i == Xboom_1 && j == 3 ? 4 :
7043 i == Xboom_1 && j == 4 ? 4 :
7044 i == Xboom_1 && j == 5 ? 6 :
7045 i == Xboom_1 && j == 6 ? 6 :
7046 i == Xboom_1 && j == 7 ? 8 :
7047 i == Xboom_2 && j == 0 ? 8 :
7048 i == Xboom_2 && j == 1 ? 8 :
7049 i == Xboom_2 && j == 2 ? 10 :
7050 i == Xboom_2 && j == 3 ? 10 :
7051 i == Xboom_2 && j == 4 ? 10 :
7052 i == Xboom_2 && j == 5 ? 12 :
7053 i == Xboom_2 && j == 6 ? 12 :
7054 i == Xboom_2 && j == 7 ? 12 :
7055 special_animation && j == 4 ? 3 :
7056 effective_action != action ? 0 :
7059 xxx_effective_action = effective_action;
7060 xxx_has_action_graphics = has_action_graphics;
7065 int frame = getAnimationFrame(g->anim_frames,
7068 g->anim_start_frame,
7082 int old_src_x = g_em->src_x;
7083 int old_src_y = g_em->src_y;
7087 getGraphicSourceExt(graphic, frame, &g_em->bitmap, &g_em->src_x, &g_em->src_y,
7088 g->double_movement && is_backside);
7090 getGraphicSourceExt(graphic, frame, &g_em->bitmap,
7091 &g_em->src_x, &g_em->src_y, FALSE);
7102 if (graphic == IMG_BUG_MOVING_RIGHT)
7103 printf("::: %d, %d, %d: %d, %d [%d, %d -> %d, %d]\n", graphic, x, y,
7104 g->double_movement, is_backside,
7105 old_src_x, old_src_y, g_em->src_x, g_em->src_y);
7113 g_em->src_offset_x = 0;
7114 g_em->src_offset_y = 0;
7115 g_em->dst_offset_x = 0;
7116 g_em->dst_offset_y = 0;
7117 g_em->width = TILEX;
7118 g_em->height = TILEY;
7120 g_em->preserve_background = FALSE;
7123 /* (updating the "crumbled" graphic definitions is probably not really needed,
7124 as animations for crumbled graphics can't be longer than one EMC cycle) */
7126 set_crumbled_graphics_EM(g_em, has_crumbled_graphics, crumbled,
7131 g_em->crumbled_bitmap = NULL;
7132 g_em->crumbled_src_x = 0;
7133 g_em->crumbled_src_y = 0;
7135 g_em->has_crumbled_graphics = FALSE;
7137 if (has_crumbled_graphics && crumbled != IMG_EMPTY_SPACE)
7139 int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
7140 g_crumbled->anim_delay,
7141 g_crumbled->anim_mode,
7142 g_crumbled->anim_start_frame,
7145 getGraphicSource(crumbled, frame_crumbled, &g_em->crumbled_bitmap,
7146 &g_em->crumbled_src_x, &g_em->crumbled_src_y);
7148 g_em->has_crumbled_graphics = TRUE;
7154 int effective_action = xxx_effective_action;
7155 int has_action_graphics = xxx_has_action_graphics;
7157 if ((!g->double_movement && (effective_action == ACTION_FALLING ||
7158 effective_action == ACTION_MOVING ||
7159 effective_action == ACTION_PUSHING ||
7160 effective_action == ACTION_EATING)) ||
7161 (!has_action_graphics && (effective_action == ACTION_FILLING ||
7162 effective_action == ACTION_EMPTYING)))
7165 (effective_action == ACTION_FALLING ||
7166 effective_action == ACTION_FILLING ||
7167 effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
7168 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
7169 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? 1 : 0);
7170 int num_steps = (i == Ydrip_s1 ? 16 :
7171 i == Ydrip_s1B ? 16 :
7172 i == Ydrip_s2 ? 16 :
7173 i == Ydrip_s2B ? 16 :
7174 i == Xsand_stonein_1 ? 32 :
7175 i == Xsand_stonein_2 ? 32 :
7176 i == Xsand_stonein_3 ? 32 :
7177 i == Xsand_stonein_4 ? 32 :
7178 i == Xsand_stoneout_1 ? 16 :
7179 i == Xsand_stoneout_2 ? 16 : 8);
7180 int cx = ABS(dx) * (TILEX / num_steps);
7181 int cy = ABS(dy) * (TILEY / num_steps);
7182 int step_frame = (i == Ydrip_s2 ? j + 8 :
7183 i == Ydrip_s2B ? j + 8 :
7184 i == Xsand_stonein_2 ? j + 8 :
7185 i == Xsand_stonein_3 ? j + 16 :
7186 i == Xsand_stonein_4 ? j + 24 :
7187 i == Xsand_stoneout_2 ? j + 8 : j) + 1;
7188 int step = (is_backside ? step_frame : num_steps - step_frame);
7190 if (is_backside) /* tile where movement starts */
7192 if (dx < 0 || dy < 0)
7194 g_em->src_offset_x = cx * step;
7195 g_em->src_offset_y = cy * step;
7199 g_em->dst_offset_x = cx * step;
7200 g_em->dst_offset_y = cy * step;
7203 else /* tile where movement ends */
7205 if (dx < 0 || dy < 0)
7207 g_em->dst_offset_x = cx * step;
7208 g_em->dst_offset_y = cy * step;
7212 g_em->src_offset_x = cx * step;
7213 g_em->src_offset_y = cy * step;
7217 g_em->width = TILEX - cx * step;
7218 g_em->height = TILEY - cy * step;
7221 /* create unique graphic identifier to decide if tile must be redrawn */
7222 /* bit 31 - 16 (16 bit): EM style graphic
7223 bit 15 - 12 ( 4 bit): EM style frame
7224 bit 11 - 6 ( 6 bit): graphic width
7225 bit 5 - 0 ( 6 bit): graphic height */
7226 g_em->unique_identifier =
7227 (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
7233 void getGraphicSourcePlayerExt_EM(struct GraphicInfo_EM *g_em,
7234 int player_nr, int anim, int frame_em)
7236 int element = player_mapping[player_nr][anim].element_rnd;
7237 int action = player_mapping[player_nr][anim].action;
7238 int direction = player_mapping[player_nr][anim].direction;
7239 int graphic = (direction == MV_NONE ?
7240 el_act2img(element, action) :
7241 el_act_dir2img(element, action, direction));
7242 struct GraphicInfo *g = &graphic_info[graphic];
7245 InitPlayerGfxAnimation(&stored_player[player_nr], action, direction);
7247 stored_player[player_nr].StepFrame = frame_em;
7249 sync_frame = stored_player[player_nr].Frame;
7251 int frame = getAnimationFrame(g->anim_frames,
7254 g->anim_start_frame,
7257 getGraphicSourceExt(graphic, frame, &g_em->bitmap,
7258 &g_em->src_x, &g_em->src_y, FALSE);
7261 printf("::: %d: %d, %d [%d]\n",
7263 stored_player[player_nr].Frame,
7264 stored_player[player_nr].StepFrame,
7269 void InitGraphicInfo_EM(void)
7272 struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
7273 struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
7278 int num_em_gfx_errors = 0;
7280 if (graphic_info_em_object[0][0].bitmap == NULL)
7282 /* EM graphics not yet initialized in em_open_all() */
7287 printf("::: [4 errors can be ignored (1 x 'bomb', 3 x 'em_dynamite']\n");
7290 /* always start with reliable default values */
7291 for (i = 0; i < TILE_MAX; i++)
7293 object_mapping[i].element_rnd = EL_UNKNOWN;
7294 object_mapping[i].is_backside = FALSE;
7295 object_mapping[i].action = ACTION_DEFAULT;
7296 object_mapping[i].direction = MV_NONE;
7299 /* always start with reliable default values */
7300 for (p = 0; p < MAX_PLAYERS; p++)
7302 for (i = 0; i < SPR_MAX; i++)
7304 player_mapping[p][i].element_rnd = EL_UNKNOWN;
7305 player_mapping[p][i].action = ACTION_DEFAULT;
7306 player_mapping[p][i].direction = MV_NONE;
7310 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
7312 int e = em_object_mapping_list[i].element_em;
7314 object_mapping[e].element_rnd = em_object_mapping_list[i].element_rnd;
7315 object_mapping[e].is_backside = em_object_mapping_list[i].is_backside;
7317 if (em_object_mapping_list[i].action != -1)
7318 object_mapping[e].action = em_object_mapping_list[i].action;
7320 if (em_object_mapping_list[i].direction != -1)
7321 object_mapping[e].direction =
7322 MV_DIR_FROM_BIT(em_object_mapping_list[i].direction);
7325 for (i = 0; em_player_mapping_list[i].action_em != -1; i++)
7327 int a = em_player_mapping_list[i].action_em;
7328 int p = em_player_mapping_list[i].player_nr;
7330 player_mapping[p][a].element_rnd = em_player_mapping_list[i].element_rnd;
7332 if (em_player_mapping_list[i].action != -1)
7333 player_mapping[p][a].action = em_player_mapping_list[i].action;
7335 if (em_player_mapping_list[i].direction != -1)
7336 player_mapping[p][a].direction =
7337 MV_DIR_FROM_BIT(em_player_mapping_list[i].direction);
7340 for (i = 0; i < TILE_MAX; i++)
7342 int element = object_mapping[i].element_rnd;
7343 int action = object_mapping[i].action;
7344 int direction = object_mapping[i].direction;
7345 boolean is_backside = object_mapping[i].is_backside;
7347 boolean action_removing = (action == ACTION_DIGGING ||
7348 action == ACTION_SNAPPING ||
7349 action == ACTION_COLLECTING);
7351 boolean action_exploding = ((action == ACTION_EXPLODING ||
7352 action == ACTION_SMASHED_BY_ROCK ||
7353 action == ACTION_SMASHED_BY_SPRING) &&
7354 element != EL_DIAMOND);
7355 boolean action_active = (action == ACTION_ACTIVE);
7356 boolean action_other = (action == ACTION_OTHER);
7358 for (j = 0; j < 8; j++)
7361 int effective_element = get_effective_element_EM(i, j);
7363 int effective_element = (j > 5 && i == Yacid_splash_eB ? EL_EMPTY :
7364 j > 5 && i == Yacid_splash_wB ? EL_EMPTY :
7366 i == Xdrip_stretch ? element :
7367 i == Xdrip_stretchB ? element :
7368 i == Ydrip_s1 ? element :
7369 i == Ydrip_s1B ? element :
7370 i == Xball_1B ? element :
7371 i == Xball_2 ? element :
7372 i == Xball_2B ? element :
7373 i == Yball_eat ? element :
7374 i == Ykey_1_eat ? element :
7375 i == Ykey_2_eat ? element :
7376 i == Ykey_3_eat ? element :
7377 i == Ykey_4_eat ? element :
7378 i == Ykey_5_eat ? element :
7379 i == Ykey_6_eat ? element :
7380 i == Ykey_7_eat ? element :
7381 i == Ykey_8_eat ? element :
7382 i == Ylenses_eat ? element :
7383 i == Ymagnify_eat ? element :
7384 i == Ygrass_eat ? element :
7385 i == Ydirt_eat ? element :
7386 i == Yemerald_stone ? EL_EMERALD :
7387 i == Ydiamond_stone ? EL_ROCK :
7388 i == Xsand_stonein_1 ? element :
7389 i == Xsand_stonein_2 ? element :
7390 i == Xsand_stonein_3 ? element :
7391 i == Xsand_stonein_4 ? element :
7392 is_backside ? EL_EMPTY :
7393 action_removing ? EL_EMPTY :
7396 int effective_action = (j < 7 ? action :
7397 i == Xdrip_stretch ? action :
7398 i == Xdrip_stretchB ? action :
7399 i == Ydrip_s1 ? action :
7400 i == Ydrip_s1B ? action :
7401 i == Xball_1B ? action :
7402 i == Xball_2 ? action :
7403 i == Xball_2B ? action :
7404 i == Yball_eat ? action :
7405 i == Ykey_1_eat ? action :
7406 i == Ykey_2_eat ? action :
7407 i == Ykey_3_eat ? action :
7408 i == Ykey_4_eat ? action :
7409 i == Ykey_5_eat ? action :
7410 i == Ykey_6_eat ? action :
7411 i == Ykey_7_eat ? action :
7412 i == Ykey_8_eat ? action :
7413 i == Ylenses_eat ? action :
7414 i == Ymagnify_eat ? action :
7415 i == Ygrass_eat ? action :
7416 i == Ydirt_eat ? action :
7417 i == Xsand_stonein_1 ? action :
7418 i == Xsand_stonein_2 ? action :
7419 i == Xsand_stonein_3 ? action :
7420 i == Xsand_stonein_4 ? action :
7421 i == Xsand_stoneout_1 ? action :
7422 i == Xsand_stoneout_2 ? action :
7423 i == Xboom_android ? ACTION_EXPLODING :
7424 action_exploding ? ACTION_EXPLODING :
7425 action_active ? action :
7426 action_other ? action :
7428 int graphic = (el_act_dir2img(effective_element, effective_action,
7430 int crumbled = (el_act_dir2crm(effective_element, effective_action,
7432 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
7433 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
7434 boolean has_action_graphics = (graphic != base_graphic);
7435 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
7436 struct GraphicInfo *g = &graphic_info[graphic];
7438 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
7440 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
7443 /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
7444 boolean special_animation = (action != ACTION_DEFAULT &&
7445 g->anim_frames == 3 &&
7446 g->anim_delay == 2 &&
7447 g->anim_mode & ANIM_LINEAR);
7448 int sync_frame = (i == Xdrip_stretch ? 7 :
7449 i == Xdrip_stretchB ? 7 :
7450 i == Ydrip_s2 ? j + 8 :
7451 i == Ydrip_s2B ? j + 8 :
7460 i == Xfake_acid_1 ? 0 :
7461 i == Xfake_acid_2 ? 10 :
7462 i == Xfake_acid_3 ? 20 :
7463 i == Xfake_acid_4 ? 30 :
7464 i == Xfake_acid_5 ? 40 :
7465 i == Xfake_acid_6 ? 50 :
7466 i == Xfake_acid_7 ? 60 :
7467 i == Xfake_acid_8 ? 70 :
7469 i == Xball_2B ? j + 8 :
7470 i == Yball_eat ? j + 1 :
7471 i == Ykey_1_eat ? j + 1 :
7472 i == Ykey_2_eat ? j + 1 :
7473 i == Ykey_3_eat ? j + 1 :
7474 i == Ykey_4_eat ? j + 1 :
7475 i == Ykey_5_eat ? j + 1 :
7476 i == Ykey_6_eat ? j + 1 :
7477 i == Ykey_7_eat ? j + 1 :
7478 i == Ykey_8_eat ? j + 1 :
7479 i == Ylenses_eat ? j + 1 :
7480 i == Ymagnify_eat ? j + 1 :
7481 i == Ygrass_eat ? j + 1 :
7482 i == Ydirt_eat ? j + 1 :
7483 i == Xamoeba_1 ? 0 :
7484 i == Xamoeba_2 ? 1 :
7485 i == Xamoeba_3 ? 2 :
7486 i == Xamoeba_4 ? 3 :
7487 i == Xamoeba_5 ? 0 :
7488 i == Xamoeba_6 ? 1 :
7489 i == Xamoeba_7 ? 2 :
7490 i == Xamoeba_8 ? 3 :
7491 i == Xexit_2 ? j + 8 :
7492 i == Xexit_3 ? j + 16 :
7493 i == Xdynamite_1 ? 0 :
7494 i == Xdynamite_2 ? 8 :
7495 i == Xdynamite_3 ? 16 :
7496 i == Xdynamite_4 ? 24 :
7497 i == Xsand_stonein_1 ? j + 1 :
7498 i == Xsand_stonein_2 ? j + 9 :
7499 i == Xsand_stonein_3 ? j + 17 :
7500 i == Xsand_stonein_4 ? j + 25 :
7501 i == Xsand_stoneout_1 && j == 0 ? 0 :
7502 i == Xsand_stoneout_1 && j == 1 ? 0 :
7503 i == Xsand_stoneout_1 && j == 2 ? 1 :
7504 i == Xsand_stoneout_1 && j == 3 ? 2 :
7505 i == Xsand_stoneout_1 && j == 4 ? 2 :
7506 i == Xsand_stoneout_1 && j == 5 ? 3 :
7507 i == Xsand_stoneout_1 && j == 6 ? 4 :
7508 i == Xsand_stoneout_1 && j == 7 ? 4 :
7509 i == Xsand_stoneout_2 && j == 0 ? 5 :
7510 i == Xsand_stoneout_2 && j == 1 ? 6 :
7511 i == Xsand_stoneout_2 && j == 2 ? 7 :
7512 i == Xsand_stoneout_2 && j == 3 ? 8 :
7513 i == Xsand_stoneout_2 && j == 4 ? 9 :
7514 i == Xsand_stoneout_2 && j == 5 ? 11 :
7515 i == Xsand_stoneout_2 && j == 6 ? 13 :
7516 i == Xsand_stoneout_2 && j == 7 ? 15 :
7517 i == Xboom_bug && j == 1 ? 2 :
7518 i == Xboom_bug && j == 2 ? 2 :
7519 i == Xboom_bug && j == 3 ? 4 :
7520 i == Xboom_bug && j == 4 ? 4 :
7521 i == Xboom_bug && j == 5 ? 2 :
7522 i == Xboom_bug && j == 6 ? 2 :
7523 i == Xboom_bug && j == 7 ? 0 :
7524 i == Xboom_bomb && j == 1 ? 2 :
7525 i == Xboom_bomb && j == 2 ? 2 :
7526 i == Xboom_bomb && j == 3 ? 4 :
7527 i == Xboom_bomb && j == 4 ? 4 :
7528 i == Xboom_bomb && j == 5 ? 2 :
7529 i == Xboom_bomb && j == 6 ? 2 :
7530 i == Xboom_bomb && j == 7 ? 0 :
7531 i == Xboom_android && j == 7 ? 6 :
7532 i == Xboom_1 && j == 1 ? 2 :
7533 i == Xboom_1 && j == 2 ? 2 :
7534 i == Xboom_1 && j == 3 ? 4 :
7535 i == Xboom_1 && j == 4 ? 4 :
7536 i == Xboom_1 && j == 5 ? 6 :
7537 i == Xboom_1 && j == 6 ? 6 :
7538 i == Xboom_1 && j == 7 ? 8 :
7539 i == Xboom_2 && j == 0 ? 8 :
7540 i == Xboom_2 && j == 1 ? 8 :
7541 i == Xboom_2 && j == 2 ? 10 :
7542 i == Xboom_2 && j == 3 ? 10 :
7543 i == Xboom_2 && j == 4 ? 10 :
7544 i == Xboom_2 && j == 5 ? 12 :
7545 i == Xboom_2 && j == 6 ? 12 :
7546 i == Xboom_2 && j == 7 ? 12 :
7547 special_animation && j == 4 ? 3 :
7548 effective_action != action ? 0 :
7552 Bitmap *debug_bitmap = g_em->bitmap;
7553 int debug_src_x = g_em->src_x;
7554 int debug_src_y = g_em->src_y;
7557 int frame = getAnimationFrame(g->anim_frames,
7560 g->anim_start_frame,
7563 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y,
7564 g->double_movement && is_backside);
7566 g_em->bitmap = src_bitmap;
7567 g_em->src_x = src_x;
7568 g_em->src_y = src_y;
7569 g_em->src_offset_x = 0;
7570 g_em->src_offset_y = 0;
7571 g_em->dst_offset_x = 0;
7572 g_em->dst_offset_y = 0;
7573 g_em->width = TILEX;
7574 g_em->height = TILEY;
7576 g_em->preserve_background = FALSE;
7579 set_crumbled_graphics_EM(g_em, has_crumbled_graphics, crumbled,
7584 g_em->crumbled_bitmap = NULL;
7585 g_em->crumbled_src_x = 0;
7586 g_em->crumbled_src_y = 0;
7587 g_em->crumbled_border_size = 0;
7589 g_em->has_crumbled_graphics = FALSE;
7592 if (has_crumbled_graphics && crumbled == IMG_EMPTY_SPACE)
7593 printf("::: empty crumbled: %d [%s], %d, %d\n",
7594 effective_element, element_info[effective_element].token_name,
7595 effective_action, direction);
7598 /* if element can be crumbled, but certain action graphics are just empty
7599 space (like instantly snapping sand to empty space in 1 frame), do not
7600 treat these empty space graphics as crumbled graphics in EMC engine */
7601 if (has_crumbled_graphics && crumbled != IMG_EMPTY_SPACE)
7603 int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
7604 g_crumbled->anim_delay,
7605 g_crumbled->anim_mode,
7606 g_crumbled->anim_start_frame,
7609 getGraphicSource(crumbled, frame_crumbled, &src_bitmap, &src_x, &src_y);
7611 g_em->has_crumbled_graphics = TRUE;
7612 g_em->crumbled_bitmap = src_bitmap;
7613 g_em->crumbled_src_x = src_x;
7614 g_em->crumbled_src_y = src_y;
7615 g_em->crumbled_border_size = graphic_info[crumbled].border_size;
7619 if (g_em == &graphic_info_em_object[207][0])
7620 printf("... %d, %d [%d, %d, %d, %d] [%d, %d, %d, %d, %d, %d => %d]\n",
7621 graphic_info_em_object[207][0].crumbled_src_x,
7622 graphic_info_em_object[207][0].crumbled_src_y,
7624 crumbled, frame, src_x, src_y,
7629 g->anim_start_frame,
7631 gfx.anim_random_frame,
7636 printf("::: EMC tile %d is crumbled\n", i);
7642 if (element == EL_ROCK &&
7643 effective_action == ACTION_FILLING)
7644 printf("::: has_action_graphics == %d\n", has_action_graphics);
7647 if ((!g->double_movement && (effective_action == ACTION_FALLING ||
7648 effective_action == ACTION_MOVING ||
7649 effective_action == ACTION_PUSHING ||
7650 effective_action == ACTION_EATING)) ||
7651 (!has_action_graphics && (effective_action == ACTION_FILLING ||
7652 effective_action == ACTION_EMPTYING)))
7655 (effective_action == ACTION_FALLING ||
7656 effective_action == ACTION_FILLING ||
7657 effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
7658 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
7659 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? 1 : 0);
7660 int num_steps = (i == Ydrip_s1 ? 16 :
7661 i == Ydrip_s1B ? 16 :
7662 i == Ydrip_s2 ? 16 :
7663 i == Ydrip_s2B ? 16 :
7664 i == Xsand_stonein_1 ? 32 :
7665 i == Xsand_stonein_2 ? 32 :
7666 i == Xsand_stonein_3 ? 32 :
7667 i == Xsand_stonein_4 ? 32 :
7668 i == Xsand_stoneout_1 ? 16 :
7669 i == Xsand_stoneout_2 ? 16 : 8);
7670 int cx = ABS(dx) * (TILEX / num_steps);
7671 int cy = ABS(dy) * (TILEY / num_steps);
7672 int step_frame = (i == Ydrip_s2 ? j + 8 :
7673 i == Ydrip_s2B ? j + 8 :
7674 i == Xsand_stonein_2 ? j + 8 :
7675 i == Xsand_stonein_3 ? j + 16 :
7676 i == Xsand_stonein_4 ? j + 24 :
7677 i == Xsand_stoneout_2 ? j + 8 : j) + 1;
7678 int step = (is_backside ? step_frame : num_steps - step_frame);
7680 if (is_backside) /* tile where movement starts */
7682 if (dx < 0 || dy < 0)
7684 g_em->src_offset_x = cx * step;
7685 g_em->src_offset_y = cy * step;
7689 g_em->dst_offset_x = cx * step;
7690 g_em->dst_offset_y = cy * step;
7693 else /* tile where movement ends */
7695 if (dx < 0 || dy < 0)
7697 g_em->dst_offset_x = cx * step;
7698 g_em->dst_offset_y = cy * step;
7702 g_em->src_offset_x = cx * step;
7703 g_em->src_offset_y = cy * step;
7707 g_em->width = TILEX - cx * step;
7708 g_em->height = TILEY - cy * step;
7711 /* create unique graphic identifier to decide if tile must be redrawn */
7712 /* bit 31 - 16 (16 bit): EM style graphic
7713 bit 15 - 12 ( 4 bit): EM style frame
7714 bit 11 - 6 ( 6 bit): graphic width
7715 bit 5 - 0 ( 6 bit): graphic height */
7716 g_em->unique_identifier =
7717 (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
7721 /* skip check for EMC elements not contained in original EMC artwork */
7722 if (element == EL_EMC_FAKE_ACID)
7725 if (g_em->bitmap != debug_bitmap ||
7726 g_em->src_x != debug_src_x ||
7727 g_em->src_y != debug_src_y ||
7728 g_em->src_offset_x != 0 ||
7729 g_em->src_offset_y != 0 ||
7730 g_em->dst_offset_x != 0 ||
7731 g_em->dst_offset_y != 0 ||
7732 g_em->width != TILEX ||
7733 g_em->height != TILEY)
7735 static int last_i = -1;
7743 printf("::: EMC GFX ERROR for element %d -> %d ('%s', '%s', %d)",
7744 i, element, element_info[element].token_name,
7745 element_action_info[effective_action].suffix, direction);
7747 if (element != effective_element)
7748 printf(" [%d ('%s')]",
7750 element_info[effective_element].token_name);
7754 if (g_em->bitmap != debug_bitmap)
7755 printf(" %d (%d): different bitmap! (0x%08x != 0x%08x)\n",
7756 j, is_backside, (int)(g_em->bitmap), (int)(debug_bitmap));
7758 if (g_em->src_x != debug_src_x ||
7759 g_em->src_y != debug_src_y)
7760 printf(" frame %d (%c): %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
7761 j, (is_backside ? 'B' : 'F'),
7762 g_em->src_x, g_em->src_y,
7763 g_em->src_x / 32, g_em->src_y / 32,
7764 debug_src_x, debug_src_y,
7765 debug_src_x / 32, debug_src_y / 32);
7767 if (g_em->src_offset_x != 0 ||
7768 g_em->src_offset_y != 0 ||
7769 g_em->dst_offset_x != 0 ||
7770 g_em->dst_offset_y != 0)
7771 printf(" %d (%d): offsets %d,%d and %d,%d should be all 0\n",
7773 g_em->src_offset_x, g_em->src_offset_y,
7774 g_em->dst_offset_x, g_em->dst_offset_y);
7776 if (g_em->width != TILEX ||
7777 g_em->height != TILEY)
7778 printf(" %d (%d): size %d,%d should be %d,%d\n",
7780 g_em->width, g_em->height, TILEX, TILEY);
7782 num_em_gfx_errors++;
7789 for (i = 0; i < TILE_MAX; i++)
7791 for (j = 0; j < 8; j++)
7793 int element = object_mapping[i].element_rnd;
7794 int action = object_mapping[i].action;
7795 int direction = object_mapping[i].direction;
7796 boolean is_backside = object_mapping[i].is_backside;
7797 int graphic_action = el_act_dir2img(element, action, direction);
7798 int graphic_default = el_act_dir2img(element, ACTION_DEFAULT, direction);
7800 if ((action == ACTION_SMASHED_BY_ROCK ||
7801 action == ACTION_SMASHED_BY_SPRING ||
7802 action == ACTION_EATING) &&
7803 graphic_action == graphic_default)
7805 int e = (action == ACTION_SMASHED_BY_ROCK ? Ystone_s :
7806 action == ACTION_SMASHED_BY_SPRING ? Yspring_s :
7807 direction == MV_LEFT ? (is_backside? Yspring_wB: Yspring_w) :
7808 direction == MV_RIGHT ? (is_backside? Yspring_eB: Yspring_e) :
7811 /* no separate animation for "smashed by rock" -- use rock instead */
7812 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
7813 struct GraphicInfo_EM *g_xx = &graphic_info_em_object[e][7 - j];
7815 g_em->bitmap = g_xx->bitmap;
7816 g_em->src_x = g_xx->src_x;
7817 g_em->src_y = g_xx->src_y;
7818 g_em->src_offset_x = g_xx->src_offset_x;
7819 g_em->src_offset_y = g_xx->src_offset_y;
7820 g_em->dst_offset_x = g_xx->dst_offset_x;
7821 g_em->dst_offset_y = g_xx->dst_offset_y;
7822 g_em->width = g_xx->width;
7823 g_em->height = g_xx->height;
7824 g_em->unique_identifier = g_xx->unique_identifier;
7827 g_em->preserve_background = TRUE;
7832 for (p = 0; p < MAX_PLAYERS; p++)
7834 for (i = 0; i < SPR_MAX; i++)
7836 int element = player_mapping[p][i].element_rnd;
7837 int action = player_mapping[p][i].action;
7838 int direction = player_mapping[p][i].direction;
7840 for (j = 0; j < 8; j++)
7842 int effective_element = element;
7843 int effective_action = action;
7844 int graphic = (direction == MV_NONE ?
7845 el_act2img(effective_element, effective_action) :
7846 el_act_dir2img(effective_element, effective_action,
7848 struct GraphicInfo *g = &graphic_info[graphic];
7849 struct GraphicInfo_EM *g_em = &graphic_info_em_player[p][i][7 - j];
7855 Bitmap *debug_bitmap = g_em->bitmap;
7856 int debug_src_x = g_em->src_x;
7857 int debug_src_y = g_em->src_y;
7860 int frame = getAnimationFrame(g->anim_frames,
7863 g->anim_start_frame,
7866 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
7868 g_em->bitmap = src_bitmap;
7869 g_em->src_x = src_x;
7870 g_em->src_y = src_y;
7871 g_em->src_offset_x = 0;
7872 g_em->src_offset_y = 0;
7873 g_em->dst_offset_x = 0;
7874 g_em->dst_offset_y = 0;
7875 g_em->width = TILEX;
7876 g_em->height = TILEY;
7880 /* skip check for EMC elements not contained in original EMC artwork */
7881 if (element == EL_PLAYER_3 ||
7882 element == EL_PLAYER_4)
7885 if (g_em->bitmap != debug_bitmap ||
7886 g_em->src_x != debug_src_x ||
7887 g_em->src_y != debug_src_y)
7889 static int last_i = -1;
7897 printf("::: EMC GFX ERROR for p/a %d/%d -> %d ('%s', '%s', %d)",
7898 p, i, element, element_info[element].token_name,
7899 element_action_info[effective_action].suffix, direction);
7901 if (element != effective_element)
7902 printf(" [%d ('%s')]",
7904 element_info[effective_element].token_name);
7908 if (g_em->bitmap != debug_bitmap)
7909 printf(" %d: different bitmap! (0x%08x != 0x%08x)\n",
7910 j, (int)(g_em->bitmap), (int)(debug_bitmap));
7912 if (g_em->src_x != debug_src_x ||
7913 g_em->src_y != debug_src_y)
7914 printf(" frame %d: %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
7916 g_em->src_x, g_em->src_y,
7917 g_em->src_x / 32, g_em->src_y / 32,
7918 debug_src_x, debug_src_y,
7919 debug_src_x / 32, debug_src_y / 32);
7921 num_em_gfx_errors++;
7931 printf("::: [%d errors found]\n", num_em_gfx_errors);
7937 void getGraphicSource_SP(struct GraphicInfo_SP *g_sp,
7938 int graphic, int sync_frame, int x, int y)
7940 int frame = getGraphicAnimationFrame(graphic, sync_frame);
7942 getGraphicSource(graphic, frame, &g_sp->bitmap, &g_sp->src_x, &g_sp->src_y);
7945 boolean isNextAnimationFrame_SP(int graphic, int sync_frame)
7947 return (IS_NEXT_FRAME(sync_frame, graphic));
7950 int getGraphicInfo_Delay(int graphic)
7952 return graphic_info[graphic].anim_delay;
7955 void PlayMenuSoundExt(int sound)
7957 if (sound == SND_UNDEFINED)
7960 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
7961 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
7964 if (IS_LOOP_SOUND(sound))
7965 PlaySoundLoop(sound);
7970 void PlayMenuSound()
7972 PlayMenuSoundExt(menu.sound[game_status]);
7975 void PlayMenuSoundStereo(int sound, int stereo_position)
7977 if (sound == SND_UNDEFINED)
7980 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
7981 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
7984 if (IS_LOOP_SOUND(sound))
7985 PlaySoundExt(sound, SOUND_MAX_VOLUME, stereo_position, SND_CTRL_PLAY_LOOP);
7987 PlaySoundStereo(sound, stereo_position);
7990 void PlayMenuSoundIfLoopExt(int sound)
7992 if (sound == SND_UNDEFINED)
7995 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
7996 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
7999 if (IS_LOOP_SOUND(sound))
8000 PlaySoundLoop(sound);
8003 void PlayMenuSoundIfLoop()
8005 PlayMenuSoundIfLoopExt(menu.sound[game_status]);
8008 void PlayMenuMusicExt(int music)
8010 if (music == MUS_UNDEFINED)
8013 if (!setup.sound_music)
8019 void PlayMenuMusic()
8021 PlayMenuMusicExt(menu.music[game_status]);
8024 void PlaySoundActivating()
8027 PlaySound(SND_MENU_ITEM_ACTIVATING);
8031 void PlaySoundSelecting()
8034 PlaySound(SND_MENU_ITEM_SELECTING);
8038 void ToggleFullscreenIfNeeded()
8040 boolean change_fullscreen = (setup.fullscreen !=
8041 video.fullscreen_enabled);
8042 boolean change_fullscreen_mode = (video.fullscreen_enabled &&
8043 !strEqual(setup.fullscreen_mode,
8044 video.fullscreen_mode_current));
8046 if (!video.fullscreen_available)
8049 if (change_fullscreen || change_fullscreen_mode)
8051 Bitmap *tmp_backbuffer = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
8053 /* save backbuffer content which gets lost when toggling fullscreen mode */
8054 BlitBitmap(backbuffer, tmp_backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
8056 if (change_fullscreen_mode)
8058 /* keep fullscreen, but change fullscreen mode (screen resolution) */
8059 video.fullscreen_enabled = FALSE; /* force new fullscreen mode */
8062 /* toggle fullscreen */
8063 ChangeVideoModeIfNeeded(setup.fullscreen);
8065 setup.fullscreen = video.fullscreen_enabled;
8067 /* restore backbuffer content from temporary backbuffer backup bitmap */
8068 BlitBitmap(tmp_backbuffer, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
8070 FreeBitmap(tmp_backbuffer);
8073 /* update visible window/screen */
8074 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
8076 redraw_mask = REDRAW_ALL;
8081 void ChangeScreenModeIfNeeded()
8083 if (global.screen.width == WIN_XSIZE &&
8084 global.screen.height == WIN_YSIZE)
8087 WIN_XSIZE = global.screen.width;
8088 WIN_YSIZE = global.screen.height;
8090 InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
8094 SetDrawDeactivationMask(REDRAW_NONE);
8095 SetDrawBackgroundMask(REDRAW_FIELD);
8097 // RedrawBackground();