1 /***********************************************************
2 * Rocks'n'Diamonds -- McDuffin Strikes Back! *
3 *----------------------------------------------------------*
4 * (c) 1995-2006 Artsoft Entertainment *
6 * Detmolder Strasse 189 *
9 * e-mail: info@artsoft.org *
10 *----------------------------------------------------------*
12 ***********************************************************/
14 #include "libgame/libgame.h"
25 /* select level set with EMC X11 graphics before activating EM GFX debugging */
26 #define DEBUG_EM_GFX 0
28 /* tool button identifiers */
29 #define TOOL_CTRL_ID_YES 0
30 #define TOOL_CTRL_ID_NO 1
31 #define TOOL_CTRL_ID_CONFIRM 2
32 #define TOOL_CTRL_ID_PLAYER_1 3
33 #define TOOL_CTRL_ID_PLAYER_2 4
34 #define TOOL_CTRL_ID_PLAYER_3 5
35 #define TOOL_CTRL_ID_PLAYER_4 6
37 #define NUM_TOOL_BUTTONS 7
39 /* forward declaration for internal use */
40 static void UnmapToolButtons();
41 static void HandleToolButtons(struct GadgetInfo *);
42 static int el_act_dir2crm(int, int, int);
43 static int el_act2crm(int, int);
45 static struct GadgetInfo *tool_gadget[NUM_TOOL_BUTTONS];
46 static int request_gadget_id = -1;
48 static char *print_if_not_empty(int element)
50 static char *s = NULL;
51 char *token_name = element_info[element].token_name;
56 s = checked_malloc(strlen(token_name) + 10 + 1);
58 if (element != EL_EMPTY)
59 sprintf(s, "%d\t['%s']", element, token_name);
61 sprintf(s, "%d", element);
66 void DumpTile(int x, int y)
71 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
78 printf("Field Info: SCREEN(%d, %d), LEVEL(%d, %d)\n", sx, sy, x, y);
81 if (!IN_LEV_FIELD(x, y))
83 printf("(not in level field)\n");
89 printf(" Feld: %d\t['%s']\n", Feld[x][y],
90 element_info[Feld[x][y]].token_name);
91 printf(" Back: %s\n", print_if_not_empty(Back[x][y]));
92 printf(" Store: %s\n", print_if_not_empty(Store[x][y]));
93 printf(" Store2: %s\n", print_if_not_empty(Store2[x][y]));
94 printf(" StorePlayer: %s\n", print_if_not_empty(StorePlayer[x][y]));
95 printf(" MovPos: %d\n", MovPos[x][y]);
96 printf(" MovDir: %d\n", MovDir[x][y]);
97 printf(" MovDelay: %d\n", MovDelay[x][y]);
98 printf(" ChangeDelay: %d\n", ChangeDelay[x][y]);
99 printf(" CustomValue: %d\n", CustomValue[x][y]);
100 printf(" GfxElement: %d\n", GfxElement[x][y]);
101 printf(" GfxAction: %d\n", GfxAction[x][y]);
102 printf(" GfxFrame: %d\n", GfxFrame[x][y]);
106 void SetDrawtoField(int mode)
108 if (mode == DRAW_BUFFERED && setup.soft_scrolling)
119 drawto_field = fieldbuffer;
121 else /* DRAW_BACKBUFFER */
127 BX2 = SCR_FIELDX - 1;
128 BY2 = SCR_FIELDY - 1;
132 drawto_field = backbuffer;
136 void RedrawPlayfield(boolean force_redraw, int x, int y, int width, int height)
138 if (game_status == GAME_MODE_PLAYING &&
139 level.game_engine_type == GAME_ENGINE_TYPE_EM)
141 /* currently there is no partial redraw -- always redraw whole playfield */
142 RedrawPlayfield_EM(TRUE);
144 /* blit playfield from scroll buffer to normal back buffer for fading in */
145 BlitScreenToBitmap_EM(backbuffer);
147 else if (game_status == GAME_MODE_PLAYING &&
148 level.game_engine_type == GAME_ENGINE_TYPE_SP)
150 /* currently there is no partial redraw -- always redraw whole playfield */
151 RedrawPlayfield_SP(TRUE);
153 /* blit playfield from scroll buffer to normal back buffer for fading in */
154 BlitScreenToBitmap_SP(backbuffer);
156 else if (game_status == GAME_MODE_PLAYING &&
157 !game.envelope_active)
163 width = gfx.sxsize + 2 * TILEX;
164 height = gfx.sysize + 2 * TILEY;
170 int x1 = (x - SX) / TILEX, y1 = (y - SY) / TILEY;
171 int x2 = (x - SX + width) / TILEX, y2 = (y - SY + height) / TILEY;
173 for (xx = BX1; xx <= BX2; xx++)
174 for (yy = BY1; yy <= BY2; yy++)
175 if (xx >= x1 && xx <= x2 && yy >= y1 && yy <= y2)
176 DrawScreenField(xx, yy);
180 if (setup.soft_scrolling)
182 int fx = FX, fy = FY;
184 fx += (ScreenMovDir & (MV_LEFT|MV_RIGHT) ? ScreenGfxPos : 0);
185 fy += (ScreenMovDir & (MV_UP|MV_DOWN) ? ScreenGfxPos : 0);
187 BlitBitmap(fieldbuffer, backbuffer, fx,fy, SXSIZE,SYSIZE, SX,SY);
199 BlitBitmap(drawto, window, x, y, width, height, x, y);
202 void DrawMaskedBorder_Rect(int x, int y, int width, int height)
204 Bitmap *bitmap = graphic_info[IMG_GLOBAL_BORDER].bitmap;
206 SetClipOrigin(bitmap, bitmap->stored_clip_gc, 0, 0);
207 BlitBitmapMasked(bitmap, backbuffer, x, y, width, height, x, y);
210 void DrawMaskedBorder_FIELD()
212 if (global.border_status >= GAME_MODE_TITLE &&
213 global.border_status <= GAME_MODE_PLAYING &&
214 border.draw_masked[global.border_status])
215 DrawMaskedBorder_Rect(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
218 void DrawMaskedBorder_DOOR_1()
220 if (border.draw_masked[GFX_SPECIAL_ARG_DOOR] &&
221 (global.border_status != GAME_MODE_EDITOR ||
222 border.draw_masked[GFX_SPECIAL_ARG_EDITOR]))
223 DrawMaskedBorder_Rect(DX, DY, DXSIZE, DYSIZE);
226 void DrawMaskedBorder_DOOR_2()
228 if (border.draw_masked[GFX_SPECIAL_ARG_DOOR] &&
229 global.border_status != GAME_MODE_EDITOR)
230 DrawMaskedBorder_Rect(VX, VY, VXSIZE, VYSIZE);
233 void DrawMaskedBorder_DOOR_3()
235 /* currently not available */
238 void DrawMaskedBorder_ALL()
240 DrawMaskedBorder_FIELD();
241 DrawMaskedBorder_DOOR_1();
242 DrawMaskedBorder_DOOR_2();
243 DrawMaskedBorder_DOOR_3();
246 void DrawMaskedBorder(int redraw_mask)
248 /* never draw masked screen borders on borderless screens */
249 if (effectiveGameStatus() == GAME_MODE_LOADING ||
250 effectiveGameStatus() == GAME_MODE_TITLE)
253 if (redraw_mask & REDRAW_ALL)
254 DrawMaskedBorder_ALL();
257 if (redraw_mask & REDRAW_FIELD)
258 DrawMaskedBorder_FIELD();
259 if (redraw_mask & REDRAW_DOOR_1)
260 DrawMaskedBorder_DOOR_1();
261 if (redraw_mask & REDRAW_DOOR_2)
262 DrawMaskedBorder_DOOR_2();
263 if (redraw_mask & REDRAW_DOOR_3)
264 DrawMaskedBorder_DOOR_3();
271 DrawBuffer *buffer = (drawto_field == window ? backbuffer : drawto_field);
274 printf("::: TILES TO REFRESH: %d\n", redraw_tiles);
275 for (x = 0; x < SCR_FIELDX; x++)
276 for (y = 0 ; y < SCR_FIELDY; y++)
277 if (redraw[redraw_x1 + x][redraw_y1 + y])
278 printf("::: - %d, %d [%s]\n",
279 LEVELX(x), LEVELY(y),
280 EL_NAME(Feld[LEVELX(x)][LEVELY(y)]));
283 if (redraw_mask & REDRAW_TILES && redraw_tiles > REDRAWTILES_THRESHOLD)
284 redraw_mask |= REDRAW_FIELD;
286 if (redraw_mask & REDRAW_FIELD)
287 redraw_mask &= ~REDRAW_TILES;
289 if (redraw_mask == REDRAW_NONE)
292 if (redraw_mask & REDRAW_TILES &&
293 game_status == GAME_MODE_PLAYING &&
294 border.draw_masked[GAME_MODE_PLAYING])
295 redraw_mask |= REDRAW_FIELD;
297 if (global.fps_slowdown && game_status == GAME_MODE_PLAYING)
299 static boolean last_frame_skipped = FALSE;
300 boolean skip_even_when_not_scrolling = TRUE;
301 boolean just_scrolling = (ScreenMovDir != 0);
302 boolean verbose = FALSE;
304 if (global.fps_slowdown_factor > 1 &&
305 (FrameCounter % global.fps_slowdown_factor) &&
306 (just_scrolling || skip_even_when_not_scrolling))
308 redraw_mask &= ~REDRAW_MAIN;
310 last_frame_skipped = TRUE;
313 printf("FRAME SKIPPED\n");
317 if (last_frame_skipped)
318 redraw_mask |= REDRAW_FIELD;
320 last_frame_skipped = FALSE;
323 printf("frame not skipped\n");
327 /* synchronize X11 graphics at this point; if we would synchronize the
328 display immediately after the buffer switching (after the XFlush),
329 this could mean that we have to wait for the graphics to complete,
330 although we could go on doing calculations for the next frame */
334 /* prevent drawing masked border to backbuffer when using playfield buffer */
335 if (game_status != GAME_MODE_PLAYING ||
336 redraw_mask & REDRAW_FROM_BACKBUFFER ||
337 buffer == backbuffer)
338 DrawMaskedBorder(redraw_mask);
340 DrawMaskedBorder(redraw_mask & REDRAW_DOORS);
342 if (redraw_mask & REDRAW_ALL)
344 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
346 redraw_mask = REDRAW_NONE;
349 if (redraw_mask & REDRAW_FIELD)
351 if (game_status != GAME_MODE_PLAYING ||
352 redraw_mask & REDRAW_FROM_BACKBUFFER)
354 BlitBitmap(backbuffer, window,
355 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE, REAL_SX, REAL_SY);
359 int fx = FX, fy = FY;
361 if (setup.soft_scrolling)
363 fx += (ScreenMovDir & (MV_LEFT | MV_RIGHT) ? ScreenGfxPos : 0);
364 fy += (ScreenMovDir & (MV_UP | MV_DOWN) ? ScreenGfxPos : 0);
367 if (setup.soft_scrolling ||
368 ABS(ScreenMovPos) + ScrollStepSize == TILEX ||
369 ABS(ScreenMovPos) == ScrollStepSize ||
370 redraw_tiles > REDRAWTILES_THRESHOLD)
372 if (border.draw_masked[GAME_MODE_PLAYING])
374 if (buffer != backbuffer)
376 /* copy playfield buffer to backbuffer to add masked border */
377 BlitBitmap(buffer, backbuffer, fx, fy, SXSIZE, SYSIZE, SX, SY);
378 DrawMaskedBorder(REDRAW_FIELD);
381 BlitBitmap(backbuffer, window,
382 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
387 BlitBitmap(buffer, window, fx, fy, SXSIZE, SYSIZE, SX, SY);
392 printf("redrawing all (ScreenGfxPos == %d) because %s\n",
394 (setup.soft_scrolling ?
395 "setup.soft_scrolling" :
396 ABS(ScreenGfxPos) + ScrollStepSize == TILEX ?
397 "ABS(ScreenGfxPos) + ScrollStepSize == TILEX" :
398 ABS(ScreenGfxPos) == ScrollStepSize ?
399 "ABS(ScreenGfxPos) == ScrollStepSize" :
400 "redraw_tiles > REDRAWTILES_THRESHOLD"));
406 redraw_mask &= ~REDRAW_MAIN;
409 if (redraw_mask & REDRAW_DOORS)
411 if (redraw_mask & REDRAW_DOOR_1)
412 BlitBitmap(backbuffer, window, DX, DY, DXSIZE, DYSIZE, DX, DY);
414 if (redraw_mask & REDRAW_DOOR_2)
415 BlitBitmap(backbuffer, window, VX, VY, VXSIZE, VYSIZE, VX, VY);
417 if (redraw_mask & REDRAW_DOOR_3)
418 BlitBitmap(backbuffer, window, EX, EY, EXSIZE, EYSIZE, EX, EY);
420 redraw_mask &= ~REDRAW_DOORS;
423 if (redraw_mask & REDRAW_MICROLEVEL)
425 BlitBitmap(backbuffer, window, SX, SY + 10 * TILEY, SXSIZE, 7 * TILEY,
426 SX, SY + 10 * TILEY);
428 redraw_mask &= ~REDRAW_MICROLEVEL;
431 if (redraw_mask & REDRAW_TILES)
433 for (x = 0; x < SCR_FIELDX; x++)
434 for (y = 0 ; y < SCR_FIELDY; y++)
435 if (redraw[redraw_x1 + x][redraw_y1 + y])
436 BlitBitmap(buffer, window,
437 FX + x * TILEX, FY + y * TILEY, TILEX, TILEY,
438 SX + x * TILEX, SY + y * TILEY);
441 if (redraw_mask & REDRAW_FPS) /* display frames per second */
446 sprintf(info1, " (only every %d. frame)", global.fps_slowdown_factor);
447 if (!global.fps_slowdown)
450 sprintf(text, "%04.1f fps%s", global.frames_per_second, info1);
452 DrawTextExt(window, SX + SXSIZE + SX, 0, text, FONT_TEXT_2, BLIT_OPAQUE);
454 DrawTextExt(window, SX, SY, text, FONT_TEXT_2, BLIT_OPAQUE);
460 for (x = 0; x < MAX_BUF_XSIZE; x++)
461 for (y = 0; y < MAX_BUF_YSIZE; y++)
464 redraw_mask = REDRAW_NONE;
467 static void FadeCrossSaveBackbuffer()
469 BlitBitmap(backbuffer, bitmap_db_cross, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
472 static void FadeExt(int fade_mask, int fade_mode, int fade_type)
474 static int fade_type_skip = FADE_TYPE_NONE;
475 void (*draw_border_function)(void) = NULL;
476 Bitmap *bitmap = (fade_mode & FADE_TYPE_TRANSFORM ? bitmap_db_cross : NULL);
477 int x, y, width, height;
478 int fade_delay, post_delay;
480 if (fade_type == FADE_TYPE_FADE_OUT)
482 if (fade_type_skip != FADE_TYPE_NONE)
485 printf("::: skipping %d ... [%d] (X)\n", fade_mode, fade_type_skip);
488 /* skip all fade operations until specified fade operation */
489 if (fade_type & fade_type_skip)
490 fade_type_skip = FADE_TYPE_NONE;
495 if (fading.fade_mode & FADE_TYPE_TRANSFORM)
497 FadeCrossSaveBackbuffer();
503 redraw_mask |= fade_mask;
505 if (fade_type == FADE_TYPE_SKIP)
508 printf("::: will skip %d ... [%d]\n", fade_mode, fade_type_skip);
511 fade_type_skip = fade_mode;
517 printf("::: !!! FADING %d ... [%d] [%d]\n", fade_mode, fade_type,
522 fade_delay = fading.fade_delay;
523 post_delay = (fade_mode == FADE_MODE_FADE_OUT ? fading.post_delay : 0);
526 if (fade_type_skip != FADE_TYPE_NONE)
529 printf("::: skipping %d ... [%d]\n", fade_mode, fade_type_skip);
532 /* skip all fade operations until specified fade operation */
533 if (fade_type & fade_type_skip)
534 fade_type_skip = FADE_TYPE_NONE;
544 if (global.autoplay_leveldir)
546 // fading.fade_mode = FADE_MODE_NONE;
553 if (fading.fade_mode == FADE_MODE_NONE)
561 /* !!! what about fade_mask == REDRAW_FIELD | REDRAW_ALL ??? !!! */
564 printf("::: NOW FADING %d ... [%d]\n", fade_mode, fade_type);
568 if (fade_mask == REDRAW_NONE)
569 fade_mask = REDRAW_FIELD;
572 // if (fade_mask & REDRAW_FIELD)
573 if (fade_mask == REDRAW_FIELD)
578 height = FULL_SYSIZE;
581 fade_delay = fading.fade_delay;
582 post_delay = (fade_mode == FADE_MODE_FADE_OUT ? fading.post_delay : 0);
585 if (border.draw_masked_when_fading)
586 draw_border_function = DrawMaskedBorder_FIELD; /* update when fading */
588 DrawMaskedBorder_FIELD(); /* draw once */
590 else /* REDRAW_ALL */
598 fade_delay = fading.fade_delay;
599 post_delay = (fade_mode == FADE_MODE_FADE_OUT ? fading.post_delay : 0);
604 if (!setup.fade_screens ||
606 fading.fade_mode == FADE_MODE_NONE)
608 if (!setup.fade_screens || fade_delay == 0)
611 if (fade_mode == FADE_MODE_FADE_OUT)
615 if (fade_mode == FADE_MODE_FADE_OUT &&
616 fading.fade_mode != FADE_MODE_NONE)
617 ClearRectangle(backbuffer, x, y, width, height);
621 BlitBitmap(backbuffer, window, x, y, width, height, x, y);
622 redraw_mask = REDRAW_NONE;
630 FadeRectangle(bitmap, x, y, width, height, fade_mode, fade_delay, post_delay,
631 draw_border_function);
633 redraw_mask &= ~fade_mask;
636 void FadeIn(int fade_mask)
638 if (fading.fade_mode & FADE_TYPE_TRANSFORM)
639 FadeExt(fade_mask, fading.fade_mode, FADE_TYPE_FADE_IN);
641 FadeExt(fade_mask, FADE_MODE_FADE_IN, FADE_TYPE_FADE_IN);
644 void FadeOut(int fade_mask)
646 if (fading.fade_mode & FADE_TYPE_TRANSFORM)
647 FadeExt(fade_mask, fading.fade_mode, FADE_TYPE_FADE_OUT);
649 FadeExt(fade_mask, FADE_MODE_FADE_OUT, FADE_TYPE_FADE_OUT);
651 global.border_status = game_status;
654 static void FadeSetLeaveNext(struct TitleFadingInfo fading_leave, boolean set)
656 static struct TitleFadingInfo fading_leave_stored;
659 fading_leave_stored = fading_leave;
661 fading = fading_leave_stored;
664 void FadeSetEnterMenu()
666 fading = menu.enter_menu;
669 printf("::: storing enter_menu\n");
672 FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */
675 void FadeSetLeaveMenu()
677 fading = menu.leave_menu;
680 printf("::: storing leave_menu\n");
683 FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */
686 void FadeSetEnterScreen()
688 fading = menu.enter_screen[game_status];
691 printf("::: storing leave_screen[%d]\n", game_status);
694 FadeSetLeaveNext(menu.leave_screen[game_status], TRUE); /* store */
697 void FadeSetNextScreen()
699 fading = menu.next_screen;
702 printf("::: storing next_screen\n");
705 // (do not overwrite fade mode set by FadeSetEnterScreen)
706 // FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */
709 void FadeSetLeaveScreen()
712 printf("::: recalling last stored value\n");
715 FadeSetLeaveNext(menu.leave_screen[game_status], FALSE); /* recall */
718 void FadeSetFromType(int type)
720 if (type & TYPE_ENTER_SCREEN)
721 FadeSetEnterScreen();
722 else if (type & TYPE_ENTER)
724 else if (type & TYPE_LEAVE)
728 void FadeSetDisabled()
730 static struct TitleFadingInfo fading_none = { FADE_MODE_NONE, -1, -1, -1 };
732 fading = fading_none;
735 void FadeSkipNextFadeIn()
737 FadeExt(0, FADE_MODE_SKIP_FADE_IN, FADE_TYPE_SKIP);
740 void FadeSkipNextFadeOut()
742 FadeExt(0, FADE_MODE_SKIP_FADE_OUT, FADE_TYPE_SKIP);
745 void SetWindowBackgroundImageIfDefined(int graphic)
747 if (graphic_info[graphic].bitmap)
748 SetWindowBackgroundBitmap(graphic_info[graphic].bitmap);
751 void SetMainBackgroundImageIfDefined(int graphic)
753 if (graphic_info[graphic].bitmap)
754 SetMainBackgroundBitmap(graphic_info[graphic].bitmap);
757 void SetDoorBackgroundImageIfDefined(int graphic)
759 if (graphic_info[graphic].bitmap)
760 SetDoorBackgroundBitmap(graphic_info[graphic].bitmap);
763 void SetWindowBackgroundImage(int graphic)
765 SetWindowBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
766 graphic_info[graphic].bitmap ?
767 graphic_info[graphic].bitmap :
768 graphic_info[IMG_BACKGROUND].bitmap);
771 void SetMainBackgroundImage(int graphic)
773 SetMainBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
774 graphic_info[graphic].bitmap ?
775 graphic_info[graphic].bitmap :
776 graphic_info[IMG_BACKGROUND].bitmap);
779 void SetDoorBackgroundImage(int graphic)
781 SetDoorBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
782 graphic_info[graphic].bitmap ?
783 graphic_info[graphic].bitmap :
784 graphic_info[IMG_BACKGROUND].bitmap);
787 void SetPanelBackground()
789 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, bitmap_db_panel,
790 DOOR_GFX_PAGEX5, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE, 0, 0);
792 SetDoorBackgroundBitmap(bitmap_db_panel);
795 void DrawBackground(int x, int y, int width, int height)
797 /* !!! "drawto" might still point to playfield buffer here (see below) !!! */
798 /* (when entering hall of fame after playing) */
800 ClearRectangleOnBackground(drawto, x, y, width, height);
802 ClearRectangleOnBackground(backbuffer, x, y, width, height);
805 redraw_mask |= REDRAW_FIELD;
808 void DrawBackgroundForFont(int x, int y, int width, int height, int font_nr)
810 struct FontBitmapInfo *font = getFontBitmapInfo(font_nr);
812 if (font->bitmap == NULL)
815 DrawBackground(x, y, width, height);
818 void DrawBackgroundForGraphic(int x, int y, int width, int height, int graphic)
820 struct GraphicInfo *g = &graphic_info[graphic];
822 if (g->bitmap == NULL)
825 DrawBackground(x, y, width, height);
830 /* !!! "drawto" might still point to playfield buffer here (see above) !!! */
831 /* (when entering hall of fame after playing) */
832 DrawBackground(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
834 /* !!! maybe this should be done before clearing the background !!! */
835 if (setup.soft_scrolling && game_status == GAME_MODE_PLAYING)
837 ClearRectangle(fieldbuffer, 0, 0, FXSIZE, FYSIZE);
838 SetDrawtoField(DRAW_BUFFERED);
841 SetDrawtoField(DRAW_BACKBUFFER);
844 void MarkTileDirty(int x, int y)
846 int xx = redraw_x1 + x;
847 int yy = redraw_y1 + y;
852 redraw[xx][yy] = TRUE;
853 redraw_mask |= REDRAW_TILES;
856 void SetBorderElement()
860 BorderElement = EL_EMPTY;
862 for (y = 0; y < lev_fieldy && BorderElement == EL_EMPTY; y++)
864 for (x = 0; x < lev_fieldx; x++)
866 if (!IS_INDESTRUCTIBLE(Feld[x][y]))
867 BorderElement = EL_STEELWALL;
869 if (y != 0 && y != lev_fieldy - 1 && x != lev_fieldx - 1)
875 void FloodFillLevel(int from_x, int from_y, int fill_element,
876 short field[MAX_LEV_FIELDX][MAX_LEV_FIELDY],
877 int max_fieldx, int max_fieldy)
881 static int check[4][2] = { { -1, 0 }, { 0, -1 }, { 1, 0 }, { 0, 1 } };
882 static int safety = 0;
884 /* check if starting field still has the desired content */
885 if (field[from_x][from_y] == fill_element)
890 if (safety > max_fieldx * max_fieldy)
891 Error(ERR_EXIT, "Something went wrong in 'FloodFill()'. Please debug.");
893 old_element = field[from_x][from_y];
894 field[from_x][from_y] = fill_element;
896 for (i = 0; i < 4; i++)
898 x = from_x + check[i][0];
899 y = from_y + check[i][1];
901 if (IN_FIELD(x, y, max_fieldx, max_fieldy) && field[x][y] == old_element)
902 FloodFillLevel(x, y, fill_element, field, max_fieldx, max_fieldy);
908 void SetRandomAnimationValue(int x, int y)
910 gfx.anim_random_frame = GfxRandom[x][y];
913 inline int getGraphicAnimationFrame(int graphic, int sync_frame)
915 /* animation synchronized with global frame counter, not move position */
916 if (graphic_info[graphic].anim_global_sync || sync_frame < 0)
917 sync_frame = FrameCounter;
919 return getAnimationFrame(graphic_info[graphic].anim_frames,
920 graphic_info[graphic].anim_delay,
921 graphic_info[graphic].anim_mode,
922 graphic_info[graphic].anim_start_frame,
926 void getSizedGraphicSource(int graphic, int frame, int tilesize_raw,
927 Bitmap **bitmap, int *x, int *y)
931 int width_mult, width_div;
932 int height_mult, height_div;
936 { 15, 16, 2, 3 }, /* 1 x 1 */
937 { 7, 8, 2, 3 }, /* 2 x 2 */
938 { 3, 4, 2, 3 }, /* 4 x 4 */
939 { 1, 2, 2, 3 }, /* 8 x 8 */
940 { 0, 1, 2, 3 }, /* 16 x 16 */
941 { 0, 1, 0, 1 }, /* 32 x 32 */
943 struct GraphicInfo *g = &graphic_info[graphic];
944 Bitmap *src_bitmap = g->bitmap;
945 int tilesize = MIN(MAX(1, tilesize_raw), TILESIZE);
946 int offset_calc_pos = log_2(tilesize);
947 int width_mult = offset_calc[offset_calc_pos].width_mult;
948 int width_div = offset_calc[offset_calc_pos].width_div;
949 int height_mult = offset_calc[offset_calc_pos].height_mult;
950 int height_div = offset_calc[offset_calc_pos].height_div;
951 int startx = src_bitmap->width * width_mult / width_div;
952 int starty = src_bitmap->height * height_mult / height_div;
953 int src_x = g->src_x * tilesize / TILESIZE;
954 int src_y = g->src_y * tilesize / TILESIZE;
955 int width = g->width * tilesize / TILESIZE;
956 int height = g->height * tilesize / TILESIZE;
957 int offset_x = g->offset_x * tilesize / TILESIZE;
958 int offset_y = g->offset_y * tilesize / TILESIZE;
960 if (g->offset_y == 0) /* frames are ordered horizontally */
962 int max_width = g->anim_frames_per_line * width;
963 int pos = (src_y / height) * max_width + src_x + frame * offset_x;
965 src_x = pos % max_width;
966 src_y = src_y % height + pos / max_width * height;
968 else if (g->offset_x == 0) /* frames are ordered vertically */
970 int max_height = g->anim_frames_per_line * height;
971 int pos = (src_x / width) * max_height + src_y + frame * offset_y;
973 src_x = src_x % width + pos / max_height * width;
974 src_y = pos % max_height;
976 else /* frames are ordered diagonally */
978 src_x = src_x + frame * offset_x;
979 src_y = src_y + frame * offset_y;
982 *bitmap = src_bitmap;
987 void getMiniGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
990 getSizedGraphicSource(graphic, 0, MINI_TILESIZE, bitmap, x, y);
992 struct GraphicInfo *g = &graphic_info[graphic];
994 int mini_starty = g->bitmap->height * 2 / 3;
997 *x = mini_startx + g->src_x / 2;
998 *y = mini_starty + g->src_y / 2;
1002 inline void getGraphicSourceExt(int graphic, int frame, Bitmap **bitmap,
1003 int *x, int *y, boolean get_backside)
1005 struct GraphicInfo *g = &graphic_info[graphic];
1006 int src_x = g->src_x + (get_backside ? g->offset2_x : 0);
1007 int src_y = g->src_y + (get_backside ? g->offset2_y : 0);
1009 *bitmap = g->bitmap;
1011 if (g->offset_y == 0) /* frames are ordered horizontally */
1013 int max_width = g->anim_frames_per_line * g->width;
1014 int pos = (src_y / g->height) * max_width + src_x + frame * g->offset_x;
1016 *x = pos % max_width;
1017 *y = src_y % g->height + pos / max_width * g->height;
1019 else if (g->offset_x == 0) /* frames are ordered vertically */
1021 int max_height = g->anim_frames_per_line * g->height;
1022 int pos = (src_x / g->width) * max_height + src_y + frame * g->offset_y;
1024 *x = src_x % g->width + pos / max_height * g->width;
1025 *y = pos % max_height;
1027 else /* frames are ordered diagonally */
1029 *x = src_x + frame * g->offset_x;
1030 *y = src_y + frame * g->offset_y;
1034 void getGraphicSource(int graphic, int frame, Bitmap **bitmap, int *x, int *y)
1036 getGraphicSourceExt(graphic, frame, bitmap, x, y, FALSE);
1039 void DrawGraphic(int x, int y, int graphic, int frame)
1042 if (!IN_SCR_FIELD(x, y))
1044 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
1045 printf("DrawGraphic(): This should never happen!\n");
1050 DrawGraphicExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic, frame);
1051 MarkTileDirty(x, y);
1054 void DrawGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
1060 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1061 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
1064 void DrawGraphicThruMask(int x, int y, int graphic, int frame)
1067 if (!IN_SCR_FIELD(x, y))
1069 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
1070 printf("DrawGraphicThruMask(): This should never happen!\n");
1075 DrawGraphicThruMaskExt(drawto_field, FX + x * TILEX, FY + y *TILEY, graphic,
1077 MarkTileDirty(x, y);
1080 void DrawGraphicThruMaskExt(DrawBuffer *d, int dst_x, int dst_y, int graphic,
1086 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1088 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1089 dst_x - src_x, dst_y - src_y);
1090 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX, TILEY, dst_x, dst_y);
1093 void DrawSizedGraphic(int x, int y, int graphic, int frame, int tilesize)
1095 DrawSizedGraphicExt(drawto, SX + x * tilesize, SY + y * tilesize, graphic,
1097 MarkTileDirty(x / tilesize, y / tilesize);
1100 void DrawSizedGraphicExt(DrawBuffer *d, int x, int y, int graphic, int frame,
1106 getSizedGraphicSource(graphic, frame, tilesize, &src_bitmap, &src_x, &src_y);
1107 BlitBitmap(src_bitmap, d, src_x, src_y, tilesize, tilesize, x, y);
1110 void DrawMiniGraphic(int x, int y, int graphic)
1112 DrawMiniGraphicExt(drawto, SX + x * MINI_TILEX,SY + y * MINI_TILEY, graphic);
1113 MarkTileDirty(x / 2, y / 2);
1116 void DrawMiniGraphicExt(DrawBuffer *d, int x, int y, int graphic)
1121 getMiniGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
1122 BlitBitmap(src_bitmap, d, src_x, src_y, MINI_TILEX, MINI_TILEY, x, y);
1125 inline static void DrawGraphicShiftedNormal(int x, int y, int dx, int dy,
1126 int graphic, int frame,
1127 int cut_mode, int mask_mode)
1132 int width = TILEX, height = TILEY;
1135 if (dx || dy) /* shifted graphic */
1137 if (x < BX1) /* object enters playfield from the left */
1144 else if (x > BX2) /* object enters playfield from the right */
1150 else if (x==BX1 && dx < 0) /* object leaves playfield to the left */
1156 else if (x==BX2 && dx > 0) /* object leaves playfield to the right */
1158 else if (dx) /* general horizontal movement */
1159 MarkTileDirty(x + SIGN(dx), y);
1161 if (y < BY1) /* object enters playfield from the top */
1163 if (cut_mode==CUT_BELOW) /* object completely above top border */
1171 else if (y > BY2) /* object enters playfield from the bottom */
1177 else if (y==BY1 && dy < 0) /* object leaves playfield to the top */
1183 else if (dy > 0 && cut_mode == CUT_ABOVE)
1185 if (y == BY2) /* object completely above bottom border */
1191 MarkTileDirty(x, y + 1);
1192 } /* object leaves playfield to the bottom */
1193 else if (dy > 0 && (y == BY2 || cut_mode == CUT_BELOW))
1195 else if (dy) /* general vertical movement */
1196 MarkTileDirty(x, y + SIGN(dy));
1200 if (!IN_SCR_FIELD(x, y))
1202 printf("DrawGraphicShifted(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
1203 printf("DrawGraphicShifted(): This should never happen!\n");
1208 if (width > 0 && height > 0)
1210 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1215 dst_x = FX + x * TILEX + dx;
1216 dst_y = FY + y * TILEY + dy;
1218 if (mask_mode == USE_MASKING)
1220 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1221 dst_x - src_x, dst_y - src_y);
1222 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1226 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1229 MarkTileDirty(x, y);
1233 inline static void DrawGraphicShiftedDouble(int x, int y, int dx, int dy,
1234 int graphic, int frame,
1235 int cut_mode, int mask_mode)
1240 int width = TILEX, height = TILEY;
1243 int x2 = x + SIGN(dx);
1244 int y2 = y + SIGN(dy);
1246 /* !!! DOES NOT WORK FOR SLOW MOVEMENT !!! */
1247 int sync_frame = GfxFrame[LEVELX(x)][LEVELY(y)];
1249 /* movement with two-tile animations must be sync'ed with movement position,
1250 not with current GfxFrame (which can be higher when using slow movement) */
1251 int anim_pos = (dx ? ABS(dx) : ABS(dy));
1252 int anim_frames = graphic_info[graphic].anim_frames;
1254 /* (we also need anim_delay here for movement animations with less frames) */
1255 int anim_delay = graphic_info[graphic].anim_delay;
1256 int sync_frame = anim_pos * anim_frames * anim_delay / TILESIZE;
1258 int sync_frame = anim_pos * anim_frames / TILESIZE;
1261 boolean draw_start_tile = (cut_mode != CUT_ABOVE); /* only for falling! */
1262 boolean draw_end_tile = (cut_mode != CUT_BELOW); /* only for falling! */
1264 /* re-calculate animation frame for two-tile movement animation */
1265 frame = getGraphicAnimationFrame(graphic, sync_frame);
1269 printf("::: %d, %d, %d => %d [%d]\n",
1270 anim_pos, anim_frames, anim_delay, sync_frame, graphic);
1272 printf("::: %d, %d => %d\n",
1273 anim_pos, anim_frames, sync_frame);
1278 printf("::: %d [%d, %d] [%d] [%d]\n", frame, sync_frame, dy,
1279 GfxFrame[LEVELX(x)][LEVELY(y)], mask_mode);
1282 /* check if movement start graphic inside screen area and should be drawn */
1283 if (draw_start_tile && IN_SCR_FIELD(x1, y1))
1285 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, TRUE);
1287 dst_x = FX + x1 * TILEX;
1288 dst_y = FY + y1 * TILEY;
1290 if (mask_mode == USE_MASKING)
1292 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1293 dst_x - src_x, dst_y - src_y);
1294 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1298 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1301 MarkTileDirty(x1, y1);
1304 /* check if movement end graphic inside screen area and should be drawn */
1305 if (draw_end_tile && IN_SCR_FIELD(x2, y2))
1307 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
1309 dst_x = FX + x2 * TILEX;
1310 dst_y = FY + y2 * TILEY;
1312 if (mask_mode == USE_MASKING)
1314 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1315 dst_x - src_x, dst_y - src_y);
1316 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1320 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1323 MarkTileDirty(x2, y2);
1327 static void DrawGraphicShifted(int x, int y, int dx, int dy,
1328 int graphic, int frame,
1329 int cut_mode, int mask_mode)
1333 DrawGraphic(x, y, graphic, frame);
1338 if (graphic_info[graphic].double_movement) /* EM style movement images */
1339 DrawGraphicShiftedDouble(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
1341 DrawGraphicShiftedNormal(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
1344 void DrawGraphicShiftedThruMask(int x, int y, int dx, int dy, int graphic,
1345 int frame, int cut_mode)
1347 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, USE_MASKING);
1350 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
1351 int cut_mode, int mask_mode)
1353 int lx = LEVELX(x), ly = LEVELY(y);
1357 if (IN_LEV_FIELD(lx, ly))
1359 SetRandomAnimationValue(lx, ly);
1361 graphic = el_act_dir2img(element, GfxAction[lx][ly], GfxDir[lx][ly]);
1362 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1364 /* do not use double (EM style) movement graphic when not moving */
1365 if (graphic_info[graphic].double_movement && !dx && !dy)
1367 graphic = el_act_dir2img(element, ACTION_DEFAULT, GfxDir[lx][ly]);
1368 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1371 else /* border element */
1373 graphic = el2img(element);
1374 frame = getGraphicAnimationFrame(graphic, -1);
1377 if (element == EL_EXPANDABLE_WALL)
1379 boolean left_stopped = FALSE, right_stopped = FALSE;
1381 if (!IN_LEV_FIELD(lx - 1, ly) || IS_WALL(Feld[lx - 1][ly]))
1382 left_stopped = TRUE;
1383 if (!IN_LEV_FIELD(lx + 1, ly) || IS_WALL(Feld[lx + 1][ly]))
1384 right_stopped = TRUE;
1386 if (left_stopped && right_stopped)
1388 else if (left_stopped)
1390 graphic = IMG_EXPANDABLE_WALL_GROWING_RIGHT;
1391 frame = graphic_info[graphic].anim_frames - 1;
1393 else if (right_stopped)
1395 graphic = IMG_EXPANDABLE_WALL_GROWING_LEFT;
1396 frame = graphic_info[graphic].anim_frames - 1;
1401 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, mask_mode);
1402 else if (mask_mode == USE_MASKING)
1403 DrawGraphicThruMask(x, y, graphic, frame);
1405 DrawGraphic(x, y, graphic, frame);
1408 void DrawLevelElementExt(int x, int y, int dx, int dy, int element,
1409 int cut_mode, int mask_mode)
1411 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1412 DrawScreenElementExt(SCREENX(x), SCREENY(y), dx, dy, element,
1413 cut_mode, mask_mode);
1416 void DrawScreenElementShifted(int x, int y, int dx, int dy, int element,
1419 DrawScreenElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1422 void DrawLevelElementShifted(int x, int y, int dx, int dy, int element,
1425 DrawLevelElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1428 void DrawLevelElementThruMask(int x, int y, int element)
1430 DrawLevelElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1433 void DrawLevelFieldThruMask(int x, int y)
1435 DrawLevelElementExt(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
1438 /* !!! implementation of quicksand is totally broken !!! */
1439 #define IS_CRUMBLED_TILE(x, y, e) \
1440 (GFX_CRUMBLED(e) && (!IN_LEV_FIELD(x, y) || \
1441 !IS_MOVING(x, y) || \
1442 (e) == EL_QUICKSAND_EMPTYING || \
1443 (e) == EL_QUICKSAND_FAST_EMPTYING))
1445 static void DrawLevelFieldCrumbledInnerCorners(int x, int y, int dx, int dy,
1450 int width, height, cx, cy;
1451 int sx = SCREENX(x), sy = SCREENY(y);
1452 int crumbled_border_size = graphic_info[graphic].border_size;
1455 getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
1457 for (i = 1; i < 4; i++)
1459 int dxx = (i & 1 ? dx : 0);
1460 int dyy = (i & 2 ? dy : 0);
1463 int element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1466 /* check if neighbour field is of same crumble type */
1467 boolean same = (IS_CRUMBLED_TILE(xx, yy, element) &&
1468 graphic_info[graphic].class ==
1469 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class);
1471 /* return if check prevents inner corner */
1472 if (same == (dxx == dx && dyy == dy))
1476 /* if we reach this point, we have an inner corner */
1478 getGraphicSource(graphic, 1, &src_bitmap, &src_x, &src_y);
1480 width = crumbled_border_size;
1481 height = crumbled_border_size;
1482 cx = (dx > 0 ? TILEX - crumbled_border_size : 0);
1483 cy = (dy > 0 ? TILEY - crumbled_border_size : 0);
1485 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1486 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
1489 static void DrawLevelFieldCrumbledBorders(int x, int y, int graphic, int frame,
1494 int width, height, bx, by, cx, cy;
1495 int sx = SCREENX(x), sy = SCREENY(y);
1496 int crumbled_border_size = graphic_info[graphic].border_size;
1499 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1501 /* draw simple, sloppy, non-corner-accurate crumbled border */
1504 width = (dir == 1 || dir == 2 ? crumbled_border_size : TILEX);
1505 height = (dir == 0 || dir == 3 ? crumbled_border_size : TILEY);
1506 cx = (dir == 2 ? TILEX - crumbled_border_size : 0);
1507 cy = (dir == 3 ? TILEY - crumbled_border_size : 0);
1509 if (dir == 1 || dir == 2) /* left or right crumbled border */
1511 width = crumbled_border_size;
1513 cx = (dir == 2 ? TILEX - crumbled_border_size : 0);
1516 else /* top or bottom crumbled border */
1519 height = crumbled_border_size;
1521 cy = (dir == 3 ? TILEY - crumbled_border_size : 0);
1525 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1526 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
1528 /* (remaining middle border part must be at least as big as corner part) */
1529 if (!(graphic_info[graphic].style & STYLE_ACCURATE_BORDERS) ||
1530 crumbled_border_size >= TILESIZE / 3)
1533 /* correct corners of crumbled border, if needed */
1536 for (i = -1; i <= 1; i+=2)
1538 int xx = x + (dir == 0 || dir == 3 ? i : 0);
1539 int yy = y + (dir == 1 || dir == 2 ? i : 0);
1540 int element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1543 /* check if neighbour field is of same crumble type */
1544 if (IS_CRUMBLED_TILE(xx, yy, element) &&
1545 graphic_info[graphic].class ==
1546 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class)
1548 /* no crumbled corner, but continued crumbled border */
1550 int c1 = (dir == 2 || dir == 3 ? TILESIZE - crumbled_border_size : 0);
1551 int c2 = (i == 1 ? TILESIZE - crumbled_border_size : 0);
1552 int b1 = (i == 1 ? crumbled_border_size :
1553 TILESIZE - 2 * crumbled_border_size);
1555 width = crumbled_border_size;
1556 height = crumbled_border_size;
1558 if (dir == 1 || dir == 2)
1573 BlitBitmap(src_bitmap, drawto_field, src_x + bx, src_y + by,
1574 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
1578 if (dir == 1 || dir == 2) /* left or right crumbled border */
1580 for (i = -1; i <= 1; i+=2)
1584 int element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1587 /* check if neighbour field is of same crumble type */
1588 if (IS_CRUMBLED_TILE(xx, yy, element) &&
1589 graphic_info[graphic].class ==
1590 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class)
1592 /* no crumbled corner, but continued crumbled border */
1594 width = crumbled_border_size;
1595 height = crumbled_border_size;
1596 cx = (dir == 2 ? TILEX - crumbled_border_size : 0);
1597 cy = (i == 1 ? TILEY - crumbled_border_size : 0);
1599 by = (i == 1 ? crumbled_border_size :
1600 TILEY - 2 * crumbled_border_size);
1602 BlitBitmap(src_bitmap, drawto_field, src_x + bx, src_y + by,
1603 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
1607 else /* top or bottom crumbled border */
1609 for (i = -1; i <= 1; i+=2)
1613 int element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1616 /* check if neighbour field is of same crumble type */
1617 if (IS_CRUMBLED_TILE(xx, yy, element) &&
1618 graphic_info[graphic].class ==
1619 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class)
1621 /* no crumbled corner, but continued crumbled border */
1623 width = crumbled_border_size;
1624 height = crumbled_border_size;
1625 cx = (i == 1 ? TILEX - crumbled_border_size : 0);
1626 cy = (dir == 3 ? TILEY - crumbled_border_size : 0);
1627 bx = (i == 1 ? crumbled_border_size :
1628 TILEX - 2 * crumbled_border_size);
1631 BlitBitmap(src_bitmap, drawto_field, src_x + bx, src_y + by,
1632 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
1639 static void DrawLevelFieldCrumbledExt(int x, int y, int graphic, int frame)
1641 int sx = SCREENX(x), sy = SCREENY(y);
1644 static int xy[4][2] =
1652 if (!IN_LEV_FIELD(x, y))
1655 element = TILE_GFX_ELEMENT(x, y);
1657 /* crumble field itself */
1658 if (IS_CRUMBLED_TILE(x, y, element))
1660 if (!IN_SCR_FIELD(sx, sy))
1663 for (i = 0; i < 4; i++)
1665 int xx = x + xy[i][0];
1666 int yy = y + xy[i][1];
1668 element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1671 /* check if neighbour field is of same crumble type */
1673 if (IS_CRUMBLED_TILE(xx, yy, element) &&
1674 graphic_info[graphic].class ==
1675 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class)
1678 if (IS_CRUMBLED_TILE(xx, yy, element))
1682 DrawLevelFieldCrumbledBorders(x, y, graphic, frame, i);
1685 if ((graphic_info[graphic].style & STYLE_INNER_CORNERS) &&
1686 graphic_info[graphic].anim_frames == 2)
1688 for (i = 0; i < 4; i++)
1690 int dx = (i & 1 ? +1 : -1);
1691 int dy = (i & 2 ? +1 : -1);
1693 DrawLevelFieldCrumbledInnerCorners(x, y, dx, dy, graphic);
1697 MarkTileDirty(sx, sy);
1699 else /* center field not crumbled -- crumble neighbour fields */
1701 for (i = 0; i < 4; i++)
1703 int xx = x + xy[i][0];
1704 int yy = y + xy[i][1];
1705 int sxx = sx + xy[i][0];
1706 int syy = sy + xy[i][1];
1708 if (!IN_LEV_FIELD(xx, yy) ||
1709 !IN_SCR_FIELD(sxx, syy))
1712 if (Feld[xx][yy] == EL_ELEMENT_SNAPPING)
1715 element = TILE_GFX_ELEMENT(xx, yy);
1717 if (!IS_CRUMBLED_TILE(xx, yy, element))
1720 graphic = el_act2crm(element, ACTION_DEFAULT);
1722 DrawLevelFieldCrumbledBorders(xx, yy, graphic, 0, 3 - i);
1724 MarkTileDirty(sxx, syy);
1729 void DrawLevelFieldCrumbled(int x, int y)
1733 if (!IN_LEV_FIELD(x, y))
1737 /* !!! CHECK THIS !!! */
1740 if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
1741 GFX_CRUMBLED(GfxElement[x][y]))
1744 if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
1745 GfxElement[x][y] != EL_UNDEFINED &&
1746 GFX_CRUMBLED(GfxElement[x][y]))
1748 DrawLevelFieldCrumbledDigging(x, y, GfxDir[x][y], GfxFrame[x][y]);
1755 graphic = el_act2crm(TILE_GFX_ELEMENT(x, y), ACTION_DEFAULT);
1757 graphic = el_act2crm(Feld[x][y], ACTION_DEFAULT);
1760 DrawLevelFieldCrumbledExt(x, y, graphic, 0);
1763 void DrawLevelFieldCrumbledDigging(int x, int y, int direction,
1766 int graphic1 = el_act_dir2img(GfxElement[x][y], ACTION_DIGGING, direction);
1767 int graphic2 = el_act_dir2crm(GfxElement[x][y], ACTION_DIGGING, direction);
1768 int frame1 = getGraphicAnimationFrame(graphic1, step_frame);
1769 int frame2 = getGraphicAnimationFrame(graphic2, step_frame);
1770 int sx = SCREENX(x), sy = SCREENY(y);
1772 DrawGraphic(sx, sy, graphic1, frame1);
1773 DrawLevelFieldCrumbledExt(x, y, graphic2, frame2);
1776 void DrawLevelFieldCrumbledNeighbours(int x, int y)
1778 int sx = SCREENX(x), sy = SCREENY(y);
1779 static int xy[4][2] =
1788 for (i = 0; i < 4; i++)
1790 int xx = x + xy[i][0];
1791 int yy = y + xy[i][1];
1792 int sxx = sx + xy[i][0];
1793 int syy = sy + xy[i][1];
1795 if (!IN_LEV_FIELD(xx, yy) ||
1796 !IN_SCR_FIELD(sxx, syy) ||
1797 !GFX_CRUMBLED(Feld[xx][yy]) ||
1801 DrawLevelField(xx, yy);
1805 static int getBorderElement(int x, int y)
1809 { EL_STEELWALL_TOPLEFT, EL_INVISIBLE_STEELWALL_TOPLEFT },
1810 { EL_STEELWALL_TOPRIGHT, EL_INVISIBLE_STEELWALL_TOPRIGHT },
1811 { EL_STEELWALL_BOTTOMLEFT, EL_INVISIBLE_STEELWALL_BOTTOMLEFT },
1812 { EL_STEELWALL_BOTTOMRIGHT, EL_INVISIBLE_STEELWALL_BOTTOMRIGHT },
1813 { EL_STEELWALL_VERTICAL, EL_INVISIBLE_STEELWALL_VERTICAL },
1814 { EL_STEELWALL_HORIZONTAL, EL_INVISIBLE_STEELWALL_HORIZONTAL },
1815 { EL_STEELWALL, EL_INVISIBLE_STEELWALL }
1817 int steel_type = (BorderElement == EL_STEELWALL ? 0 : 1);
1818 int steel_position = (x == -1 && y == -1 ? 0 :
1819 x == lev_fieldx && y == -1 ? 1 :
1820 x == -1 && y == lev_fieldy ? 2 :
1821 x == lev_fieldx && y == lev_fieldy ? 3 :
1822 x == -1 || x == lev_fieldx ? 4 :
1823 y == -1 || y == lev_fieldy ? 5 : 6);
1825 return border[steel_position][steel_type];
1828 void DrawScreenElement(int x, int y, int element)
1830 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
1831 DrawLevelFieldCrumbled(LEVELX(x), LEVELY(y));
1834 void DrawLevelElement(int x, int y, int element)
1836 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1837 DrawScreenElement(SCREENX(x), SCREENY(y), element);
1840 void DrawScreenField(int x, int y)
1842 int lx = LEVELX(x), ly = LEVELY(y);
1843 int element, content;
1845 if (!IN_LEV_FIELD(lx, ly))
1847 if (lx < -1 || lx > lev_fieldx || ly < -1 || ly > lev_fieldy)
1850 element = getBorderElement(lx, ly);
1852 DrawScreenElement(x, y, element);
1857 element = Feld[lx][ly];
1858 content = Store[lx][ly];
1860 if (IS_MOVING(lx, ly))
1862 int horiz_move = (MovDir[lx][ly] == MV_LEFT || MovDir[lx][ly] == MV_RIGHT);
1863 boolean cut_mode = NO_CUTTING;
1865 if (element == EL_QUICKSAND_EMPTYING ||
1866 element == EL_QUICKSAND_FAST_EMPTYING ||
1867 element == EL_MAGIC_WALL_EMPTYING ||
1868 element == EL_BD_MAGIC_WALL_EMPTYING ||
1869 element == EL_DC_MAGIC_WALL_EMPTYING ||
1870 element == EL_AMOEBA_DROPPING)
1871 cut_mode = CUT_ABOVE;
1872 else if (element == EL_QUICKSAND_FILLING ||
1873 element == EL_QUICKSAND_FAST_FILLING ||
1874 element == EL_MAGIC_WALL_FILLING ||
1875 element == EL_BD_MAGIC_WALL_FILLING ||
1876 element == EL_DC_MAGIC_WALL_FILLING)
1877 cut_mode = CUT_BELOW;
1880 if (lx == 9 && ly == 1)
1881 printf("::: %s [%d] [%d, %d] [%d]\n",
1882 EL_NAME(TILE_GFX_ELEMENT(lx, ly)),
1883 el_act2crm(TILE_GFX_ELEMENT(lx, ly), ACTION_DEFAULT),
1884 element_info[EL_QUICKSAND_EMPTYING].graphic[ACTION_DEFAULT],
1885 element_info[EL_QUICKSAND_EMPTYING].crumbled[ACTION_DEFAULT],
1886 GFX_CRUMBLED(TILE_GFX_ELEMENT(lx, ly)));
1889 if (cut_mode == CUT_ABOVE)
1891 DrawScreenElement(x, y, element);
1893 DrawScreenElementShifted(x, y, 0, 0, element, NO_CUTTING);
1896 DrawScreenElement(x, y, EL_EMPTY);
1899 DrawScreenElementShifted(x, y, MovPos[lx][ly], 0, element, NO_CUTTING);
1900 else if (cut_mode == NO_CUTTING)
1901 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], element, cut_mode);
1904 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], content, cut_mode);
1907 if (cut_mode == CUT_BELOW &&
1908 IN_LEV_FIELD(lx, ly + 1) && IN_SCR_FIELD(x, y + 1))
1909 DrawLevelElement(lx, ly + 1, element);
1913 if (content == EL_ACID)
1915 int dir = MovDir[lx][ly];
1916 int newlx = lx + (dir == MV_LEFT ? -1 : dir == MV_RIGHT ? +1 : 0);
1917 int newly = ly + (dir == MV_UP ? -1 : dir == MV_DOWN ? +1 : 0);
1919 DrawLevelElementThruMask(newlx, newly, EL_ACID);
1922 else if (IS_BLOCKED(lx, ly))
1927 boolean cut_mode = NO_CUTTING;
1928 int element_old, content_old;
1930 Blocked2Moving(lx, ly, &oldx, &oldy);
1933 horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
1934 MovDir[oldx][oldy] == MV_RIGHT);
1936 element_old = Feld[oldx][oldy];
1937 content_old = Store[oldx][oldy];
1939 if (element_old == EL_QUICKSAND_EMPTYING ||
1940 element_old == EL_QUICKSAND_FAST_EMPTYING ||
1941 element_old == EL_MAGIC_WALL_EMPTYING ||
1942 element_old == EL_BD_MAGIC_WALL_EMPTYING ||
1943 element_old == EL_DC_MAGIC_WALL_EMPTYING ||
1944 element_old == EL_AMOEBA_DROPPING)
1945 cut_mode = CUT_ABOVE;
1947 DrawScreenElement(x, y, EL_EMPTY);
1950 DrawScreenElementShifted(sx, sy, MovPos[oldx][oldy], 0, element_old,
1952 else if (cut_mode == NO_CUTTING)
1953 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], element_old,
1956 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], content_old,
1959 else if (IS_DRAWABLE(element))
1960 DrawScreenElement(x, y, element);
1962 DrawScreenElement(x, y, EL_EMPTY);
1965 void DrawLevelField(int x, int y)
1967 if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1968 DrawScreenField(SCREENX(x), SCREENY(y));
1969 else if (IS_MOVING(x, y))
1973 Moving2Blocked(x, y, &newx, &newy);
1974 if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
1975 DrawScreenField(SCREENX(newx), SCREENY(newy));
1977 else if (IS_BLOCKED(x, y))
1981 Blocked2Moving(x, y, &oldx, &oldy);
1982 if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
1983 DrawScreenField(SCREENX(oldx), SCREENY(oldy));
1987 void DrawMiniElement(int x, int y, int element)
1991 graphic = el2edimg(element);
1992 DrawMiniGraphic(x, y, graphic);
1995 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
1997 int x = sx + scroll_x, y = sy + scroll_y;
1999 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
2000 DrawMiniElement(sx, sy, EL_EMPTY);
2001 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
2002 DrawMiniElement(sx, sy, Feld[x][y]);
2004 DrawMiniGraphic(sx, sy, el2edimg(getBorderElement(x, y)));
2007 void DrawEnvelopeBackground(int envelope_nr, int startx, int starty,
2008 int x, int y, int xsize, int ysize, int font_nr)
2010 int font_width = getFontWidth(font_nr);
2011 int font_height = getFontHeight(font_nr);
2012 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
2015 int dst_x = SX + startx + x * font_width;
2016 int dst_y = SY + starty + y * font_height;
2017 int width = graphic_info[graphic].width;
2018 int height = graphic_info[graphic].height;
2019 int inner_width = MAX(width - 2 * font_width, font_width);
2020 int inner_height = MAX(height - 2 * font_height, font_height);
2021 int inner_sx = (width >= 3 * font_width ? font_width : 0);
2022 int inner_sy = (height >= 3 * font_height ? font_height : 0);
2023 boolean draw_masked = graphic_info[graphic].draw_masked;
2025 getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
2027 if (src_bitmap == NULL || width < font_width || height < font_height)
2029 ClearRectangle(drawto, dst_x, dst_y, font_width, font_height);
2033 src_x += (x == 0 ? 0 : x == xsize - 1 ? width - font_width :
2034 inner_sx + (x - 1) * font_width % inner_width);
2035 src_y += (y == 0 ? 0 : y == ysize - 1 ? height - font_height :
2036 inner_sy + (y - 1) * font_height % inner_height);
2040 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
2041 dst_x - src_x, dst_y - src_y);
2042 BlitBitmapMasked(src_bitmap, drawto, src_x, src_y, font_width, font_height,
2046 BlitBitmap(src_bitmap, drawto, src_x, src_y, font_width, font_height,
2050 void AnimateEnvelope(int envelope_nr, int anim_mode, int action)
2052 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
2053 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
2054 int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
2055 boolean ffwd_delay = (tape.playing && tape.fast_forward);
2056 boolean no_delay = (tape.warp_forward);
2057 unsigned long anim_delay = 0;
2058 int frame_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
2059 int anim_delay_value = (no_delay ? 0 : frame_delay_value);
2060 int font_nr = FONT_ENVELOPE_1 + envelope_nr;
2061 int font_width = getFontWidth(font_nr);
2062 int font_height = getFontHeight(font_nr);
2063 int max_xsize = level.envelope[envelope_nr].xsize;
2064 int max_ysize = level.envelope[envelope_nr].ysize;
2065 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize : 0);
2066 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize : 0);
2067 int xend = max_xsize;
2068 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize : 0);
2069 int xstep = (xstart < xend ? 1 : 0);
2070 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
2073 for (x = xstart, y = ystart; x <= xend && y <= yend; x += xstep, y += ystep)
2075 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
2076 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
2077 int sx = (SXSIZE - xsize * font_width) / 2;
2078 int sy = (SYSIZE - ysize * font_height) / 2;
2081 SetDrawtoField(DRAW_BUFFERED);
2083 BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
2085 SetDrawtoField(DRAW_BACKBUFFER);
2087 for (yy = 0; yy < ysize; yy++) for (xx = 0; xx < xsize; xx++)
2088 DrawEnvelopeBackground(envelope_nr, sx,sy, xx,yy, xsize, ysize, font_nr);
2091 DrawTextBuffer(SX + sx + font_width, SY + sy + font_height,
2092 level.envelope[envelope_nr].text, font_nr, max_xsize,
2093 xsize - 2, ysize - 2, mask_mode,
2094 level.envelope[envelope_nr].autowrap,
2095 level.envelope[envelope_nr].centered, FALSE);
2097 DrawTextToTextArea(SX + sx + font_width, SY + sy + font_height,
2098 level.envelope[envelope_nr].text, font_nr, max_xsize,
2099 xsize - 2, ysize - 2, mask_mode);
2102 redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
2105 WaitUntilDelayReached(&anim_delay, anim_delay_value / 2);
2109 void ShowEnvelope(int envelope_nr)
2111 int element = EL_ENVELOPE_1 + envelope_nr;
2112 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
2113 int sound_opening = element_info[element].sound[ACTION_OPENING];
2114 int sound_closing = element_info[element].sound[ACTION_CLOSING];
2115 boolean ffwd_delay = (tape.playing && tape.fast_forward);
2116 boolean no_delay = (tape.warp_forward);
2117 int normal_delay_value = ONE_SECOND_DELAY / (ffwd_delay ? 2 : 1);
2118 int wait_delay_value = (no_delay ? 0 : normal_delay_value);
2119 int anim_mode = graphic_info[graphic].anim_mode;
2120 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
2121 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
2123 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
2125 PlayMenuSoundStereo(sound_opening, SOUND_MIDDLE);
2127 if (anim_mode == ANIM_DEFAULT)
2128 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_OPENING);
2130 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_OPENING);
2133 Delay(wait_delay_value);
2135 WaitForEventToContinue();
2137 PlayMenuSoundStereo(sound_closing, SOUND_MIDDLE);
2139 if (anim_mode != ANIM_NONE)
2140 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_CLOSING);
2142 if (anim_mode == ANIM_DEFAULT)
2143 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_CLOSING);
2145 game.envelope_active = FALSE;
2147 SetDrawtoField(DRAW_BUFFERED);
2149 redraw_mask |= REDRAW_FIELD;
2153 void DrawPreviewElement(int dst_x, int dst_y, int element, int tilesize)
2157 int graphic = el2preimg(element);
2159 getSizedGraphicSource(graphic, 0, tilesize, &src_bitmap, &src_x, &src_y);
2160 BlitBitmap(src_bitmap, drawto, src_x, src_y, tilesize, tilesize, dst_x,dst_y);
2168 SetMainBackgroundImage(IMG_BACKGROUND_PLAYING);
2169 SetDrawBackgroundMask(REDRAW_FIELD);
2171 SetDrawBackgroundMask(REDRAW_NONE);
2176 for (x = BX1; x <= BX2; x++)
2177 for (y = BY1; y <= BY2; y++)
2178 DrawScreenField(x, y);
2180 redraw_mask |= REDRAW_FIELD;
2183 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
2187 for (x = 0; x < size_x; x++)
2188 for (y = 0; y < size_y; y++)
2189 DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
2191 redraw_mask |= REDRAW_FIELD;
2194 static void DrawPreviewLevelExt(int from_x, int from_y)
2196 boolean show_level_border = (BorderElement != EL_EMPTY);
2197 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
2198 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
2199 int tile_size = preview.tile_size;
2200 int preview_width = preview.xsize * tile_size;
2201 int preview_height = preview.ysize * tile_size;
2202 int real_preview_xsize = MIN(level_xsize, preview.xsize);
2203 int real_preview_ysize = MIN(level_ysize, preview.ysize);
2204 int dst_x = SX + ALIGNED_XPOS(preview.x, preview_width, preview.align);
2205 int dst_y = SY + ALIGNED_YPOS(preview.y, preview_height, preview.valign);
2208 DrawBackground(dst_x, dst_y, preview_width, preview_height);
2210 dst_x += (preview_width - real_preview_xsize * tile_size) / 2;
2211 dst_y += (preview_height - real_preview_ysize * tile_size) / 2;
2213 for (x = 0; x < real_preview_xsize; x++)
2215 for (y = 0; y < real_preview_ysize; y++)
2217 int lx = from_x + x + (show_level_border ? -1 : 0);
2218 int ly = from_y + y + (show_level_border ? -1 : 0);
2219 int element = (IN_LEV_FIELD(lx, ly) ? level.field[lx][ly] :
2220 getBorderElement(lx, ly));
2222 DrawPreviewElement(dst_x + x * tile_size, dst_y + y * tile_size,
2223 element, tile_size);
2227 redraw_mask |= REDRAW_MICROLEVEL;
2230 #define MICROLABEL_EMPTY 0
2231 #define MICROLABEL_LEVEL_NAME 1
2232 #define MICROLABEL_LEVEL_AUTHOR_HEAD 2
2233 #define MICROLABEL_LEVEL_AUTHOR 3
2234 #define MICROLABEL_IMPORTED_FROM_HEAD 4
2235 #define MICROLABEL_IMPORTED_FROM 5
2236 #define MICROLABEL_IMPORTED_BY_HEAD 6
2237 #define MICROLABEL_IMPORTED_BY 7
2239 static int getMaxTextLength(struct TextPosInfo *pos, int font_nr)
2241 int max_text_width = SXSIZE;
2242 int font_width = getFontWidth(font_nr);
2244 if (pos->align == ALIGN_CENTER)
2245 max_text_width = (pos->x < SXSIZE / 2 ? pos->x * 2 : (SXSIZE - pos->x) * 2);
2246 else if (pos->align == ALIGN_RIGHT)
2247 max_text_width = pos->x;
2249 max_text_width = SXSIZE - pos->x;
2251 return max_text_width / font_width;
2254 static void DrawPreviewLevelLabelExt(int mode)
2256 struct TextPosInfo *pos = &menu.main.text.level_info_2;
2257 char label_text[MAX_OUTPUT_LINESIZE + 1];
2258 int max_len_label_text;
2260 int font_nr = pos->font;
2263 if (mode == MICROLABEL_LEVEL_AUTHOR_HEAD ||
2264 mode == MICROLABEL_IMPORTED_FROM_HEAD ||
2265 mode == MICROLABEL_IMPORTED_BY_HEAD)
2266 font_nr = pos->font_alt;
2268 int font_nr = FONT_TEXT_2;
2271 if (mode == MICROLABEL_LEVEL_AUTHOR_HEAD ||
2272 mode == MICROLABEL_IMPORTED_FROM_HEAD ||
2273 mode == MICROLABEL_IMPORTED_BY_HEAD)
2274 font_nr = FONT_TEXT_3;
2278 max_len_label_text = getMaxTextLength(pos, font_nr);
2280 max_len_label_text = SXSIZE / getFontWidth(font_nr);
2284 if (pos->size != -1)
2285 max_len_label_text = pos->size;
2288 for (i = 0; i < max_len_label_text; i++)
2289 label_text[i] = ' ';
2290 label_text[max_len_label_text] = '\0';
2292 if (strlen(label_text) > 0)
2295 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
2297 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
2298 int lypos = MICROLABEL2_YPOS;
2300 DrawText(lxpos, lypos, label_text, font_nr);
2305 (mode == MICROLABEL_LEVEL_NAME ? level.name :
2306 mode == MICROLABEL_LEVEL_AUTHOR_HEAD ? "created by" :
2307 mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
2308 mode == MICROLABEL_IMPORTED_FROM_HEAD ? "imported from" :
2309 mode == MICROLABEL_IMPORTED_FROM ? leveldir_current->imported_from :
2310 mode == MICROLABEL_IMPORTED_BY_HEAD ? "imported by" :
2311 mode == MICROLABEL_IMPORTED_BY ? leveldir_current->imported_by :""),
2312 max_len_label_text);
2313 label_text[max_len_label_text] = '\0';
2315 if (strlen(label_text) > 0)
2318 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
2320 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
2321 int lypos = MICROLABEL2_YPOS;
2323 DrawText(lxpos, lypos, label_text, font_nr);
2327 redraw_mask |= REDRAW_MICROLEVEL;
2330 void DrawPreviewLevel(boolean restart)
2332 static unsigned long scroll_delay = 0;
2333 static unsigned long label_delay = 0;
2334 static int from_x, from_y, scroll_direction;
2335 static int label_state, label_counter;
2336 unsigned long scroll_delay_value = preview.step_delay;
2337 boolean show_level_border = (BorderElement != EL_EMPTY);
2338 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
2339 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
2340 int last_game_status = game_status; /* save current game status */
2343 /* force PREVIEW font on preview level */
2344 game_status = GAME_MODE_PSEUDO_PREVIEW;
2352 if (preview.anim_mode == ANIM_CENTERED)
2354 if (level_xsize > preview.xsize)
2355 from_x = (level_xsize - preview.xsize) / 2;
2356 if (level_ysize > preview.ysize)
2357 from_y = (level_ysize - preview.ysize) / 2;
2360 from_x += preview.xoffset;
2361 from_y += preview.yoffset;
2363 scroll_direction = MV_RIGHT;
2367 DrawPreviewLevelExt(from_x, from_y);
2368 DrawPreviewLevelLabelExt(label_state);
2370 /* initialize delay counters */
2371 DelayReached(&scroll_delay, 0);
2372 DelayReached(&label_delay, 0);
2374 if (leveldir_current->name)
2376 struct TextPosInfo *pos = &menu.main.text.level_info_1;
2377 char label_text[MAX_OUTPUT_LINESIZE + 1];
2379 int font_nr = pos->font;
2381 int font_nr = FONT_TEXT_1;
2384 int max_len_label_text = getMaxTextLength(pos, font_nr);
2386 int max_len_label_text = SXSIZE / getFontWidth(font_nr);
2394 if (pos->size != -1)
2395 max_len_label_text = pos->size;
2398 strncpy(label_text, leveldir_current->name, max_len_label_text);
2399 label_text[max_len_label_text] = '\0';
2402 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
2404 lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
2405 lypos = SY + MICROLABEL1_YPOS;
2407 DrawText(lxpos, lypos, label_text, font_nr);
2411 game_status = last_game_status; /* restore current game status */
2416 /* scroll preview level, if needed */
2417 if (preview.anim_mode != ANIM_NONE &&
2418 (level_xsize > preview.xsize || level_ysize > preview.ysize) &&
2419 DelayReached(&scroll_delay, scroll_delay_value))
2421 switch (scroll_direction)
2426 from_x -= preview.step_offset;
2427 from_x = (from_x < 0 ? 0 : from_x);
2430 scroll_direction = MV_UP;
2434 if (from_x < level_xsize - preview.xsize)
2436 from_x += preview.step_offset;
2437 from_x = (from_x > level_xsize - preview.xsize ?
2438 level_xsize - preview.xsize : from_x);
2441 scroll_direction = MV_DOWN;
2447 from_y -= preview.step_offset;
2448 from_y = (from_y < 0 ? 0 : from_y);
2451 scroll_direction = MV_RIGHT;
2455 if (from_y < level_ysize - preview.ysize)
2457 from_y += preview.step_offset;
2458 from_y = (from_y > level_ysize - preview.ysize ?
2459 level_ysize - preview.ysize : from_y);
2462 scroll_direction = MV_LEFT;
2469 DrawPreviewLevelExt(from_x, from_y);
2472 /* !!! THIS ALL SUCKS -- SHOULD BE CLEANLY REWRITTEN !!! */
2473 /* redraw micro level label, if needed */
2474 if (!strEqual(level.name, NAMELESS_LEVEL_NAME) &&
2475 !strEqual(level.author, ANONYMOUS_NAME) &&
2476 !strEqual(level.author, leveldir_current->name) &&
2477 DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
2479 int max_label_counter = 23;
2481 if (leveldir_current->imported_from != NULL &&
2482 strlen(leveldir_current->imported_from) > 0)
2483 max_label_counter += 14;
2484 if (leveldir_current->imported_by != NULL &&
2485 strlen(leveldir_current->imported_by) > 0)
2486 max_label_counter += 14;
2488 label_counter = (label_counter + 1) % max_label_counter;
2489 label_state = (label_counter >= 0 && label_counter <= 7 ?
2490 MICROLABEL_LEVEL_NAME :
2491 label_counter >= 9 && label_counter <= 12 ?
2492 MICROLABEL_LEVEL_AUTHOR_HEAD :
2493 label_counter >= 14 && label_counter <= 21 ?
2494 MICROLABEL_LEVEL_AUTHOR :
2495 label_counter >= 23 && label_counter <= 26 ?
2496 MICROLABEL_IMPORTED_FROM_HEAD :
2497 label_counter >= 28 && label_counter <= 35 ?
2498 MICROLABEL_IMPORTED_FROM :
2499 label_counter >= 37 && label_counter <= 40 ?
2500 MICROLABEL_IMPORTED_BY_HEAD :
2501 label_counter >= 42 && label_counter <= 49 ?
2502 MICROLABEL_IMPORTED_BY : MICROLABEL_EMPTY);
2504 if (leveldir_current->imported_from == NULL &&
2505 (label_state == MICROLABEL_IMPORTED_FROM_HEAD ||
2506 label_state == MICROLABEL_IMPORTED_FROM))
2507 label_state = (label_state == MICROLABEL_IMPORTED_FROM_HEAD ?
2508 MICROLABEL_IMPORTED_BY_HEAD : MICROLABEL_IMPORTED_BY);
2510 DrawPreviewLevelLabelExt(label_state);
2513 game_status = last_game_status; /* restore current game status */
2516 inline void DrawGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
2517 int graphic, int sync_frame, int mask_mode)
2519 int frame = getGraphicAnimationFrame(graphic, sync_frame);
2521 if (mask_mode == USE_MASKING)
2522 DrawGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
2524 DrawGraphicExt(dst_bitmap, x, y, graphic, frame);
2527 inline void DrawGraphicAnimation(int x, int y, int graphic)
2529 int lx = LEVELX(x), ly = LEVELY(y);
2531 if (!IN_SCR_FIELD(x, y))
2534 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
2535 graphic, GfxFrame[lx][ly], NO_MASKING);
2536 MarkTileDirty(x, y);
2539 void DrawLevelGraphicAnimation(int x, int y, int graphic)
2541 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
2544 void DrawLevelElementAnimation(int x, int y, int element)
2546 int graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
2548 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
2551 inline void DrawLevelGraphicAnimationIfNeeded(int x, int y, int graphic)
2553 int sx = SCREENX(x), sy = SCREENY(y);
2555 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
2558 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
2561 DrawGraphicAnimation(sx, sy, graphic);
2564 if (GFX_CRUMBLED(TILE_GFX_ELEMENT(x, y)))
2565 DrawLevelFieldCrumbled(x, y);
2567 if (GFX_CRUMBLED(Feld[x][y]))
2568 DrawLevelFieldCrumbled(x, y);
2572 void DrawLevelElementAnimationIfNeeded(int x, int y, int element)
2574 int sx = SCREENX(x), sy = SCREENY(y);
2577 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
2580 graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
2582 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
2585 DrawGraphicAnimation(sx, sy, graphic);
2587 if (GFX_CRUMBLED(element))
2588 DrawLevelFieldCrumbled(x, y);
2591 static int getPlayerGraphic(struct PlayerInfo *player, int move_dir)
2593 if (player->use_murphy)
2595 /* this works only because currently only one player can be "murphy" ... */
2596 static int last_horizontal_dir = MV_LEFT;
2597 int graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, move_dir);
2599 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
2600 last_horizontal_dir = move_dir;
2602 if (graphic == IMG_SP_MURPHY) /* undefined => use special graphic */
2604 int direction = (player->is_snapping ? move_dir : last_horizontal_dir);
2606 graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, direction);
2612 return el_act_dir2img(player->artwork_element, player->GfxAction,move_dir);
2615 static boolean equalGraphics(int graphic1, int graphic2)
2617 struct GraphicInfo *g1 = &graphic_info[graphic1];
2618 struct GraphicInfo *g2 = &graphic_info[graphic2];
2620 return (g1->bitmap == g2->bitmap &&
2621 g1->src_x == g2->src_x &&
2622 g1->src_y == g2->src_y &&
2623 g1->anim_frames == g2->anim_frames &&
2624 g1->anim_delay == g2->anim_delay &&
2625 g1->anim_mode == g2->anim_mode);
2628 void DrawAllPlayers()
2632 for (i = 0; i < MAX_PLAYERS; i++)
2633 if (stored_player[i].active)
2634 DrawPlayer(&stored_player[i]);
2637 void DrawPlayerField(int x, int y)
2639 if (!IS_PLAYER(x, y))
2642 DrawPlayer(PLAYERINFO(x, y));
2645 #define DRAW_PLAYER_OVER_PUSHED_ELEMENT 1
2647 void DrawPlayer(struct PlayerInfo *player)
2649 int jx = player->jx;
2650 int jy = player->jy;
2651 int move_dir = player->MovDir;
2652 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? +1 : 0);
2653 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? +1 : 0);
2654 int last_jx = (player->is_moving ? jx - dx : jx);
2655 int last_jy = (player->is_moving ? jy - dy : jy);
2656 int next_jx = jx + dx;
2657 int next_jy = jy + dy;
2658 boolean player_is_moving = (player->MovPos ? TRUE : FALSE);
2659 boolean player_is_opaque = FALSE;
2660 int sx = SCREENX(jx), sy = SCREENY(jy);
2661 int sxx = 0, syy = 0;
2662 int element = Feld[jx][jy], last_element = Feld[last_jx][last_jy];
2664 int action = ACTION_DEFAULT;
2665 int last_player_graphic = getPlayerGraphic(player, move_dir);
2666 int last_player_frame = player->Frame;
2669 /* GfxElement[][] is set to the element the player is digging or collecting;
2670 remove also for off-screen player if the player is not moving anymore */
2671 if (IN_LEV_FIELD(jx, jy) && !player_is_moving)
2672 GfxElement[jx][jy] = EL_UNDEFINED;
2674 if (!player->active || !IN_SCR_FIELD(SCREENX(last_jx), SCREENY(last_jy)))
2678 if (!IN_LEV_FIELD(jx, jy))
2680 printf("DrawPlayerField(): x = %d, y = %d\n",jx,jy);
2681 printf("DrawPlayerField(): sx = %d, sy = %d\n",sx,sy);
2682 printf("DrawPlayerField(): This should never happen!\n");
2687 if (element == EL_EXPLOSION)
2690 action = (player->is_pushing ? ACTION_PUSHING :
2691 player->is_digging ? ACTION_DIGGING :
2692 player->is_collecting ? ACTION_COLLECTING :
2693 player->is_moving ? ACTION_MOVING :
2694 player->is_snapping ? ACTION_SNAPPING :
2695 player->is_dropping ? ACTION_DROPPING :
2696 player->is_waiting ? player->action_waiting : ACTION_DEFAULT);
2698 if (player->is_waiting)
2699 move_dir = player->dir_waiting;
2701 InitPlayerGfxAnimation(player, action, move_dir);
2703 /* ----------------------------------------------------------------------- */
2704 /* draw things in the field the player is leaving, if needed */
2705 /* ----------------------------------------------------------------------- */
2707 if (player->is_moving)
2709 if (Back[last_jx][last_jy] && IS_DRAWABLE(last_element))
2711 DrawLevelElement(last_jx, last_jy, Back[last_jx][last_jy]);
2713 if (last_element == EL_DYNAMITE_ACTIVE ||
2714 last_element == EL_EM_DYNAMITE_ACTIVE ||
2715 last_element == EL_SP_DISK_RED_ACTIVE)
2716 DrawDynamite(last_jx, last_jy);
2718 DrawLevelFieldThruMask(last_jx, last_jy);
2720 else if (last_element == EL_DYNAMITE_ACTIVE ||
2721 last_element == EL_EM_DYNAMITE_ACTIVE ||
2722 last_element == EL_SP_DISK_RED_ACTIVE)
2723 DrawDynamite(last_jx, last_jy);
2725 /* !!! this is not enough to prevent flickering of players which are
2726 moving next to each others without a free tile between them -- this
2727 can only be solved by drawing all players layer by layer (first the
2728 background, then the foreground etc.) !!! => TODO */
2729 else if (!IS_PLAYER(last_jx, last_jy))
2730 DrawLevelField(last_jx, last_jy);
2733 DrawLevelField(last_jx, last_jy);
2736 if (player->is_pushing && IN_SCR_FIELD(SCREENX(next_jx), SCREENY(next_jy)))
2737 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
2740 if (!IN_SCR_FIELD(sx, sy))
2743 /* ----------------------------------------------------------------------- */
2744 /* draw things behind the player, if needed */
2745 /* ----------------------------------------------------------------------- */
2748 DrawLevelElement(jx, jy, Back[jx][jy]);
2749 else if (IS_ACTIVE_BOMB(element))
2750 DrawLevelElement(jx, jy, EL_EMPTY);
2753 if (player_is_moving && GfxElement[jx][jy] != EL_UNDEFINED)
2755 int old_element = GfxElement[jx][jy];
2756 int old_graphic = el_act_dir2img(old_element, action, move_dir);
2757 int frame = getGraphicAnimationFrame(old_graphic, player->StepFrame);
2759 if (GFX_CRUMBLED(old_element))
2760 DrawLevelFieldCrumbledDigging(jx, jy, move_dir, player->StepFrame);
2762 DrawGraphic(sx, sy, old_graphic, frame);
2764 if (graphic_info[old_graphic].anim_mode & ANIM_OPAQUE_PLAYER)
2765 player_is_opaque = TRUE;
2769 GfxElement[jx][jy] = EL_UNDEFINED;
2771 /* make sure that pushed elements are drawn with correct frame rate */
2773 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
2775 if (player->is_pushing && player->is_moving && !IS_ANIM_MODE_CE(graphic))
2776 GfxFrame[jx][jy] = player->StepFrame;
2778 if (player->is_pushing && player->is_moving)
2779 GfxFrame[jx][jy] = player->StepFrame;
2782 DrawLevelField(jx, jy);
2786 #if !DRAW_PLAYER_OVER_PUSHED_ELEMENT
2787 /* ----------------------------------------------------------------------- */
2788 /* draw player himself */
2789 /* ----------------------------------------------------------------------- */
2791 graphic = getPlayerGraphic(player, move_dir);
2793 /* in the case of changed player action or direction, prevent the current
2794 animation frame from being restarted for identical animations */
2795 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
2796 player->Frame = last_player_frame;
2798 frame = getGraphicAnimationFrame(graphic, player->Frame);
2802 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
2803 sxx = player->GfxPos;
2805 syy = player->GfxPos;
2808 if (!setup.soft_scrolling && ScreenMovPos)
2811 if (player_is_opaque)
2812 DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
2814 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
2816 if (SHIELD_ON(player))
2818 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
2819 IMG_SHIELD_NORMAL_ACTIVE);
2820 int frame = getGraphicAnimationFrame(graphic, -1);
2822 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
2826 #if DRAW_PLAYER_OVER_PUSHED_ELEMENT
2829 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
2830 sxx = player->GfxPos;
2832 syy = player->GfxPos;
2836 /* ----------------------------------------------------------------------- */
2837 /* draw things the player is pushing, if needed */
2838 /* ----------------------------------------------------------------------- */
2841 printf("::: %d, %d [%d, %d] [%d]\n",
2842 player->is_pushing, player_is_moving, player->GfxAction,
2843 player->is_moving, player_is_moving);
2847 if (player->is_pushing && player->is_moving)
2849 int px = SCREENX(jx), py = SCREENY(jy);
2850 int pxx = (TILEX - ABS(sxx)) * dx;
2851 int pyy = (TILEY - ABS(syy)) * dy;
2852 int gfx_frame = GfxFrame[jx][jy];
2858 if (!IS_MOVING(jx, jy)) /* push movement already finished */
2860 element = Feld[next_jx][next_jy];
2861 gfx_frame = GfxFrame[next_jx][next_jy];
2864 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
2867 sync_frame = (IS_ANIM_MODE_CE(graphic) ? gfx_frame : player->StepFrame);
2868 frame = getGraphicAnimationFrame(graphic, sync_frame);
2870 frame = getGraphicAnimationFrame(graphic, player->StepFrame);
2873 /* draw background element under pushed element (like the Sokoban field) */
2875 if (game.use_masked_pushing && IS_MOVING(jx, jy))
2877 /* this allows transparent pushing animation over non-black background */
2880 DrawLevelElement(jx, jy, Back[jx][jy]);
2882 DrawLevelElement(jx, jy, EL_EMPTY);
2884 if (Back[next_jx][next_jy])
2885 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
2887 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
2889 else if (Back[next_jx][next_jy])
2890 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
2892 if (Back[next_jx][next_jy])
2893 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
2897 printf("::: %d, %d, %d, %d [%d] [%d, %d, %d] [%d] [%d, %d] [%d, %d]\n",
2898 jx, px, player->GfxPos, player->StepFrame,
2903 GfxFrame[jx][jy], GfxFrame[next_jx][next_jy]);
2907 /* do not draw (EM style) pushing animation when pushing is finished */
2908 /* (two-tile animations usually do not contain start and end frame) */
2909 if (graphic_info[graphic].double_movement && !IS_MOVING(jx, jy))
2910 DrawLevelElement(next_jx, next_jy, Feld[next_jx][next_jy]);
2912 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
2914 /* masked drawing is needed for EMC style (double) movement graphics */
2915 /* !!! (ONLY WHEN DRAWING PUSHED ELEMENT OVER THE PLAYER) !!! */
2916 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
2921 #if DRAW_PLAYER_OVER_PUSHED_ELEMENT
2922 /* ----------------------------------------------------------------------- */
2923 /* draw player himself */
2924 /* ----------------------------------------------------------------------- */
2926 graphic = getPlayerGraphic(player, move_dir);
2928 /* in the case of changed player action or direction, prevent the current
2929 animation frame from being restarted for identical animations */
2930 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
2931 player->Frame = last_player_frame;
2933 frame = getGraphicAnimationFrame(graphic, player->Frame);
2937 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
2938 sxx = player->GfxPos;
2940 syy = player->GfxPos;
2943 if (!setup.soft_scrolling && ScreenMovPos)
2946 if (player_is_opaque)
2947 DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
2949 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
2951 if (SHIELD_ON(player))
2953 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
2954 IMG_SHIELD_NORMAL_ACTIVE);
2955 int frame = getGraphicAnimationFrame(graphic, -1);
2957 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
2961 /* ----------------------------------------------------------------------- */
2962 /* draw things in front of player (active dynamite or dynabombs) */
2963 /* ----------------------------------------------------------------------- */
2965 if (IS_ACTIVE_BOMB(element))
2967 graphic = el2img(element);
2968 frame = getGraphicAnimationFrame(graphic, GfxFrame[jx][jy]);
2970 if (game.emulation == EMU_SUPAPLEX)
2971 DrawGraphic(sx, sy, IMG_SP_DISK_RED, frame);
2973 DrawGraphicThruMask(sx, sy, graphic, frame);
2976 if (player_is_moving && last_element == EL_EXPLOSION)
2978 int element = (GfxElement[last_jx][last_jy] != EL_UNDEFINED ?
2979 GfxElement[last_jx][last_jy] : EL_EMPTY);
2980 int graphic = el_act2img(element, ACTION_EXPLODING);
2981 int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
2982 int phase = ExplodePhase[last_jx][last_jy] - 1;
2983 int frame = getGraphicAnimationFrame(graphic, phase - delay);
2986 DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy), graphic, frame);
2989 /* ----------------------------------------------------------------------- */
2990 /* draw elements the player is just walking/passing through/under */
2991 /* ----------------------------------------------------------------------- */
2993 if (player_is_moving)
2995 /* handle the field the player is leaving ... */
2996 if (IS_ACCESSIBLE_INSIDE(last_element))
2997 DrawLevelField(last_jx, last_jy);
2998 else if (IS_ACCESSIBLE_UNDER(last_element))
2999 DrawLevelFieldThruMask(last_jx, last_jy);
3002 /* do not redraw accessible elements if the player is just pushing them */
3003 if (!player_is_moving || !player->is_pushing)
3005 /* ... and the field the player is entering */
3006 if (IS_ACCESSIBLE_INSIDE(element))
3007 DrawLevelField(jx, jy);
3008 else if (IS_ACCESSIBLE_UNDER(element))
3009 DrawLevelFieldThruMask(jx, jy);
3012 MarkTileDirty(sx, sy);
3015 /* ------------------------------------------------------------------------- */
3017 void WaitForEventToContinue()
3019 boolean still_wait = TRUE;
3021 /* simulate releasing mouse button over last gadget, if still pressed */
3023 HandleGadgets(-1, -1, 0);
3025 button_status = MB_RELEASED;
3041 case EVENT_BUTTONPRESS:
3042 case EVENT_KEYPRESS:
3046 case EVENT_KEYRELEASE:
3047 ClearPlayerAction();
3051 HandleOtherEvents(&event);
3055 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
3062 /* don't eat all CPU time */
3067 #define MAX_REQUEST_LINES 13
3068 #define MAX_REQUEST_LINE_FONT1_LEN 7
3069 #define MAX_REQUEST_LINE_FONT2_LEN 10
3071 boolean Request(char *text, unsigned int req_state)
3073 int mx, my, ty, result = -1;
3074 unsigned int old_door_state;
3075 int last_game_status = game_status; /* save current game status */
3076 int max_request_line_len = MAX_REQUEST_LINE_FONT1_LEN;
3077 int font_nr = FONT_TEXT_2;
3078 int max_word_len = 0;
3081 for (text_ptr = text; *text_ptr; text_ptr++)
3083 max_word_len = (*text_ptr != ' ' ? max_word_len + 1 : 0);
3085 if (max_word_len > MAX_REQUEST_LINE_FONT1_LEN)
3087 max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
3089 font_nr = FONT_TEXT_1;
3091 font_nr = FONT_LEVEL_NUMBER;
3098 if (game_status == GAME_MODE_PLAYING)
3100 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
3101 BlitScreenToBitmap_EM(backbuffer);
3102 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
3103 BlitScreenToBitmap_SP(backbuffer);
3106 /* disable deactivated drawing when quick-loading level tape recording */
3107 if (tape.playing && tape.deactivate_display)
3108 TapeDeactivateDisplayOff(TRUE);
3110 SetMouseCursor(CURSOR_DEFAULT);
3112 #if defined(NETWORK_AVALIABLE)
3113 /* pause network game while waiting for request to answer */
3114 if (options.network &&
3115 game_status == GAME_MODE_PLAYING &&
3116 req_state & REQUEST_WAIT_FOR_INPUT)
3117 SendToServer_PausePlaying();
3120 old_door_state = GetDoorState();
3122 /* simulate releasing mouse button over last gadget, if still pressed */
3124 HandleGadgets(-1, -1, 0);
3128 if (old_door_state & DOOR_OPEN_1)
3130 CloseDoor(DOOR_CLOSE_1);
3132 /* save old door content */
3133 BlitBitmap(bitmap_db_door, bitmap_db_door,
3134 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
3135 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
3139 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
3142 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
3144 /* clear door drawing field */
3145 DrawBackground(DX, DY, DXSIZE, DYSIZE);
3147 /* force DOOR font inside door area */
3148 game_status = GAME_MODE_PSEUDO_DOOR;
3150 /* write text for request */
3151 for (ty = 0; ty < MAX_REQUEST_LINES; ty++)
3153 char text_line[max_request_line_len + 1];
3159 for (tl = 0, tx = 0; tx < max_request_line_len; tl++, tx++)
3162 if (!tc || tc == ' ')
3173 strncpy(text_line, text, tl);
3176 DrawText(DX + (DXSIZE - tl * getFontWidth(font_nr)) / 2,
3177 DY + 8 + ty * (getFontHeight(font_nr) + 2),
3178 text_line, font_nr);
3180 text += tl + (tc == ' ' ? 1 : 0);
3183 game_status = last_game_status; /* restore current game status */
3185 if (req_state & REQ_ASK)
3187 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
3188 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
3190 else if (req_state & REQ_CONFIRM)
3192 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
3194 else if (req_state & REQ_PLAYER)
3196 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
3197 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
3198 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
3199 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
3202 /* copy request gadgets to door backbuffer */
3203 BlitBitmap(drawto, bitmap_db_door,
3204 DX, DY, DXSIZE, DYSIZE,
3205 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
3207 OpenDoor(DOOR_OPEN_1);
3209 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
3211 if (game_status == GAME_MODE_PLAYING)
3213 SetPanelBackground();
3214 SetDrawBackgroundMask(REDRAW_DOOR_1);
3218 SetDrawBackgroundMask(REDRAW_FIELD);
3224 if (game_status != GAME_MODE_MAIN)
3227 button_status = MB_RELEASED;
3229 request_gadget_id = -1;
3231 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
3243 case EVENT_BUTTONPRESS:
3244 case EVENT_BUTTONRELEASE:
3245 case EVENT_MOTIONNOTIFY:
3247 if (event.type == EVENT_MOTIONNOTIFY)
3249 if (!PointerInWindow(window))
3250 continue; /* window and pointer are on different screens */
3255 motion_status = TRUE;
3256 mx = ((MotionEvent *) &event)->x;
3257 my = ((MotionEvent *) &event)->y;
3261 motion_status = FALSE;
3262 mx = ((ButtonEvent *) &event)->x;
3263 my = ((ButtonEvent *) &event)->y;
3264 if (event.type == EVENT_BUTTONPRESS)
3265 button_status = ((ButtonEvent *) &event)->button;
3267 button_status = MB_RELEASED;
3270 /* this sets 'request_gadget_id' */
3271 HandleGadgets(mx, my, button_status);
3273 switch (request_gadget_id)
3275 case TOOL_CTRL_ID_YES:
3278 case TOOL_CTRL_ID_NO:
3281 case TOOL_CTRL_ID_CONFIRM:
3282 result = TRUE | FALSE;
3285 case TOOL_CTRL_ID_PLAYER_1:
3288 case TOOL_CTRL_ID_PLAYER_2:
3291 case TOOL_CTRL_ID_PLAYER_3:
3294 case TOOL_CTRL_ID_PLAYER_4:
3305 case EVENT_KEYPRESS:
3306 switch (GetEventKey((KeyEvent *)&event, TRUE))
3309 if (req_state & REQ_CONFIRM)
3325 if (req_state & REQ_PLAYER)
3329 case EVENT_KEYRELEASE:
3330 ClearPlayerAction();
3334 HandleOtherEvents(&event);
3338 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
3340 int joy = AnyJoystick();
3342 if (joy & JOY_BUTTON_1)
3344 else if (joy & JOY_BUTTON_2)
3350 if (game_status == GAME_MODE_PLAYING && local_player->LevelSolved_GameEnd)
3352 HandleGameActions();
3358 if (!PendingEvent()) /* delay only if no pending events */
3369 if (!PendingEvent()) /* delay only if no pending events */
3372 /* don't eat all CPU time */
3379 if (game_status != GAME_MODE_MAIN)
3384 if (!(req_state & REQ_STAY_OPEN))
3386 CloseDoor(DOOR_CLOSE_1);
3388 if (((old_door_state & DOOR_OPEN_1) && !(req_state & REQ_STAY_CLOSED)) ||
3389 (req_state & REQ_REOPEN))
3390 OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
3395 if (game_status == GAME_MODE_PLAYING)
3397 SetPanelBackground();
3398 SetDrawBackgroundMask(REDRAW_DOOR_1);
3402 SetDrawBackgroundMask(REDRAW_FIELD);
3405 #if defined(NETWORK_AVALIABLE)
3406 /* continue network game after request */
3407 if (options.network &&
3408 game_status == GAME_MODE_PLAYING &&
3409 req_state & REQUEST_WAIT_FOR_INPUT)
3410 SendToServer_ContinuePlaying();
3413 /* restore deactivated drawing when quick-loading level tape recording */
3414 if (tape.playing && tape.deactivate_display)
3415 TapeDeactivateDisplayOn();
3420 unsigned int OpenDoor(unsigned int door_state)
3422 if (door_state & DOOR_COPY_BACK)
3424 if (door_state & DOOR_OPEN_1)
3425 BlitBitmap(bitmap_db_door, bitmap_db_door,
3426 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
3427 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
3429 if (door_state & DOOR_OPEN_2)
3430 BlitBitmap(bitmap_db_door, bitmap_db_door,
3431 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY2, VXSIZE, VYSIZE,
3432 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
3434 door_state &= ~DOOR_COPY_BACK;
3437 return MoveDoor(door_state);
3440 unsigned int CloseDoor(unsigned int door_state)
3442 unsigned int old_door_state = GetDoorState();
3444 if (!(door_state & DOOR_NO_COPY_BACK))
3446 if (old_door_state & DOOR_OPEN_1)
3447 BlitBitmap(backbuffer, bitmap_db_door,
3448 DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
3450 if (old_door_state & DOOR_OPEN_2)
3451 BlitBitmap(backbuffer, bitmap_db_door,
3452 VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
3454 door_state &= ~DOOR_NO_COPY_BACK;
3457 return MoveDoor(door_state);
3460 unsigned int GetDoorState()
3462 return MoveDoor(DOOR_GET_STATE);
3465 unsigned int SetDoorState(unsigned int door_state)
3467 return MoveDoor(door_state | DOOR_SET_STATE);
3470 unsigned int MoveDoor(unsigned int door_state)
3472 static int door1 = DOOR_OPEN_1;
3473 static int door2 = DOOR_CLOSE_2;
3474 unsigned long door_delay = 0;
3475 unsigned long door_delay_value;
3478 if (door_1.width < 0 || door_1.width > DXSIZE)
3479 door_1.width = DXSIZE;
3480 if (door_1.height < 0 || door_1.height > DYSIZE)
3481 door_1.height = DYSIZE;
3482 if (door_2.width < 0 || door_2.width > VXSIZE)
3483 door_2.width = VXSIZE;
3484 if (door_2.height < 0 || door_2.height > VYSIZE)
3485 door_2.height = VYSIZE;
3487 if (door_state == DOOR_GET_STATE)
3488 return (door1 | door2);
3490 if (door_state & DOOR_SET_STATE)
3492 if (door_state & DOOR_ACTION_1)
3493 door1 = door_state & DOOR_ACTION_1;
3494 if (door_state & DOOR_ACTION_2)
3495 door2 = door_state & DOOR_ACTION_2;
3497 return (door1 | door2);
3500 if (!(door_state & DOOR_FORCE_REDRAW))
3502 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
3503 door_state &= ~DOOR_OPEN_1;
3504 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
3505 door_state &= ~DOOR_CLOSE_1;
3506 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
3507 door_state &= ~DOOR_OPEN_2;
3508 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
3509 door_state &= ~DOOR_CLOSE_2;
3512 door_delay_value = (door_state & DOOR_ACTION_1 ? door_1.step_delay :
3515 if (setup.quick_doors)
3517 stepsize = 20; /* must be chosen to always draw last frame */
3518 door_delay_value = 0;
3521 if (global.autoplay_leveldir)
3523 door_state |= DOOR_NO_DELAY;
3524 door_state &= ~DOOR_CLOSE_ALL;
3528 if (game_status == GAME_MODE_EDITOR)
3529 door_state |= DOOR_NO_DELAY;
3532 if (door_state & DOOR_ACTION)
3534 boolean handle_door_1 = (door_state & DOOR_ACTION_1);
3535 boolean handle_door_2 = (door_state & DOOR_ACTION_2);
3536 boolean door_1_done = (!handle_door_1);
3537 boolean door_2_done = (!handle_door_2);
3538 boolean door_1_vertical = (door_1.anim_mode & ANIM_VERTICAL);
3539 boolean door_2_vertical = (door_2.anim_mode & ANIM_VERTICAL);
3540 int door_size_1 = (door_1_vertical ? door_1.height : door_1.width);
3541 int door_size_2 = (door_2_vertical ? door_2.height : door_2.width);
3542 int max_door_size_1 = (door_1_vertical ? DYSIZE : DXSIZE);
3543 int max_door_size_2 = (door_2_vertical ? VYSIZE : VXSIZE);
3544 int door_size = (handle_door_1 ? door_size_1 : door_size_2);
3545 int max_door_size = (handle_door_1 ? max_door_size_1 : max_door_size_2);
3546 int door_skip = max_door_size - door_size;
3547 int end = door_size;
3548 int start = ((door_state & DOOR_NO_DELAY) ? end : 0);
3551 if (!(door_state & DOOR_NO_DELAY) && !setup.quick_doors)
3553 /* opening door sound has priority over simultaneously closing door */
3554 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
3555 PlayMenuSoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
3556 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
3557 PlayMenuSoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
3560 for (k = start; k <= end && !(door_1_done && door_2_done); k += stepsize)
3563 Bitmap *bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
3564 GC gc = bitmap->stored_clip_gc;
3566 if (door_state & DOOR_ACTION_1)
3568 int a = MIN(x * door_1.step_offset, end);
3569 int p = (door_state & DOOR_OPEN_1 ? end - a : a);
3570 int i = p + door_skip;
3572 if (door_1.anim_mode & ANIM_STATIC_PANEL)
3574 BlitBitmap(bitmap_db_door, drawto,
3575 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1,
3576 DXSIZE, DYSIZE, DX, DY);
3580 BlitBitmap(bitmap_db_door, drawto,
3581 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + p / 2,
3582 DXSIZE, DYSIZE - p / 2, DX, DY);
3584 ClearRectangle(drawto, DX, DY + DYSIZE - p / 2, DXSIZE, p / 2);
3587 if (door_1.anim_mode & ANIM_HORIZONTAL && x <= DXSIZE)
3589 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
3590 int dst1_x = DX + DXSIZE - i, dst1_y = DY;
3591 int src2_x = DXSIZE - i, src2_y = DOOR_GFX_PAGEY1;
3592 int dst2_x = DX, dst2_y = DY;
3593 int width = i, height = DYSIZE;
3595 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
3596 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
3599 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
3600 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
3603 else if (door_1.anim_mode & ANIM_VERTICAL && x <= DYSIZE)
3605 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
3606 int dst1_x = DX, dst1_y = DY + DYSIZE - i;
3607 int src2_x = 0, src2_y = DOOR_GFX_PAGEY1 + DYSIZE - i;
3608 int dst2_x = DX, dst2_y = DY;
3609 int width = DXSIZE, height = i;
3611 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
3612 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
3615 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
3616 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
3619 else if (x <= DXSIZE) /* ANIM_DEFAULT */
3621 int j = (door_1.anim_mode == ANIM_DEFAULT ? (DXSIZE - i) / 3 : 0);
3623 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
3624 BlitBitmapMasked(bitmap, drawto,
3625 DXSIZE, DOOR_GFX_PAGEY1, i, 77,
3626 DX + DXSIZE - i, DY + j);
3627 BlitBitmapMasked(bitmap, drawto,
3628 DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63,
3629 DX + DXSIZE - i, DY + 140 + j);
3630 SetClipOrigin(bitmap, gc, DX - DXSIZE + i,
3631 DY - (DOOR_GFX_PAGEY1 + j));
3632 BlitBitmapMasked(bitmap, drawto,
3633 DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j,
3635 BlitBitmapMasked(bitmap, drawto,
3636 DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63,
3639 BlitBitmapMasked(bitmap, drawto,
3640 DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
3642 BlitBitmapMasked(bitmap, drawto,
3643 DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
3645 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
3646 BlitBitmapMasked(bitmap, drawto,
3647 DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
3648 DX + DXSIZE - i, DY + 77 + j);
3649 BlitBitmapMasked(bitmap, drawto,
3650 DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
3651 DX + DXSIZE - i, DY + 203 + j);
3654 redraw_mask |= REDRAW_DOOR_1;
3655 door_1_done = (a == end);
3658 if (door_state & DOOR_ACTION_2)
3660 int a = MIN(x * door_2.step_offset, door_size);
3661 int p = (door_state & DOOR_OPEN_2 ? door_size - a : a);
3662 int i = p + door_skip;
3664 if (door_2.anim_mode & ANIM_STATIC_PANEL)
3666 BlitBitmap(bitmap_db_door, drawto,
3667 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2,
3668 VXSIZE, VYSIZE, VX, VY);
3670 else if (x <= VYSIZE)
3672 BlitBitmap(bitmap_db_door, drawto,
3673 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + p / 2,
3674 VXSIZE, VYSIZE - p / 2, VX, VY);
3676 ClearRectangle(drawto, VX, VY + VYSIZE - p / 2, VXSIZE, p / 2);
3679 if (door_2.anim_mode & ANIM_HORIZONTAL && x <= VXSIZE)
3681 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
3682 int dst1_x = VX + VXSIZE - i, dst1_y = VY;
3683 int src2_x = VXSIZE - i, src2_y = DOOR_GFX_PAGEY2;
3684 int dst2_x = VX, dst2_y = VY;
3685 int width = i, height = VYSIZE;
3687 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
3688 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
3691 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
3692 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
3695 else if (door_2.anim_mode & ANIM_VERTICAL && x <= VYSIZE)
3697 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
3698 int dst1_x = VX, dst1_y = VY + VYSIZE - i;
3699 int src2_x = 0, src2_y = DOOR_GFX_PAGEY2 + VYSIZE - i;
3700 int dst2_x = VX, dst2_y = VY;
3701 int width = VXSIZE, height = i;
3703 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
3704 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
3707 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
3708 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
3711 else if (x <= VXSIZE) /* ANIM_DEFAULT */
3713 int j = (door_2.anim_mode == ANIM_DEFAULT ? (VXSIZE - i) / 3 : 0);
3715 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
3716 BlitBitmapMasked(bitmap, drawto,
3717 VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2,
3718 VX + VXSIZE - i, VY + j);
3719 SetClipOrigin(bitmap, gc,
3720 VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
3721 BlitBitmapMasked(bitmap, drawto,
3722 VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j,
3725 BlitBitmapMasked(bitmap, drawto,
3726 VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2,
3727 i, VYSIZE / 2, VX, VY + VYSIZE / 2 - j);
3728 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
3729 BlitBitmapMasked(bitmap, drawto,
3730 VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2,
3732 VX + VXSIZE - i, VY + VYSIZE / 2 + j);
3735 redraw_mask |= REDRAW_DOOR_2;
3736 door_2_done = (a == VXSIZE);
3739 if (!(door_state & DOOR_NO_DELAY))
3743 if (game_status == GAME_MODE_MAIN)
3746 WaitUntilDelayReached(&door_delay, door_delay_value);
3751 if (door_state & DOOR_ACTION_1)
3752 door1 = door_state & DOOR_ACTION_1;
3753 if (door_state & DOOR_ACTION_2)
3754 door2 = door_state & DOOR_ACTION_2;
3756 return (door1 | door2);
3759 void DrawSpecialEditorDoor()
3761 /* draw bigger toolbox window */
3762 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
3763 DOOR_GFX_PAGEX7, 0, EXSIZE + 8, 8,
3765 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
3766 EX - 6, VY - 4, EXSIZE + 12, EYSIZE - VYSIZE + 4,
3769 redraw_mask |= REDRAW_ALL;
3772 void UndrawSpecialEditorDoor()
3774 /* draw normal tape recorder window */
3775 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
3776 EX - 6, EY - 12, EXSIZE + 12, EYSIZE - VYSIZE + 12,
3779 redraw_mask |= REDRAW_ALL;
3783 /* ---------- new tool button stuff ---------------------------------------- */
3785 /* graphic position values for tool buttons */
3786 #define TOOL_BUTTON_YES_XPOS 2
3787 #define TOOL_BUTTON_YES_YPOS 250
3788 #define TOOL_BUTTON_YES_GFX_YPOS 0
3789 #define TOOL_BUTTON_YES_XSIZE 46
3790 #define TOOL_BUTTON_YES_YSIZE 28
3791 #define TOOL_BUTTON_NO_XPOS 52
3792 #define TOOL_BUTTON_NO_YPOS TOOL_BUTTON_YES_YPOS
3793 #define TOOL_BUTTON_NO_GFX_YPOS TOOL_BUTTON_YES_GFX_YPOS
3794 #define TOOL_BUTTON_NO_XSIZE TOOL_BUTTON_YES_XSIZE
3795 #define TOOL_BUTTON_NO_YSIZE TOOL_BUTTON_YES_YSIZE
3796 #define TOOL_BUTTON_CONFIRM_XPOS TOOL_BUTTON_YES_XPOS
3797 #define TOOL_BUTTON_CONFIRM_YPOS TOOL_BUTTON_YES_YPOS
3798 #define TOOL_BUTTON_CONFIRM_GFX_YPOS 30
3799 #define TOOL_BUTTON_CONFIRM_XSIZE 96
3800 #define TOOL_BUTTON_CONFIRM_YSIZE TOOL_BUTTON_YES_YSIZE
3801 #define TOOL_BUTTON_PLAYER_XSIZE 30
3802 #define TOOL_BUTTON_PLAYER_YSIZE 30
3803 #define TOOL_BUTTON_PLAYER_GFX_XPOS 5
3804 #define TOOL_BUTTON_PLAYER_GFX_YPOS 185
3805 #define TOOL_BUTTON_PLAYER_XPOS (5 + TOOL_BUTTON_PLAYER_XSIZE / 2)
3806 #define TOOL_BUTTON_PLAYER_YPOS (215 - TOOL_BUTTON_PLAYER_YSIZE / 2)
3807 #define TOOL_BUTTON_PLAYER1_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3808 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
3809 #define TOOL_BUTTON_PLAYER2_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3810 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
3811 #define TOOL_BUTTON_PLAYER3_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3812 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
3813 #define TOOL_BUTTON_PLAYER4_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3814 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
3815 #define TOOL_BUTTON_PLAYER1_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3816 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
3817 #define TOOL_BUTTON_PLAYER2_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3818 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
3819 #define TOOL_BUTTON_PLAYER3_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3820 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
3821 #define TOOL_BUTTON_PLAYER4_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3822 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
3831 } toolbutton_info[NUM_TOOL_BUTTONS] =
3834 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_GFX_YPOS,
3835 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_YPOS,
3836 TOOL_BUTTON_YES_XSIZE, TOOL_BUTTON_YES_YSIZE,
3841 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_GFX_YPOS,
3842 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_YPOS,
3843 TOOL_BUTTON_NO_XSIZE, TOOL_BUTTON_NO_YSIZE,
3848 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_GFX_YPOS,
3849 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_YPOS,
3850 TOOL_BUTTON_CONFIRM_XSIZE, TOOL_BUTTON_CONFIRM_YSIZE,
3851 TOOL_CTRL_ID_CONFIRM,
3855 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3856 TOOL_BUTTON_PLAYER1_XPOS, TOOL_BUTTON_PLAYER1_YPOS,
3857 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3858 TOOL_CTRL_ID_PLAYER_1,
3862 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3863 TOOL_BUTTON_PLAYER2_XPOS, TOOL_BUTTON_PLAYER2_YPOS,
3864 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3865 TOOL_CTRL_ID_PLAYER_2,
3869 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3870 TOOL_BUTTON_PLAYER3_XPOS, TOOL_BUTTON_PLAYER3_YPOS,
3871 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3872 TOOL_CTRL_ID_PLAYER_3,
3876 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3877 TOOL_BUTTON_PLAYER4_XPOS, TOOL_BUTTON_PLAYER4_YPOS,
3878 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3879 TOOL_CTRL_ID_PLAYER_4,
3884 void CreateToolButtons()
3888 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3890 Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
3891 Bitmap *deco_bitmap = None;
3892 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
3893 struct GadgetInfo *gi;
3894 unsigned long event_mask;
3895 int gd_xoffset, gd_yoffset;
3896 int gd_x1, gd_x2, gd_y;
3899 event_mask = GD_EVENT_RELEASED;
3901 gd_xoffset = toolbutton_info[i].xpos;
3902 gd_yoffset = toolbutton_info[i].ypos;
3903 gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
3904 gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
3905 gd_y = DOOR_GFX_PAGEY1 + gd_yoffset;
3907 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
3909 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
3911 getMiniGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr),
3912 &deco_bitmap, &deco_x, &deco_y);
3913 deco_xpos = (toolbutton_info[i].width - MINI_TILEX) / 2;
3914 deco_ypos = (toolbutton_info[i].height - MINI_TILEY) / 2;
3917 gi = CreateGadget(GDI_CUSTOM_ID, id,
3918 GDI_INFO_TEXT, toolbutton_info[i].infotext,
3919 GDI_X, DX + toolbutton_info[i].x,
3920 GDI_Y, DY + toolbutton_info[i].y,
3921 GDI_WIDTH, toolbutton_info[i].width,
3922 GDI_HEIGHT, toolbutton_info[i].height,
3923 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
3924 GDI_STATE, GD_BUTTON_UNPRESSED,
3925 GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
3926 GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
3927 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
3928 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
3929 GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
3930 GDI_DECORATION_SHIFTING, 1, 1,
3931 GDI_DIRECT_DRAW, FALSE,
3932 GDI_EVENT_MASK, event_mask,
3933 GDI_CALLBACK_ACTION, HandleToolButtons,
3937 Error(ERR_EXIT, "cannot create gadget");
3939 tool_gadget[id] = gi;
3943 void FreeToolButtons()
3947 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3948 FreeGadget(tool_gadget[i]);
3951 static void UnmapToolButtons()
3955 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3956 UnmapGadget(tool_gadget[i]);
3959 static void HandleToolButtons(struct GadgetInfo *gi)
3961 request_gadget_id = gi->custom_id;
3964 static struct Mapping_EM_to_RND_object
3967 boolean is_rnd_to_em_mapping; /* unique mapping EM <-> RND */
3968 boolean is_backside; /* backside of moving element */
3974 em_object_mapping_list[] =
3977 Xblank, TRUE, FALSE,
3981 Yacid_splash_eB, FALSE, FALSE,
3982 EL_ACID_SPLASH_RIGHT, -1, -1
3985 Yacid_splash_wB, FALSE, FALSE,
3986 EL_ACID_SPLASH_LEFT, -1, -1
3989 #ifdef EM_ENGINE_BAD_ROLL
3991 Xstone_force_e, FALSE, FALSE,
3992 EL_ROCK, -1, MV_BIT_RIGHT
3995 Xstone_force_w, FALSE, FALSE,
3996 EL_ROCK, -1, MV_BIT_LEFT
3999 Xnut_force_e, FALSE, FALSE,
4000 EL_NUT, -1, MV_BIT_RIGHT
4003 Xnut_force_w, FALSE, FALSE,
4004 EL_NUT, -1, MV_BIT_LEFT
4007 Xspring_force_e, FALSE, FALSE,
4008 EL_SPRING, -1, MV_BIT_RIGHT
4011 Xspring_force_w, FALSE, FALSE,
4012 EL_SPRING, -1, MV_BIT_LEFT
4015 Xemerald_force_e, FALSE, FALSE,
4016 EL_EMERALD, -1, MV_BIT_RIGHT
4019 Xemerald_force_w, FALSE, FALSE,
4020 EL_EMERALD, -1, MV_BIT_LEFT
4023 Xdiamond_force_e, FALSE, FALSE,
4024 EL_DIAMOND, -1, MV_BIT_RIGHT
4027 Xdiamond_force_w, FALSE, FALSE,
4028 EL_DIAMOND, -1, MV_BIT_LEFT
4031 Xbomb_force_e, FALSE, FALSE,
4032 EL_BOMB, -1, MV_BIT_RIGHT
4035 Xbomb_force_w, FALSE, FALSE,
4036 EL_BOMB, -1, MV_BIT_LEFT
4038 #endif /* EM_ENGINE_BAD_ROLL */
4041 Xstone, TRUE, FALSE,
4045 Xstone_pause, FALSE, FALSE,
4049 Xstone_fall, FALSE, FALSE,
4053 Ystone_s, FALSE, FALSE,
4054 EL_ROCK, ACTION_FALLING, -1
4057 Ystone_sB, FALSE, TRUE,
4058 EL_ROCK, ACTION_FALLING, -1
4061 Ystone_e, FALSE, FALSE,
4062 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
4065 Ystone_eB, FALSE, TRUE,
4066 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
4069 Ystone_w, FALSE, FALSE,
4070 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
4073 Ystone_wB, FALSE, TRUE,
4074 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
4081 Xnut_pause, FALSE, FALSE,
4085 Xnut_fall, FALSE, FALSE,
4089 Ynut_s, FALSE, FALSE,
4090 EL_NUT, ACTION_FALLING, -1
4093 Ynut_sB, FALSE, TRUE,
4094 EL_NUT, ACTION_FALLING, -1
4097 Ynut_e, FALSE, FALSE,
4098 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
4101 Ynut_eB, FALSE, TRUE,
4102 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
4105 Ynut_w, FALSE, FALSE,
4106 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
4109 Ynut_wB, FALSE, TRUE,
4110 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
4113 Xbug_n, TRUE, FALSE,
4117 Xbug_e, TRUE, FALSE,
4118 EL_BUG_RIGHT, -1, -1
4121 Xbug_s, TRUE, FALSE,
4125 Xbug_w, TRUE, FALSE,
4129 Xbug_gon, FALSE, FALSE,
4133 Xbug_goe, FALSE, FALSE,
4134 EL_BUG_RIGHT, -1, -1
4137 Xbug_gos, FALSE, FALSE,
4141 Xbug_gow, FALSE, FALSE,
4145 Ybug_n, FALSE, FALSE,
4146 EL_BUG, ACTION_MOVING, MV_BIT_UP
4149 Ybug_nB, FALSE, TRUE,
4150 EL_BUG, ACTION_MOVING, MV_BIT_UP
4153 Ybug_e, FALSE, FALSE,
4154 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
4157 Ybug_eB, FALSE, TRUE,
4158 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
4161 Ybug_s, FALSE, FALSE,
4162 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
4165 Ybug_sB, FALSE, TRUE,
4166 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
4169 Ybug_w, FALSE, FALSE,
4170 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
4173 Ybug_wB, FALSE, TRUE,
4174 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
4177 Ybug_w_n, FALSE, FALSE,
4178 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
4181 Ybug_n_e, FALSE, FALSE,
4182 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
4185 Ybug_e_s, FALSE, FALSE,
4186 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
4189 Ybug_s_w, FALSE, FALSE,
4190 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
4193 Ybug_e_n, FALSE, FALSE,
4194 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
4197 Ybug_s_e, FALSE, FALSE,
4198 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
4201 Ybug_w_s, FALSE, FALSE,
4202 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
4205 Ybug_n_w, FALSE, FALSE,
4206 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
4209 Ybug_stone, FALSE, FALSE,
4210 EL_BUG, ACTION_SMASHED_BY_ROCK, -1
4213 Ybug_spring, FALSE, FALSE,
4214 EL_BUG, ACTION_SMASHED_BY_SPRING, -1
4217 Xtank_n, TRUE, FALSE,
4218 EL_SPACESHIP_UP, -1, -1
4221 Xtank_e, TRUE, FALSE,
4222 EL_SPACESHIP_RIGHT, -1, -1
4225 Xtank_s, TRUE, FALSE,
4226 EL_SPACESHIP_DOWN, -1, -1
4229 Xtank_w, TRUE, FALSE,
4230 EL_SPACESHIP_LEFT, -1, -1
4233 Xtank_gon, FALSE, FALSE,
4234 EL_SPACESHIP_UP, -1, -1
4237 Xtank_goe, FALSE, FALSE,
4238 EL_SPACESHIP_RIGHT, -1, -1
4241 Xtank_gos, FALSE, FALSE,
4242 EL_SPACESHIP_DOWN, -1, -1
4245 Xtank_gow, FALSE, FALSE,
4246 EL_SPACESHIP_LEFT, -1, -1
4249 Ytank_n, FALSE, FALSE,
4250 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
4253 Ytank_nB, FALSE, TRUE,
4254 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
4257 Ytank_e, FALSE, FALSE,
4258 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
4261 Ytank_eB, FALSE, TRUE,
4262 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
4265 Ytank_s, FALSE, FALSE,
4266 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
4269 Ytank_sB, FALSE, TRUE,
4270 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
4273 Ytank_w, FALSE, FALSE,
4274 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
4277 Ytank_wB, FALSE, TRUE,
4278 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
4281 Ytank_w_n, FALSE, FALSE,
4282 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
4285 Ytank_n_e, FALSE, FALSE,
4286 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
4289 Ytank_e_s, FALSE, FALSE,
4290 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
4293 Ytank_s_w, FALSE, FALSE,
4294 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
4297 Ytank_e_n, FALSE, FALSE,
4298 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
4301 Ytank_s_e, FALSE, FALSE,
4302 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
4305 Ytank_w_s, FALSE, FALSE,
4306 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
4309 Ytank_n_w, FALSE, FALSE,
4310 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
4313 Ytank_stone, FALSE, FALSE,
4314 EL_SPACESHIP, ACTION_SMASHED_BY_ROCK, -1
4317 Ytank_spring, FALSE, FALSE,
4318 EL_SPACESHIP, ACTION_SMASHED_BY_SPRING, -1
4321 Xandroid, TRUE, FALSE,
4322 EL_EMC_ANDROID, ACTION_ACTIVE, -1
4325 Xandroid_1_n, FALSE, FALSE,
4326 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
4329 Xandroid_2_n, FALSE, FALSE,
4330 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
4333 Xandroid_1_e, FALSE, FALSE,
4334 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
4337 Xandroid_2_e, FALSE, FALSE,
4338 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
4341 Xandroid_1_w, FALSE, FALSE,
4342 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
4345 Xandroid_2_w, FALSE, FALSE,
4346 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
4349 Xandroid_1_s, FALSE, FALSE,
4350 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
4353 Xandroid_2_s, FALSE, FALSE,
4354 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
4357 Yandroid_n, FALSE, FALSE,
4358 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
4361 Yandroid_nB, FALSE, TRUE,
4362 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
4365 Yandroid_ne, FALSE, FALSE,
4366 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPRIGHT
4369 Yandroid_neB, FALSE, TRUE,
4370 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPRIGHT
4373 Yandroid_e, FALSE, FALSE,
4374 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
4377 Yandroid_eB, FALSE, TRUE,
4378 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
4381 Yandroid_se, FALSE, FALSE,
4382 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNRIGHT
4385 Yandroid_seB, FALSE, TRUE,
4386 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNRIGHT
4389 Yandroid_s, FALSE, FALSE,
4390 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
4393 Yandroid_sB, FALSE, TRUE,
4394 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
4397 Yandroid_sw, FALSE, FALSE,
4398 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNLEFT
4401 Yandroid_swB, FALSE, TRUE,
4402 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNLEFT
4405 Yandroid_w, FALSE, FALSE,
4406 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
4409 Yandroid_wB, FALSE, TRUE,
4410 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
4413 Yandroid_nw, FALSE, FALSE,
4414 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPLEFT
4417 Yandroid_nwB, FALSE, TRUE,
4418 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPLEFT
4421 Xspring, TRUE, FALSE,
4425 Xspring_pause, FALSE, FALSE,
4429 Xspring_e, FALSE, FALSE,
4433 Xspring_w, FALSE, FALSE,
4437 Xspring_fall, FALSE, FALSE,
4441 Yspring_s, FALSE, FALSE,
4442 EL_SPRING, ACTION_FALLING, -1
4445 Yspring_sB, FALSE, TRUE,
4446 EL_SPRING, ACTION_FALLING, -1
4449 Yspring_e, FALSE, FALSE,
4450 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
4453 Yspring_eB, FALSE, TRUE,
4454 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
4457 Yspring_w, FALSE, FALSE,
4458 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
4461 Yspring_wB, FALSE, TRUE,
4462 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
4465 Yspring_kill_e, FALSE, FALSE,
4466 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
4469 Yspring_kill_eB, FALSE, TRUE,
4470 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
4473 Yspring_kill_w, FALSE, FALSE,
4474 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
4477 Yspring_kill_wB, FALSE, TRUE,
4478 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
4481 Xeater_n, TRUE, FALSE,
4482 EL_YAMYAM_UP, -1, -1
4485 Xeater_e, TRUE, FALSE,
4486 EL_YAMYAM_RIGHT, -1, -1
4489 Xeater_w, TRUE, FALSE,
4490 EL_YAMYAM_LEFT, -1, -1
4493 Xeater_s, TRUE, FALSE,
4494 EL_YAMYAM_DOWN, -1, -1
4497 Yeater_n, FALSE, FALSE,
4498 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
4501 Yeater_nB, FALSE, TRUE,
4502 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
4505 Yeater_e, FALSE, FALSE,
4506 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
4509 Yeater_eB, FALSE, TRUE,
4510 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
4513 Yeater_s, FALSE, FALSE,
4514 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
4517 Yeater_sB, FALSE, TRUE,
4518 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
4521 Yeater_w, FALSE, FALSE,
4522 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
4525 Yeater_wB, FALSE, TRUE,
4526 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
4529 Yeater_stone, FALSE, FALSE,
4530 EL_YAMYAM, ACTION_SMASHED_BY_ROCK, -1
4533 Yeater_spring, FALSE, FALSE,
4534 EL_YAMYAM, ACTION_SMASHED_BY_SPRING, -1
4537 Xalien, TRUE, FALSE,
4541 Xalien_pause, FALSE, FALSE,
4545 Yalien_n, FALSE, FALSE,
4546 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
4549 Yalien_nB, FALSE, TRUE,
4550 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
4553 Yalien_e, FALSE, FALSE,
4554 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
4557 Yalien_eB, FALSE, TRUE,
4558 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
4561 Yalien_s, FALSE, FALSE,
4562 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
4565 Yalien_sB, FALSE, TRUE,
4566 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
4569 Yalien_w, FALSE, FALSE,
4570 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
4573 Yalien_wB, FALSE, TRUE,
4574 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
4577 Yalien_stone, FALSE, FALSE,
4578 EL_ROBOT, ACTION_SMASHED_BY_ROCK, -1
4581 Yalien_spring, FALSE, FALSE,
4582 EL_ROBOT, ACTION_SMASHED_BY_SPRING, -1
4585 Xemerald, TRUE, FALSE,
4589 Xemerald_pause, FALSE, FALSE,
4593 Xemerald_fall, FALSE, FALSE,
4597 Xemerald_shine, FALSE, FALSE,
4598 EL_EMERALD, ACTION_TWINKLING, -1
4601 Yemerald_s, FALSE, FALSE,
4602 EL_EMERALD, ACTION_FALLING, -1
4605 Yemerald_sB, FALSE, TRUE,
4606 EL_EMERALD, ACTION_FALLING, -1
4609 Yemerald_e, FALSE, FALSE,
4610 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
4613 Yemerald_eB, FALSE, TRUE,
4614 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
4617 Yemerald_w, FALSE, FALSE,
4618 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
4621 Yemerald_wB, FALSE, TRUE,
4622 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
4625 Yemerald_eat, FALSE, FALSE,
4626 EL_EMERALD, ACTION_COLLECTING, -1
4629 Yemerald_stone, FALSE, FALSE,
4630 EL_NUT, ACTION_BREAKING, -1
4633 Xdiamond, TRUE, FALSE,
4637 Xdiamond_pause, FALSE, FALSE,
4641 Xdiamond_fall, FALSE, FALSE,
4645 Xdiamond_shine, FALSE, FALSE,
4646 EL_DIAMOND, ACTION_TWINKLING, -1
4649 Ydiamond_s, FALSE, FALSE,
4650 EL_DIAMOND, ACTION_FALLING, -1
4653 Ydiamond_sB, FALSE, TRUE,
4654 EL_DIAMOND, ACTION_FALLING, -1
4657 Ydiamond_e, FALSE, FALSE,
4658 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
4661 Ydiamond_eB, FALSE, TRUE,
4662 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
4665 Ydiamond_w, FALSE, FALSE,
4666 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
4669 Ydiamond_wB, FALSE, TRUE,
4670 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
4673 Ydiamond_eat, FALSE, FALSE,
4674 EL_DIAMOND, ACTION_COLLECTING, -1
4677 Ydiamond_stone, FALSE, FALSE,
4678 EL_DIAMOND, ACTION_SMASHED_BY_ROCK, -1
4681 Xdrip_fall, TRUE, FALSE,
4682 EL_AMOEBA_DROP, -1, -1
4685 Xdrip_stretch, FALSE, FALSE,
4686 EL_AMOEBA_DROP, ACTION_FALLING, -1
4689 Xdrip_stretchB, FALSE, TRUE,
4690 EL_AMOEBA_DROP, ACTION_FALLING, -1
4693 Xdrip_eat, FALSE, FALSE,
4694 EL_AMOEBA_DROP, ACTION_GROWING, -1
4697 Ydrip_s1, FALSE, FALSE,
4698 EL_AMOEBA_DROP, ACTION_FALLING, -1
4701 Ydrip_s1B, FALSE, TRUE,
4702 EL_AMOEBA_DROP, ACTION_FALLING, -1
4705 Ydrip_s2, FALSE, FALSE,
4706 EL_AMOEBA_DROP, ACTION_FALLING, -1
4709 Ydrip_s2B, FALSE, TRUE,
4710 EL_AMOEBA_DROP, ACTION_FALLING, -1
4717 Xbomb_pause, FALSE, FALSE,
4721 Xbomb_fall, FALSE, FALSE,
4725 Ybomb_s, FALSE, FALSE,
4726 EL_BOMB, ACTION_FALLING, -1
4729 Ybomb_sB, FALSE, TRUE,
4730 EL_BOMB, ACTION_FALLING, -1
4733 Ybomb_e, FALSE, FALSE,
4734 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
4737 Ybomb_eB, FALSE, TRUE,
4738 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
4741 Ybomb_w, FALSE, FALSE,
4742 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
4745 Ybomb_wB, FALSE, TRUE,
4746 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
4749 Ybomb_eat, FALSE, FALSE,
4750 EL_BOMB, ACTION_ACTIVATING, -1
4753 Xballoon, TRUE, FALSE,
4757 Yballoon_n, FALSE, FALSE,
4758 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
4761 Yballoon_nB, FALSE, TRUE,
4762 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
4765 Yballoon_e, FALSE, FALSE,
4766 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
4769 Yballoon_eB, FALSE, TRUE,
4770 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
4773 Yballoon_s, FALSE, FALSE,
4774 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
4777 Yballoon_sB, FALSE, TRUE,
4778 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
4781 Yballoon_w, FALSE, FALSE,
4782 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
4785 Yballoon_wB, FALSE, TRUE,
4786 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
4789 Xgrass, TRUE, FALSE,
4790 EL_EMC_GRASS, -1, -1
4793 Ygrass_nB, FALSE, FALSE,
4794 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_UP
4797 Ygrass_eB, FALSE, FALSE,
4798 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_RIGHT
4801 Ygrass_sB, FALSE, FALSE,
4802 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_DOWN
4805 Ygrass_wB, FALSE, FALSE,
4806 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_LEFT
4813 Ydirt_nB, FALSE, FALSE,
4814 EL_SAND, ACTION_DIGGING, MV_BIT_UP
4817 Ydirt_eB, FALSE, FALSE,
4818 EL_SAND, ACTION_DIGGING, MV_BIT_RIGHT
4821 Ydirt_sB, FALSE, FALSE,
4822 EL_SAND, ACTION_DIGGING, MV_BIT_DOWN
4825 Ydirt_wB, FALSE, FALSE,
4826 EL_SAND, ACTION_DIGGING, MV_BIT_LEFT
4829 Xacid_ne, TRUE, FALSE,
4830 EL_ACID_POOL_TOPRIGHT, -1, -1
4833 Xacid_se, TRUE, FALSE,
4834 EL_ACID_POOL_BOTTOMRIGHT, -1, -1
4837 Xacid_s, TRUE, FALSE,
4838 EL_ACID_POOL_BOTTOM, -1, -1
4841 Xacid_sw, TRUE, FALSE,
4842 EL_ACID_POOL_BOTTOMLEFT, -1, -1
4845 Xacid_nw, TRUE, FALSE,
4846 EL_ACID_POOL_TOPLEFT, -1, -1
4849 Xacid_1, TRUE, FALSE,
4853 Xacid_2, FALSE, FALSE,
4857 Xacid_3, FALSE, FALSE,
4861 Xacid_4, FALSE, FALSE,
4865 Xacid_5, FALSE, FALSE,
4869 Xacid_6, FALSE, FALSE,
4873 Xacid_7, FALSE, FALSE,
4877 Xacid_8, FALSE, FALSE,
4881 Xball_1, TRUE, FALSE,
4882 EL_EMC_MAGIC_BALL, -1, -1
4885 Xball_1B, FALSE, FALSE,
4886 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
4889 Xball_2, FALSE, FALSE,
4890 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
4893 Xball_2B, FALSE, FALSE,
4894 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
4897 Yball_eat, FALSE, FALSE,
4898 EL_EMC_MAGIC_BALL, ACTION_DROPPING, -1
4901 Ykey_1_eat, FALSE, FALSE,
4902 EL_EM_KEY_1, ACTION_COLLECTING, -1
4905 Ykey_2_eat, FALSE, FALSE,
4906 EL_EM_KEY_2, ACTION_COLLECTING, -1
4909 Ykey_3_eat, FALSE, FALSE,
4910 EL_EM_KEY_3, ACTION_COLLECTING, -1
4913 Ykey_4_eat, FALSE, FALSE,
4914 EL_EM_KEY_4, ACTION_COLLECTING, -1
4917 Ykey_5_eat, FALSE, FALSE,
4918 EL_EMC_KEY_5, ACTION_COLLECTING, -1
4921 Ykey_6_eat, FALSE, FALSE,
4922 EL_EMC_KEY_6, ACTION_COLLECTING, -1
4925 Ykey_7_eat, FALSE, FALSE,
4926 EL_EMC_KEY_7, ACTION_COLLECTING, -1
4929 Ykey_8_eat, FALSE, FALSE,
4930 EL_EMC_KEY_8, ACTION_COLLECTING, -1
4933 Ylenses_eat, FALSE, FALSE,
4934 EL_EMC_LENSES, ACTION_COLLECTING, -1
4937 Ymagnify_eat, FALSE, FALSE,
4938 EL_EMC_MAGNIFIER, ACTION_COLLECTING, -1
4941 Ygrass_eat, FALSE, FALSE,
4942 EL_EMC_GRASS, ACTION_SNAPPING, -1
4945 Ydirt_eat, FALSE, FALSE,
4946 EL_SAND, ACTION_SNAPPING, -1
4949 Xgrow_ns, TRUE, FALSE,
4950 EL_EXPANDABLE_WALL_VERTICAL, -1, -1
4953 Ygrow_ns_eat, FALSE, FALSE,
4954 EL_EXPANDABLE_WALL_VERTICAL, ACTION_GROWING, -1
4957 Xgrow_ew, TRUE, FALSE,
4958 EL_EXPANDABLE_WALL_HORIZONTAL, -1, -1
4961 Ygrow_ew_eat, FALSE, FALSE,
4962 EL_EXPANDABLE_WALL_HORIZONTAL, ACTION_GROWING, -1
4965 Xwonderwall, TRUE, FALSE,
4966 EL_MAGIC_WALL, -1, -1
4969 XwonderwallB, FALSE, FALSE,
4970 EL_MAGIC_WALL, ACTION_ACTIVE, -1
4973 Xamoeba_1, TRUE, FALSE,
4974 EL_AMOEBA_DRY, ACTION_OTHER, -1
4977 Xamoeba_2, FALSE, FALSE,
4978 EL_AMOEBA_DRY, ACTION_OTHER, -1
4981 Xamoeba_3, FALSE, FALSE,
4982 EL_AMOEBA_DRY, ACTION_OTHER, -1
4985 Xamoeba_4, FALSE, FALSE,
4986 EL_AMOEBA_DRY, ACTION_OTHER, -1
4989 Xamoeba_5, TRUE, FALSE,
4990 EL_AMOEBA_WET, ACTION_OTHER, -1
4993 Xamoeba_6, FALSE, FALSE,
4994 EL_AMOEBA_WET, ACTION_OTHER, -1
4997 Xamoeba_7, FALSE, FALSE,
4998 EL_AMOEBA_WET, ACTION_OTHER, -1
5001 Xamoeba_8, FALSE, FALSE,
5002 EL_AMOEBA_WET, ACTION_OTHER, -1
5005 Xdoor_1, TRUE, FALSE,
5006 EL_EM_GATE_1, -1, -1
5009 Xdoor_2, TRUE, FALSE,
5010 EL_EM_GATE_2, -1, -1
5013 Xdoor_3, TRUE, FALSE,
5014 EL_EM_GATE_3, -1, -1
5017 Xdoor_4, TRUE, FALSE,
5018 EL_EM_GATE_4, -1, -1
5021 Xdoor_5, TRUE, FALSE,
5022 EL_EMC_GATE_5, -1, -1
5025 Xdoor_6, TRUE, FALSE,
5026 EL_EMC_GATE_6, -1, -1
5029 Xdoor_7, TRUE, FALSE,
5030 EL_EMC_GATE_7, -1, -1
5033 Xdoor_8, TRUE, FALSE,
5034 EL_EMC_GATE_8, -1, -1
5037 Xkey_1, TRUE, FALSE,
5041 Xkey_2, TRUE, FALSE,
5045 Xkey_3, TRUE, FALSE,
5049 Xkey_4, TRUE, FALSE,
5053 Xkey_5, TRUE, FALSE,
5054 EL_EMC_KEY_5, -1, -1
5057 Xkey_6, TRUE, FALSE,
5058 EL_EMC_KEY_6, -1, -1
5061 Xkey_7, TRUE, FALSE,
5062 EL_EMC_KEY_7, -1, -1
5065 Xkey_8, TRUE, FALSE,
5066 EL_EMC_KEY_8, -1, -1
5069 Xwind_n, TRUE, FALSE,
5070 EL_BALLOON_SWITCH_UP, -1, -1
5073 Xwind_e, TRUE, FALSE,
5074 EL_BALLOON_SWITCH_RIGHT, -1, -1
5077 Xwind_s, TRUE, FALSE,
5078 EL_BALLOON_SWITCH_DOWN, -1, -1
5081 Xwind_w, TRUE, FALSE,
5082 EL_BALLOON_SWITCH_LEFT, -1, -1
5085 Xwind_nesw, TRUE, FALSE,
5086 EL_BALLOON_SWITCH_ANY, -1, -1
5089 Xwind_stop, TRUE, FALSE,
5090 EL_BALLOON_SWITCH_NONE, -1, -1
5094 EL_EM_EXIT_CLOSED, -1, -1
5097 Xexit_1, TRUE, FALSE,
5098 EL_EM_EXIT_OPEN, -1, -1
5101 Xexit_2, FALSE, FALSE,
5102 EL_EM_EXIT_OPEN, -1, -1
5105 Xexit_3, FALSE, FALSE,
5106 EL_EM_EXIT_OPEN, -1, -1
5109 Xdynamite, TRUE, FALSE,
5110 EL_EM_DYNAMITE, -1, -1
5113 Ydynamite_eat, FALSE, FALSE,
5114 EL_EM_DYNAMITE, ACTION_COLLECTING, -1
5117 Xdynamite_1, TRUE, FALSE,
5118 EL_EM_DYNAMITE_ACTIVE, -1, -1
5121 Xdynamite_2, FALSE, FALSE,
5122 EL_EM_DYNAMITE_ACTIVE, -1, -1
5125 Xdynamite_3, FALSE, FALSE,
5126 EL_EM_DYNAMITE_ACTIVE, -1, -1
5129 Xdynamite_4, FALSE, FALSE,
5130 EL_EM_DYNAMITE_ACTIVE, -1, -1
5133 Xbumper, TRUE, FALSE,
5134 EL_EMC_SPRING_BUMPER, -1, -1
5137 XbumperB, FALSE, FALSE,
5138 EL_EMC_SPRING_BUMPER, ACTION_ACTIVE, -1
5141 Xwheel, TRUE, FALSE,
5142 EL_ROBOT_WHEEL, -1, -1
5145 XwheelB, FALSE, FALSE,
5146 EL_ROBOT_WHEEL, ACTION_ACTIVE, -1
5149 Xswitch, TRUE, FALSE,
5150 EL_EMC_MAGIC_BALL_SWITCH, -1, -1
5153 XswitchB, FALSE, FALSE,
5154 EL_EMC_MAGIC_BALL_SWITCH, ACTION_ACTIVE, -1
5158 EL_QUICKSAND_EMPTY, -1, -1
5161 Xsand_stone, TRUE, FALSE,
5162 EL_QUICKSAND_FULL, -1, -1
5165 Xsand_stonein_1, FALSE, TRUE,
5166 EL_ROCK, ACTION_FILLING, -1
5169 Xsand_stonein_2, FALSE, TRUE,
5170 EL_ROCK, ACTION_FILLING, -1
5173 Xsand_stonein_3, FALSE, TRUE,
5174 EL_ROCK, ACTION_FILLING, -1
5177 Xsand_stonein_4, FALSE, TRUE,
5178 EL_ROCK, ACTION_FILLING, -1
5182 Xsand_stonesand_1, FALSE, FALSE,
5183 EL_QUICKSAND_EMPTYING, -1, -1
5186 Xsand_stonesand_2, FALSE, FALSE,
5187 EL_QUICKSAND_EMPTYING, -1, -1
5190 Xsand_stonesand_3, FALSE, FALSE,
5191 EL_QUICKSAND_EMPTYING, -1, -1
5194 Xsand_stonesand_4, FALSE, FALSE,
5195 EL_QUICKSAND_EMPTYING, -1, -1
5198 Xsand_stonesand_quickout_1, FALSE, FALSE,
5199 EL_QUICKSAND_EMPTYING, -1, -1
5202 Xsand_stonesand_quickout_2, FALSE, FALSE,
5203 EL_QUICKSAND_EMPTYING, -1, -1
5207 Xsand_stonesand_1, FALSE, FALSE,
5208 EL_QUICKSAND_FULL, -1, -1
5211 Xsand_stonesand_2, FALSE, FALSE,
5212 EL_QUICKSAND_FULL, -1, -1
5215 Xsand_stonesand_3, FALSE, FALSE,
5216 EL_QUICKSAND_FULL, -1, -1
5219 Xsand_stonesand_4, FALSE, FALSE,
5220 EL_QUICKSAND_FULL, -1, -1
5224 Xsand_stoneout_1, FALSE, FALSE,
5225 EL_ROCK, ACTION_EMPTYING, -1
5228 Xsand_stoneout_2, FALSE, FALSE,
5229 EL_ROCK, ACTION_EMPTYING, -1
5233 Xsand_sandstone_1, FALSE, FALSE,
5234 EL_QUICKSAND_FILLING, -1, -1
5237 Xsand_sandstone_2, FALSE, FALSE,
5238 EL_QUICKSAND_FILLING, -1, -1
5241 Xsand_sandstone_3, FALSE, FALSE,
5242 EL_QUICKSAND_FILLING, -1, -1
5245 Xsand_sandstone_4, FALSE, FALSE,
5246 EL_QUICKSAND_FILLING, -1, -1
5250 Xsand_sandstone_1, FALSE, FALSE,
5251 EL_QUICKSAND_FULL, -1, -1
5254 Xsand_sandstone_2, FALSE, FALSE,
5255 EL_QUICKSAND_FULL, -1, -1
5258 Xsand_sandstone_3, FALSE, FALSE,
5259 EL_QUICKSAND_FULL, -1, -1
5262 Xsand_sandstone_4, FALSE, FALSE,
5263 EL_QUICKSAND_FULL, -1, -1
5267 Xplant, TRUE, FALSE,
5268 EL_EMC_PLANT, -1, -1
5271 Yplant, FALSE, FALSE,
5272 EL_EMC_PLANT, -1, -1
5275 Xlenses, TRUE, FALSE,
5276 EL_EMC_LENSES, -1, -1
5279 Xmagnify, TRUE, FALSE,
5280 EL_EMC_MAGNIFIER, -1, -1
5283 Xdripper, TRUE, FALSE,
5284 EL_EMC_DRIPPER, -1, -1
5287 XdripperB, FALSE, FALSE,
5288 EL_EMC_DRIPPER, ACTION_ACTIVE, -1
5291 Xfake_blank, TRUE, FALSE,
5292 EL_INVISIBLE_WALL, -1, -1
5295 Xfake_blankB, FALSE, FALSE,
5296 EL_INVISIBLE_WALL, ACTION_ACTIVE, -1
5299 Xfake_grass, TRUE, FALSE,
5300 EL_EMC_FAKE_GRASS, -1, -1
5303 Xfake_grassB, FALSE, FALSE,
5304 EL_EMC_FAKE_GRASS, ACTION_ACTIVE, -1
5307 Xfake_door_1, TRUE, FALSE,
5308 EL_EM_GATE_1_GRAY, -1, -1
5311 Xfake_door_2, TRUE, FALSE,
5312 EL_EM_GATE_2_GRAY, -1, -1
5315 Xfake_door_3, TRUE, FALSE,
5316 EL_EM_GATE_3_GRAY, -1, -1
5319 Xfake_door_4, TRUE, FALSE,
5320 EL_EM_GATE_4_GRAY, -1, -1
5323 Xfake_door_5, TRUE, FALSE,
5324 EL_EMC_GATE_5_GRAY, -1, -1
5327 Xfake_door_6, TRUE, FALSE,
5328 EL_EMC_GATE_6_GRAY, -1, -1
5331 Xfake_door_7, TRUE, FALSE,
5332 EL_EMC_GATE_7_GRAY, -1, -1
5335 Xfake_door_8, TRUE, FALSE,
5336 EL_EMC_GATE_8_GRAY, -1, -1
5339 Xfake_acid_1, TRUE, FALSE,
5340 EL_EMC_FAKE_ACID, -1, -1
5343 Xfake_acid_2, FALSE, FALSE,
5344 EL_EMC_FAKE_ACID, -1, -1
5347 Xfake_acid_3, FALSE, FALSE,
5348 EL_EMC_FAKE_ACID, -1, -1
5351 Xfake_acid_4, FALSE, FALSE,
5352 EL_EMC_FAKE_ACID, -1, -1
5355 Xfake_acid_5, FALSE, FALSE,
5356 EL_EMC_FAKE_ACID, -1, -1
5359 Xfake_acid_6, FALSE, FALSE,
5360 EL_EMC_FAKE_ACID, -1, -1
5363 Xfake_acid_7, FALSE, FALSE,
5364 EL_EMC_FAKE_ACID, -1, -1
5367 Xfake_acid_8, FALSE, FALSE,
5368 EL_EMC_FAKE_ACID, -1, -1
5371 Xsteel_1, TRUE, FALSE,
5372 EL_STEELWALL, -1, -1
5375 Xsteel_2, TRUE, FALSE,
5376 EL_EMC_STEELWALL_2, -1, -1
5379 Xsteel_3, TRUE, FALSE,
5380 EL_EMC_STEELWALL_3, -1, -1
5383 Xsteel_4, TRUE, FALSE,
5384 EL_EMC_STEELWALL_4, -1, -1
5387 Xwall_1, TRUE, FALSE,
5391 Xwall_2, TRUE, FALSE,
5392 EL_EMC_WALL_14, -1, -1
5395 Xwall_3, TRUE, FALSE,
5396 EL_EMC_WALL_15, -1, -1
5399 Xwall_4, TRUE, FALSE,
5400 EL_EMC_WALL_16, -1, -1
5403 Xround_wall_1, TRUE, FALSE,
5404 EL_WALL_SLIPPERY, -1, -1
5407 Xround_wall_2, TRUE, FALSE,
5408 EL_EMC_WALL_SLIPPERY_2, -1, -1
5411 Xround_wall_3, TRUE, FALSE,
5412 EL_EMC_WALL_SLIPPERY_3, -1, -1
5415 Xround_wall_4, TRUE, FALSE,
5416 EL_EMC_WALL_SLIPPERY_4, -1, -1
5419 Xdecor_1, TRUE, FALSE,
5420 EL_EMC_WALL_8, -1, -1
5423 Xdecor_2, TRUE, FALSE,
5424 EL_EMC_WALL_6, -1, -1
5427 Xdecor_3, TRUE, FALSE,
5428 EL_EMC_WALL_4, -1, -1
5431 Xdecor_4, TRUE, FALSE,
5432 EL_EMC_WALL_7, -1, -1
5435 Xdecor_5, TRUE, FALSE,
5436 EL_EMC_WALL_5, -1, -1
5439 Xdecor_6, TRUE, FALSE,
5440 EL_EMC_WALL_9, -1, -1
5443 Xdecor_7, TRUE, FALSE,
5444 EL_EMC_WALL_10, -1, -1
5447 Xdecor_8, TRUE, FALSE,
5448 EL_EMC_WALL_1, -1, -1
5451 Xdecor_9, TRUE, FALSE,
5452 EL_EMC_WALL_2, -1, -1
5455 Xdecor_10, TRUE, FALSE,
5456 EL_EMC_WALL_3, -1, -1
5459 Xdecor_11, TRUE, FALSE,
5460 EL_EMC_WALL_11, -1, -1
5463 Xdecor_12, TRUE, FALSE,
5464 EL_EMC_WALL_12, -1, -1
5467 Xalpha_0, TRUE, FALSE,
5468 EL_CHAR('0'), -1, -1
5471 Xalpha_1, TRUE, FALSE,
5472 EL_CHAR('1'), -1, -1
5475 Xalpha_2, TRUE, FALSE,
5476 EL_CHAR('2'), -1, -1
5479 Xalpha_3, TRUE, FALSE,
5480 EL_CHAR('3'), -1, -1
5483 Xalpha_4, TRUE, FALSE,
5484 EL_CHAR('4'), -1, -1
5487 Xalpha_5, TRUE, FALSE,
5488 EL_CHAR('5'), -1, -1
5491 Xalpha_6, TRUE, FALSE,
5492 EL_CHAR('6'), -1, -1
5495 Xalpha_7, TRUE, FALSE,
5496 EL_CHAR('7'), -1, -1
5499 Xalpha_8, TRUE, FALSE,
5500 EL_CHAR('8'), -1, -1
5503 Xalpha_9, TRUE, FALSE,
5504 EL_CHAR('9'), -1, -1
5507 Xalpha_excla, TRUE, FALSE,
5508 EL_CHAR('!'), -1, -1
5511 Xalpha_quote, TRUE, FALSE,
5512 EL_CHAR('"'), -1, -1
5515 Xalpha_comma, TRUE, FALSE,
5516 EL_CHAR(','), -1, -1
5519 Xalpha_minus, TRUE, FALSE,
5520 EL_CHAR('-'), -1, -1
5523 Xalpha_perio, TRUE, FALSE,
5524 EL_CHAR('.'), -1, -1
5527 Xalpha_colon, TRUE, FALSE,
5528 EL_CHAR(':'), -1, -1
5531 Xalpha_quest, TRUE, FALSE,
5532 EL_CHAR('?'), -1, -1
5535 Xalpha_a, TRUE, FALSE,
5536 EL_CHAR('A'), -1, -1
5539 Xalpha_b, TRUE, FALSE,
5540 EL_CHAR('B'), -1, -1
5543 Xalpha_c, TRUE, FALSE,
5544 EL_CHAR('C'), -1, -1
5547 Xalpha_d, TRUE, FALSE,
5548 EL_CHAR('D'), -1, -1
5551 Xalpha_e, TRUE, FALSE,
5552 EL_CHAR('E'), -1, -1
5555 Xalpha_f, TRUE, FALSE,
5556 EL_CHAR('F'), -1, -1
5559 Xalpha_g, TRUE, FALSE,
5560 EL_CHAR('G'), -1, -1
5563 Xalpha_h, TRUE, FALSE,
5564 EL_CHAR('H'), -1, -1
5567 Xalpha_i, TRUE, FALSE,
5568 EL_CHAR('I'), -1, -1
5571 Xalpha_j, TRUE, FALSE,
5572 EL_CHAR('J'), -1, -1
5575 Xalpha_k, TRUE, FALSE,
5576 EL_CHAR('K'), -1, -1
5579 Xalpha_l, TRUE, FALSE,
5580 EL_CHAR('L'), -1, -1
5583 Xalpha_m, TRUE, FALSE,
5584 EL_CHAR('M'), -1, -1
5587 Xalpha_n, TRUE, FALSE,
5588 EL_CHAR('N'), -1, -1
5591 Xalpha_o, TRUE, FALSE,
5592 EL_CHAR('O'), -1, -1
5595 Xalpha_p, TRUE, FALSE,
5596 EL_CHAR('P'), -1, -1
5599 Xalpha_q, TRUE, FALSE,
5600 EL_CHAR('Q'), -1, -1
5603 Xalpha_r, TRUE, FALSE,
5604 EL_CHAR('R'), -1, -1
5607 Xalpha_s, TRUE, FALSE,
5608 EL_CHAR('S'), -1, -1
5611 Xalpha_t, TRUE, FALSE,
5612 EL_CHAR('T'), -1, -1
5615 Xalpha_u, TRUE, FALSE,
5616 EL_CHAR('U'), -1, -1
5619 Xalpha_v, TRUE, FALSE,
5620 EL_CHAR('V'), -1, -1
5623 Xalpha_w, TRUE, FALSE,
5624 EL_CHAR('W'), -1, -1
5627 Xalpha_x, TRUE, FALSE,
5628 EL_CHAR('X'), -1, -1
5631 Xalpha_y, TRUE, FALSE,
5632 EL_CHAR('Y'), -1, -1
5635 Xalpha_z, TRUE, FALSE,
5636 EL_CHAR('Z'), -1, -1
5639 Xalpha_arrow_e, TRUE, FALSE,
5640 EL_CHAR('>'), -1, -1
5643 Xalpha_arrow_w, TRUE, FALSE,
5644 EL_CHAR('<'), -1, -1
5647 Xalpha_copyr, TRUE, FALSE,
5648 EL_CHAR('©'), -1, -1
5652 Xboom_bug, FALSE, FALSE,
5653 EL_BUG, ACTION_EXPLODING, -1
5656 Xboom_bomb, FALSE, FALSE,
5657 EL_BOMB, ACTION_EXPLODING, -1
5660 Xboom_android, FALSE, FALSE,
5661 EL_EMC_ANDROID, ACTION_OTHER, -1
5664 Xboom_1, FALSE, FALSE,
5665 EL_DEFAULT, ACTION_EXPLODING, -1
5668 Xboom_2, FALSE, FALSE,
5669 EL_DEFAULT, ACTION_EXPLODING, -1
5672 Znormal, FALSE, FALSE,
5676 Zdynamite, FALSE, FALSE,
5680 Zplayer, FALSE, FALSE,
5684 ZBORDER, FALSE, FALSE,
5694 static struct Mapping_EM_to_RND_player
5703 em_player_mapping_list[] =
5707 EL_PLAYER_1, ACTION_MOVING, MV_BIT_UP,
5711 EL_PLAYER_1, ACTION_MOVING, MV_BIT_RIGHT,
5715 EL_PLAYER_1, ACTION_MOVING, MV_BIT_DOWN,
5719 EL_PLAYER_1, ACTION_MOVING, MV_BIT_LEFT,
5723 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_UP,
5727 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_RIGHT,
5731 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_DOWN,
5735 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_LEFT,
5739 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_UP,
5743 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_RIGHT,
5747 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_DOWN,
5751 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_LEFT,
5755 EL_PLAYER_2, ACTION_MOVING, MV_BIT_UP,
5759 EL_PLAYER_2, ACTION_MOVING, MV_BIT_RIGHT,
5763 EL_PLAYER_2, ACTION_MOVING, MV_BIT_DOWN,
5767 EL_PLAYER_2, ACTION_MOVING, MV_BIT_LEFT,
5771 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_UP,
5775 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_RIGHT,
5779 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_DOWN,
5783 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_LEFT,
5787 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_UP,
5791 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_RIGHT,
5795 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_DOWN,
5799 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_LEFT,
5803 EL_PLAYER_1, ACTION_DEFAULT, -1,
5807 EL_PLAYER_2, ACTION_DEFAULT, -1,
5811 EL_PLAYER_3, ACTION_MOVING, MV_BIT_UP,
5815 EL_PLAYER_3, ACTION_MOVING, MV_BIT_RIGHT,
5819 EL_PLAYER_3, ACTION_MOVING, MV_BIT_DOWN,
5823 EL_PLAYER_3, ACTION_MOVING, MV_BIT_LEFT,
5827 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_UP,
5831 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_RIGHT,
5835 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_DOWN,
5839 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_LEFT,
5843 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_UP,
5847 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_RIGHT,
5851 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_DOWN,
5855 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_LEFT,
5859 EL_PLAYER_4, ACTION_MOVING, MV_BIT_UP,
5863 EL_PLAYER_4, ACTION_MOVING, MV_BIT_RIGHT,
5867 EL_PLAYER_4, ACTION_MOVING, MV_BIT_DOWN,
5871 EL_PLAYER_4, ACTION_MOVING, MV_BIT_LEFT,
5875 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_UP,
5879 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_RIGHT,
5883 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_DOWN,
5887 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_LEFT,
5891 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_UP,
5895 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_RIGHT,
5899 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_DOWN,
5903 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_LEFT,
5907 EL_PLAYER_3, ACTION_DEFAULT, -1,
5911 EL_PLAYER_4, ACTION_DEFAULT, -1,
5920 int map_element_RND_to_EM(int element_rnd)
5922 static unsigned short mapping_RND_to_EM[NUM_FILE_ELEMENTS];
5923 static boolean mapping_initialized = FALSE;
5925 if (!mapping_initialized)
5929 /* return "Xalpha_quest" for all undefined elements in mapping array */
5930 for (i = 0; i < NUM_FILE_ELEMENTS; i++)
5931 mapping_RND_to_EM[i] = Xalpha_quest;
5933 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5934 if (em_object_mapping_list[i].is_rnd_to_em_mapping)
5935 mapping_RND_to_EM[em_object_mapping_list[i].element_rnd] =
5936 em_object_mapping_list[i].element_em;
5938 mapping_initialized = TRUE;
5941 if (element_rnd >= 0 && element_rnd < NUM_FILE_ELEMENTS)
5942 return mapping_RND_to_EM[element_rnd];
5944 Error(ERR_WARN, "invalid RND level element %d", element_rnd);
5949 int map_element_EM_to_RND(int element_em)
5951 static unsigned short mapping_EM_to_RND[TILE_MAX];
5952 static boolean mapping_initialized = FALSE;
5954 if (!mapping_initialized)
5958 /* return "EL_UNKNOWN" for all undefined elements in mapping array */
5959 for (i = 0; i < TILE_MAX; i++)
5960 mapping_EM_to_RND[i] = EL_UNKNOWN;
5962 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5963 mapping_EM_to_RND[em_object_mapping_list[i].element_em] =
5964 em_object_mapping_list[i].element_rnd;
5966 mapping_initialized = TRUE;
5969 if (element_em >= 0 && element_em < TILE_MAX)
5970 return mapping_EM_to_RND[element_em];
5972 Error(ERR_WARN, "invalid EM level element %d", element_em);
5977 void map_android_clone_elements_RND_to_EM(struct LevelInfo *level)
5979 struct LevelInfo_EM *level_em = level->native_em_level;
5980 struct LEVEL *lev = level_em->lev;
5983 for (i = 0; i < TILE_MAX; i++)
5984 lev->android_array[i] = Xblank;
5986 for (i = 0; i < level->num_android_clone_elements; i++)
5988 int element_rnd = level->android_clone_element[i];
5989 int element_em = map_element_RND_to_EM(element_rnd);
5991 for (j = 0; em_object_mapping_list[j].element_em != -1; j++)
5992 if (em_object_mapping_list[j].element_rnd == element_rnd)
5993 lev->android_array[em_object_mapping_list[j].element_em] = element_em;
5997 void map_android_clone_elements_EM_to_RND(struct LevelInfo *level)
5999 struct LevelInfo_EM *level_em = level->native_em_level;
6000 struct LEVEL *lev = level_em->lev;
6003 level->num_android_clone_elements = 0;
6005 for (i = 0; i < TILE_MAX; i++)
6007 int element_em = lev->android_array[i];
6009 boolean element_found = FALSE;
6011 if (element_em == Xblank)
6014 element_rnd = map_element_EM_to_RND(element_em);
6016 for (j = 0; j < level->num_android_clone_elements; j++)
6017 if (level->android_clone_element[j] == element_rnd)
6018 element_found = TRUE;
6022 level->android_clone_element[level->num_android_clone_elements++] =
6025 if (level->num_android_clone_elements == MAX_ANDROID_ELEMENTS)
6030 if (level->num_android_clone_elements == 0)
6032 level->num_android_clone_elements = 1;
6033 level->android_clone_element[0] = EL_EMPTY;
6037 int map_direction_RND_to_EM(int direction)
6039 return (direction == MV_UP ? 0 :
6040 direction == MV_RIGHT ? 1 :
6041 direction == MV_DOWN ? 2 :
6042 direction == MV_LEFT ? 3 :
6046 int map_direction_EM_to_RND(int direction)
6048 return (direction == 0 ? MV_UP :
6049 direction == 1 ? MV_RIGHT :
6050 direction == 2 ? MV_DOWN :
6051 direction == 3 ? MV_LEFT :
6055 int map_element_RND_to_SP(int element_rnd)
6057 int element_sp = 0x20; /* map unknown elements to yellow "hardware" */
6059 if (element_rnd >= EL_SP_START &&
6060 element_rnd <= EL_SP_END)
6061 element_sp = element_rnd - EL_SP_START;
6062 else if (element_rnd == EL_EMPTY_SPACE)
6064 else if (element_rnd == EL_INVISIBLE_WALL)
6070 int map_element_SP_to_RND(int element_sp)
6072 int element_rnd = EL_UNKNOWN;
6074 if (element_sp >= 0x00 &&
6076 element_rnd = EL_SP_START + element_sp;
6077 else if (element_sp == 0x28)
6078 element_rnd = EL_INVISIBLE_WALL;
6083 int map_action_SP_to_RND(int action_sp)
6087 case actActive: return ACTION_ACTIVE;
6088 case actImpact: return ACTION_IMPACT;
6089 case actExploding: return ACTION_EXPLODING;
6090 case actDigging: return ACTION_DIGGING;
6091 case actSnapping: return ACTION_SNAPPING;
6092 case actCollecting: return ACTION_COLLECTING;
6093 case actPassing: return ACTION_PASSING;
6094 case actPushing: return ACTION_PUSHING;
6095 case actDropping: return ACTION_DROPPING;
6097 default: return ACTION_DEFAULT;
6101 int get_next_element(int element)
6105 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
6106 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
6107 case EL_QUICKSAND_FAST_FILLING: return EL_QUICKSAND_FAST_FULL;
6108 case EL_QUICKSAND_FAST_EMPTYING: return EL_QUICKSAND_FAST_EMPTY;
6109 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
6110 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
6111 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
6112 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
6113 case EL_DC_MAGIC_WALL_FILLING: return EL_DC_MAGIC_WALL_FULL;
6114 case EL_DC_MAGIC_WALL_EMPTYING: return EL_DC_MAGIC_WALL_ACTIVE;
6115 case EL_AMOEBA_DROPPING: return EL_AMOEBA_WET;
6117 default: return element;
6122 int el_act_dir2img(int element, int action, int direction)
6124 element = GFX_ELEMENT(element);
6126 if (direction == MV_NONE)
6127 return element_info[element].graphic[action];
6129 direction = MV_DIR_TO_BIT(direction);
6131 return element_info[element].direction_graphic[action][direction];
6134 int el_act_dir2img(int element, int action, int direction)
6136 element = GFX_ELEMENT(element);
6137 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
6139 /* direction_graphic[][] == graphic[] for undefined direction graphics */
6140 return element_info[element].direction_graphic[action][direction];
6145 static int el_act_dir2crm(int element, int action, int direction)
6147 element = GFX_ELEMENT(element);
6149 if (direction == MV_NONE)
6150 return element_info[element].crumbled[action];
6152 direction = MV_DIR_TO_BIT(direction);
6154 return element_info[element].direction_crumbled[action][direction];
6157 static int el_act_dir2crm(int element, int action, int direction)
6159 element = GFX_ELEMENT(element);
6160 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
6162 /* direction_graphic[][] == graphic[] for undefined direction graphics */
6163 return element_info[element].direction_crumbled[action][direction];
6167 int el_act2img(int element, int action)
6169 element = GFX_ELEMENT(element);
6171 return element_info[element].graphic[action];
6174 int el_act2crm(int element, int action)
6176 element = GFX_ELEMENT(element);
6178 return element_info[element].crumbled[action];
6181 int el_dir2img(int element, int direction)
6183 element = GFX_ELEMENT(element);
6185 return el_act_dir2img(element, ACTION_DEFAULT, direction);
6188 int el2baseimg(int element)
6190 return element_info[element].graphic[ACTION_DEFAULT];
6193 int el2img(int element)
6195 element = GFX_ELEMENT(element);
6197 return element_info[element].graphic[ACTION_DEFAULT];
6200 int el2edimg(int element)
6202 element = GFX_ELEMENT(element);
6204 return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
6207 int el2preimg(int element)
6209 element = GFX_ELEMENT(element);
6211 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];
6214 int el2panelimg(int element)
6216 element = GFX_ELEMENT(element);
6218 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PANEL];
6221 int font2baseimg(int font_nr)
6223 return font_info[font_nr].special_graphic[GFX_SPECIAL_ARG_DEFAULT];
6226 int getBeltNrFromBeltElement(int element)
6228 return (element < EL_CONVEYOR_BELT_2_LEFT ? 0 :
6229 element < EL_CONVEYOR_BELT_3_LEFT ? 1 :
6230 element < EL_CONVEYOR_BELT_4_LEFT ? 2 : 3);
6233 int getBeltNrFromBeltActiveElement(int element)
6235 return (element < EL_CONVEYOR_BELT_2_LEFT_ACTIVE ? 0 :
6236 element < EL_CONVEYOR_BELT_3_LEFT_ACTIVE ? 1 :
6237 element < EL_CONVEYOR_BELT_4_LEFT_ACTIVE ? 2 : 3);
6240 int getBeltNrFromBeltSwitchElement(int element)
6242 return (element < EL_CONVEYOR_BELT_2_SWITCH_LEFT ? 0 :
6243 element < EL_CONVEYOR_BELT_3_SWITCH_LEFT ? 1 :
6244 element < EL_CONVEYOR_BELT_4_SWITCH_LEFT ? 2 : 3);
6247 int getBeltDirNrFromBeltElement(int element)
6249 static int belt_base_element[4] =
6251 EL_CONVEYOR_BELT_1_LEFT,
6252 EL_CONVEYOR_BELT_2_LEFT,
6253 EL_CONVEYOR_BELT_3_LEFT,
6254 EL_CONVEYOR_BELT_4_LEFT
6257 int belt_nr = getBeltNrFromBeltElement(element);
6258 int belt_dir_nr = element - belt_base_element[belt_nr];
6260 return (belt_dir_nr % 3);
6263 int getBeltDirNrFromBeltSwitchElement(int element)
6265 static int belt_base_element[4] =
6267 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
6268 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
6269 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
6270 EL_CONVEYOR_BELT_4_SWITCH_LEFT
6273 int belt_nr = getBeltNrFromBeltSwitchElement(element);
6274 int belt_dir_nr = element - belt_base_element[belt_nr];
6276 return (belt_dir_nr % 3);
6279 int getBeltDirFromBeltElement(int element)
6281 static int belt_move_dir[3] =
6288 int belt_dir_nr = getBeltDirNrFromBeltElement(element);
6290 return belt_move_dir[belt_dir_nr];
6293 int getBeltDirFromBeltSwitchElement(int element)
6295 static int belt_move_dir[3] =
6302 int belt_dir_nr = getBeltDirNrFromBeltSwitchElement(element);
6304 return belt_move_dir[belt_dir_nr];
6307 int getBeltElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
6309 static int belt_base_element[4] =
6311 EL_CONVEYOR_BELT_1_LEFT,
6312 EL_CONVEYOR_BELT_2_LEFT,
6313 EL_CONVEYOR_BELT_3_LEFT,
6314 EL_CONVEYOR_BELT_4_LEFT
6317 return belt_base_element[belt_nr] + belt_dir_nr;
6320 int getBeltElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
6322 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
6324 return getBeltElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
6327 int getBeltSwitchElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
6329 static int belt_base_element[4] =
6331 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
6332 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
6333 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
6334 EL_CONVEYOR_BELT_4_SWITCH_LEFT
6337 return belt_base_element[belt_nr] + belt_dir_nr;
6340 int getBeltSwitchElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
6342 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
6344 return getBeltSwitchElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
6347 int getNumActivePlayers_EM()
6349 int num_players = 0;
6355 for (i = 0; i < MAX_PLAYERS; i++)
6356 if (tape.player_participates[i])
6362 int getGameFrameDelay_EM(int native_em_game_frame_delay)
6364 int game_frame_delay_value;
6366 game_frame_delay_value =
6367 (tape.playing && tape.fast_forward ? FfwdFrameDelay :
6368 GameFrameDelay == GAME_FRAME_DELAY ? native_em_game_frame_delay :
6371 if (tape.playing && tape.warp_forward && !tape.pausing)
6372 game_frame_delay_value = 0;
6374 return game_frame_delay_value;
6377 unsigned int InitRND(long seed)
6379 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
6380 return InitEngineRandom_EM(seed);
6381 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
6382 return InitEngineRandom_SP(seed);
6384 return InitEngineRandom_RND(seed);
6388 static struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
6389 static struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
6392 inline static int get_effective_element_EM(int tile, int frame_em)
6394 int element = object_mapping[tile].element_rnd;
6395 int action = object_mapping[tile].action;
6396 boolean is_backside = object_mapping[tile].is_backside;
6397 boolean action_removing = (action == ACTION_DIGGING ||
6398 action == ACTION_SNAPPING ||
6399 action == ACTION_COLLECTING);
6405 case Yacid_splash_eB:
6406 case Yacid_splash_wB:
6407 return (frame_em > 5 ? EL_EMPTY : element);
6413 else /* frame_em == 7 */
6417 case Yacid_splash_eB:
6418 case Yacid_splash_wB:
6421 case Yemerald_stone:
6424 case Ydiamond_stone:
6428 case Xdrip_stretchB:
6447 case Xsand_stonein_1:
6448 case Xsand_stonein_2:
6449 case Xsand_stonein_3:
6450 case Xsand_stonein_4:
6454 return (is_backside || action_removing ? EL_EMPTY : element);
6459 inline static boolean check_linear_animation_EM(int tile)
6463 case Xsand_stonesand_1:
6464 case Xsand_stonesand_quickout_1:
6465 case Xsand_sandstone_1:
6466 case Xsand_stonein_1:
6467 case Xsand_stoneout_1:
6492 inline static void set_crumbled_graphics_EM(struct GraphicInfo_EM *g_em,
6493 boolean has_crumbled_graphics,
6494 int crumbled, int sync_frame)
6496 /* if element can be crumbled, but certain action graphics are just empty
6497 space (like instantly snapping sand to empty space in 1 frame), do not
6498 treat these empty space graphics as crumbled graphics in EMC engine */
6499 if (crumbled == IMG_EMPTY_SPACE)
6500 has_crumbled_graphics = FALSE;
6502 if (has_crumbled_graphics)
6504 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
6505 int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
6506 g_crumbled->anim_delay,
6507 g_crumbled->anim_mode,
6508 g_crumbled->anim_start_frame,
6511 getGraphicSource(crumbled, frame_crumbled, &g_em->crumbled_bitmap,
6512 &g_em->crumbled_src_x, &g_em->crumbled_src_y);
6514 g_em->crumbled_border_size = graphic_info[crumbled].border_size;
6516 g_em->has_crumbled_graphics = TRUE;
6520 g_em->crumbled_bitmap = NULL;
6521 g_em->crumbled_src_x = 0;
6522 g_em->crumbled_src_y = 0;
6523 g_em->crumbled_border_size = 0;
6525 g_em->has_crumbled_graphics = FALSE;
6529 void ResetGfxAnimation_EM(int x, int y, int tile)
6534 void SetGfxAnimation_EM(struct GraphicInfo_EM *g_em,
6535 int tile, int frame_em, int x, int y)
6537 int action = object_mapping[tile].action;
6539 int direction = object_mapping[tile].direction;
6540 int effective_element = get_effective_element_EM(tile, frame_em);
6541 int graphic = (direction == MV_NONE ?
6542 el_act2img(effective_element, action) :
6543 el_act_dir2img(effective_element, action, direction));
6544 struct GraphicInfo *g = &graphic_info[graphic];
6547 boolean action_removing = (action == ACTION_DIGGING ||
6548 action == ACTION_SNAPPING ||
6549 action == ACTION_COLLECTING);
6550 boolean action_moving = (action == ACTION_FALLING ||
6551 action == ACTION_MOVING ||
6552 action == ACTION_PUSHING ||
6553 action == ACTION_EATING ||
6554 action == ACTION_FILLING ||
6555 action == ACTION_EMPTYING);
6556 boolean action_falling = (action == ACTION_FALLING ||
6557 action == ACTION_FILLING ||
6558 action == ACTION_EMPTYING);
6560 /* special case: graphic uses "2nd movement tile" and has defined
6561 7 frames for movement animation (or less) => use default graphic
6562 for last (8th) frame which ends the movement animation */
6563 if (g->double_movement && g->anim_frames < 8 && frame_em == 7)
6565 action = ACTION_DEFAULT; /* (keep action_* unchanged for now) */
6566 graphic = (direction == MV_NONE ?
6567 el_act2img(effective_element, action) :
6568 el_act_dir2img(effective_element, action, direction));
6570 g = &graphic_info[graphic];
6574 if (tile == Xsand_stonesand_1 ||
6575 tile == Xsand_stonesand_2 ||
6576 tile == Xsand_stonesand_3 ||
6577 tile == Xsand_stonesand_4)
6578 printf("::: 1: quicksand frame %d [%d]\n", GfxFrame[x][y], tile);
6582 if ((action_removing || check_linear_animation_EM(tile)) && frame_em == 0)
6586 // printf("::: resetting... [%d]\n", tile);
6589 if (action_removing || check_linear_animation_EM(tile))
6591 GfxFrame[x][y] = frame_em;
6593 // printf("::: resetting... [%d]\n", tile);
6596 else if (action_moving)
6598 boolean is_backside = object_mapping[tile].is_backside;
6602 int direction = object_mapping[tile].direction;
6603 int move_dir = (action_falling ? MV_DOWN : direction);
6608 /* !!! TEST !!! NEW !!! DOES NOT WORK RIGHT YET !!! */
6609 if (g->double_movement && frame_em == 0)
6613 // printf("::: resetting... [%d]\n", tile);
6617 if (move_dir == MV_LEFT)
6618 GfxFrame[x - 1][y] = GfxFrame[x][y];
6619 else if (move_dir == MV_RIGHT)
6620 GfxFrame[x + 1][y] = GfxFrame[x][y];
6621 else if (move_dir == MV_UP)
6622 GfxFrame[x][y - 1] = GfxFrame[x][y];
6623 else if (move_dir == MV_DOWN)
6624 GfxFrame[x][y + 1] = GfxFrame[x][y];
6631 /* special case: animation for Xsand_stonesand_quickout_1/2 twice as fast */
6632 if (tile == Xsand_stonesand_quickout_1 ||
6633 tile == Xsand_stonesand_quickout_2)
6638 if (tile == Xsand_stonesand_1 ||
6639 tile == Xsand_stonesand_2 ||
6640 tile == Xsand_stonesand_3 ||
6641 tile == Xsand_stonesand_4)
6642 printf("::: 2: quicksand frame %d [%d]\n", GfxFrame[x][y], tile);
6646 if (graphic_info[graphic].anim_global_sync)
6647 sync_frame = FrameCounter;
6648 else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY))
6649 sync_frame = GfxFrame[x][y];
6651 sync_frame = 0; /* playfield border (pseudo steel) */
6653 SetRandomAnimationValue(x, y);
6655 int frame = getAnimationFrame(g->anim_frames,
6658 g->anim_start_frame,
6661 g_em->unique_identifier =
6662 (graphic << 16) | ((frame % 8) << 12) | (g_em->width << 6) | g_em->height;
6666 void getGraphicSourceObjectExt_EM(struct GraphicInfo_EM *g_em,
6667 int tile, int frame_em, int x, int y)
6669 int action = object_mapping[tile].action;
6670 int direction = object_mapping[tile].direction;
6671 boolean is_backside = object_mapping[tile].is_backside;
6672 int effective_element = get_effective_element_EM(tile, frame_em);
6674 int effective_action = action;
6676 int effective_action = (frame_em < 7 ? action : ACTION_DEFAULT);
6678 int graphic = (direction == MV_NONE ?
6679 el_act2img(effective_element, effective_action) :
6680 el_act_dir2img(effective_element, effective_action,
6682 int crumbled = (direction == MV_NONE ?
6683 el_act2crm(effective_element, effective_action) :
6684 el_act_dir2crm(effective_element, effective_action,
6686 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
6687 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
6688 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
6689 struct GraphicInfo *g = &graphic_info[graphic];
6691 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
6695 /* special case: graphic uses "2nd movement tile" and has defined
6696 7 frames for movement animation (or less) => use default graphic
6697 for last (8th) frame which ends the movement animation */
6698 if (g->double_movement && g->anim_frames < 8 && frame_em == 7)
6700 effective_action = ACTION_DEFAULT;
6701 graphic = (direction == MV_NONE ?
6702 el_act2img(effective_element, effective_action) :
6703 el_act_dir2img(effective_element, effective_action,
6705 crumbled = (direction == MV_NONE ?
6706 el_act2crm(effective_element, effective_action) :
6707 el_act_dir2crm(effective_element, effective_action,
6710 g = &graphic_info[graphic];
6720 if (frame_em == 0) /* reset animation frame for certain elements */
6722 if (check_linear_animation_EM(tile))
6727 if (graphic_info[graphic].anim_global_sync)
6728 sync_frame = FrameCounter;
6729 else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY))
6730 sync_frame = GfxFrame[x][y];
6732 sync_frame = 0; /* playfield border (pseudo steel) */
6734 SetRandomAnimationValue(x, y);
6739 int xxx_sync_frame = (i == Xdrip_stretch ? 7 :
6740 i == Xdrip_stretchB ? 7 :
6741 i == Ydrip_s2 ? j + 8 :
6742 i == Ydrip_s2B ? j + 8 :
6751 i == Xfake_acid_1 ? 0 :
6752 i == Xfake_acid_2 ? 10 :
6753 i == Xfake_acid_3 ? 20 :
6754 i == Xfake_acid_4 ? 30 :
6755 i == Xfake_acid_5 ? 40 :
6756 i == Xfake_acid_6 ? 50 :
6757 i == Xfake_acid_7 ? 60 :
6758 i == Xfake_acid_8 ? 70 :
6760 i == Xball_2B ? j + 8 :
6761 i == Yball_eat ? j + 1 :
6762 i == Ykey_1_eat ? j + 1 :
6763 i == Ykey_2_eat ? j + 1 :
6764 i == Ykey_3_eat ? j + 1 :
6765 i == Ykey_4_eat ? j + 1 :
6766 i == Ykey_5_eat ? j + 1 :
6767 i == Ykey_6_eat ? j + 1 :
6768 i == Ykey_7_eat ? j + 1 :
6769 i == Ykey_8_eat ? j + 1 :
6770 i == Ylenses_eat ? j + 1 :
6771 i == Ymagnify_eat ? j + 1 :
6772 i == Ygrass_eat ? j + 1 :
6773 i == Ydirt_eat ? j + 1 :
6774 i == Xamoeba_1 ? 0 :
6775 i == Xamoeba_2 ? 1 :
6776 i == Xamoeba_3 ? 2 :
6777 i == Xamoeba_4 ? 3 :
6778 i == Xamoeba_5 ? 0 :
6779 i == Xamoeba_6 ? 1 :
6780 i == Xamoeba_7 ? 2 :
6781 i == Xamoeba_8 ? 3 :
6782 i == Xexit_2 ? j + 8 :
6783 i == Xexit_3 ? j + 16 :
6784 i == Xdynamite_1 ? 0 :
6785 i == Xdynamite_2 ? 8 :
6786 i == Xdynamite_3 ? 16 :
6787 i == Xdynamite_4 ? 24 :
6788 i == Xsand_stonein_1 ? j + 1 :
6789 i == Xsand_stonein_2 ? j + 9 :
6790 i == Xsand_stonein_3 ? j + 17 :
6791 i == Xsand_stonein_4 ? j + 25 :
6792 i == Xsand_stoneout_1 && j == 0 ? 0 :
6793 i == Xsand_stoneout_1 && j == 1 ? 0 :
6794 i == Xsand_stoneout_1 && j == 2 ? 1 :
6795 i == Xsand_stoneout_1 && j == 3 ? 2 :
6796 i == Xsand_stoneout_1 && j == 4 ? 2 :
6797 i == Xsand_stoneout_1 && j == 5 ? 3 :
6798 i == Xsand_stoneout_1 && j == 6 ? 4 :
6799 i == Xsand_stoneout_1 && j == 7 ? 4 :
6800 i == Xsand_stoneout_2 && j == 0 ? 5 :
6801 i == Xsand_stoneout_2 && j == 1 ? 6 :
6802 i == Xsand_stoneout_2 && j == 2 ? 7 :
6803 i == Xsand_stoneout_2 && j == 3 ? 8 :
6804 i == Xsand_stoneout_2 && j == 4 ? 9 :
6805 i == Xsand_stoneout_2 && j == 5 ? 11 :
6806 i == Xsand_stoneout_2 && j == 6 ? 13 :
6807 i == Xsand_stoneout_2 && j == 7 ? 15 :
6808 i == Xboom_bug && j == 1 ? 2 :
6809 i == Xboom_bug && j == 2 ? 2 :
6810 i == Xboom_bug && j == 3 ? 4 :
6811 i == Xboom_bug && j == 4 ? 4 :
6812 i == Xboom_bug && j == 5 ? 2 :
6813 i == Xboom_bug && j == 6 ? 2 :
6814 i == Xboom_bug && j == 7 ? 0 :
6815 i == Xboom_bomb && j == 1 ? 2 :
6816 i == Xboom_bomb && j == 2 ? 2 :
6817 i == Xboom_bomb && j == 3 ? 4 :
6818 i == Xboom_bomb && j == 4 ? 4 :
6819 i == Xboom_bomb && j == 5 ? 2 :
6820 i == Xboom_bomb && j == 6 ? 2 :
6821 i == Xboom_bomb && j == 7 ? 0 :
6822 i == Xboom_android && j == 7 ? 6 :
6823 i == Xboom_1 && j == 1 ? 2 :
6824 i == Xboom_1 && j == 2 ? 2 :
6825 i == Xboom_1 && j == 3 ? 4 :
6826 i == Xboom_1 && j == 4 ? 4 :
6827 i == Xboom_1 && j == 5 ? 6 :
6828 i == Xboom_1 && j == 6 ? 6 :
6829 i == Xboom_1 && j == 7 ? 8 :
6830 i == Xboom_2 && j == 0 ? 8 :
6831 i == Xboom_2 && j == 1 ? 8 :
6832 i == Xboom_2 && j == 2 ? 10 :
6833 i == Xboom_2 && j == 3 ? 10 :
6834 i == Xboom_2 && j == 4 ? 10 :
6835 i == Xboom_2 && j == 5 ? 12 :
6836 i == Xboom_2 && j == 6 ? 12 :
6837 i == Xboom_2 && j == 7 ? 12 :
6839 special_animation && j == 4 ? 3 :
6840 effective_action != action ? 0 :
6846 int xxx_effective_action;
6847 int xxx_has_action_graphics;
6850 int element = object_mapping[i].element_rnd;
6851 int action = object_mapping[i].action;
6852 int direction = object_mapping[i].direction;
6853 boolean is_backside = object_mapping[i].is_backside;
6855 boolean action_removing = (action == ACTION_DIGGING ||
6856 action == ACTION_SNAPPING ||
6857 action == ACTION_COLLECTING);
6859 boolean action_exploding = ((action == ACTION_EXPLODING ||
6860 action == ACTION_SMASHED_BY_ROCK ||
6861 action == ACTION_SMASHED_BY_SPRING) &&
6862 element != EL_DIAMOND);
6863 boolean action_active = (action == ACTION_ACTIVE);
6864 boolean action_other = (action == ACTION_OTHER);
6868 int effective_element = get_effective_element_EM(i, j);
6870 int effective_element = (j > 5 && i == Yacid_splash_eB ? EL_EMPTY :
6871 j > 5 && i == Yacid_splash_wB ? EL_EMPTY :
6873 i == Xdrip_stretch ? element :
6874 i == Xdrip_stretchB ? element :
6875 i == Ydrip_s1 ? element :
6876 i == Ydrip_s1B ? element :
6877 i == Xball_1B ? element :
6878 i == Xball_2 ? element :
6879 i == Xball_2B ? element :
6880 i == Yball_eat ? element :
6881 i == Ykey_1_eat ? element :
6882 i == Ykey_2_eat ? element :
6883 i == Ykey_3_eat ? element :
6884 i == Ykey_4_eat ? element :
6885 i == Ykey_5_eat ? element :
6886 i == Ykey_6_eat ? element :
6887 i == Ykey_7_eat ? element :
6888 i == Ykey_8_eat ? element :
6889 i == Ylenses_eat ? element :
6890 i == Ymagnify_eat ? element :
6891 i == Ygrass_eat ? element :
6892 i == Ydirt_eat ? element :
6893 i == Yemerald_stone ? EL_EMERALD :
6894 i == Ydiamond_stone ? EL_ROCK :
6895 i == Xsand_stonein_1 ? element :
6896 i == Xsand_stonein_2 ? element :
6897 i == Xsand_stonein_3 ? element :
6898 i == Xsand_stonein_4 ? element :
6899 is_backside ? EL_EMPTY :
6900 action_removing ? EL_EMPTY :
6903 int effective_action = (j < 7 ? action :
6904 i == Xdrip_stretch ? action :
6905 i == Xdrip_stretchB ? action :
6906 i == Ydrip_s1 ? action :
6907 i == Ydrip_s1B ? action :
6908 i == Xball_1B ? action :
6909 i == Xball_2 ? action :
6910 i == Xball_2B ? action :
6911 i == Yball_eat ? action :
6912 i == Ykey_1_eat ? action :
6913 i == Ykey_2_eat ? action :
6914 i == Ykey_3_eat ? action :
6915 i == Ykey_4_eat ? action :
6916 i == Ykey_5_eat ? action :
6917 i == Ykey_6_eat ? action :
6918 i == Ykey_7_eat ? action :
6919 i == Ykey_8_eat ? action :
6920 i == Ylenses_eat ? action :
6921 i == Ymagnify_eat ? action :
6922 i == Ygrass_eat ? action :
6923 i == Ydirt_eat ? action :
6924 i == Xsand_stonein_1 ? action :
6925 i == Xsand_stonein_2 ? action :
6926 i == Xsand_stonein_3 ? action :
6927 i == Xsand_stonein_4 ? action :
6928 i == Xsand_stoneout_1 ? action :
6929 i == Xsand_stoneout_2 ? action :
6930 i == Xboom_android ? ACTION_EXPLODING :
6931 action_exploding ? ACTION_EXPLODING :
6932 action_active ? action :
6933 action_other ? action :
6935 int graphic = (el_act_dir2img(effective_element, effective_action,
6937 int crumbled = (el_act_dir2crm(effective_element, effective_action,
6939 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
6940 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
6941 boolean has_action_graphics = (graphic != base_graphic);
6942 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
6943 struct GraphicInfo *g = &graphic_info[graphic];
6945 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
6947 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
6950 /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
6951 boolean special_animation = (action != ACTION_DEFAULT &&
6952 g->anim_frames == 3 &&
6953 g->anim_delay == 2 &&
6954 g->anim_mode & ANIM_LINEAR);
6955 xxx_sync_frame = (i == Xdrip_stretch ? 7 :
6956 i == Xdrip_stretchB ? 7 :
6957 i == Ydrip_s2 ? j + 8 :
6958 i == Ydrip_s2B ? j + 8 :
6967 i == Xfake_acid_1 ? 0 :
6968 i == Xfake_acid_2 ? 10 :
6969 i == Xfake_acid_3 ? 20 :
6970 i == Xfake_acid_4 ? 30 :
6971 i == Xfake_acid_5 ? 40 :
6972 i == Xfake_acid_6 ? 50 :
6973 i == Xfake_acid_7 ? 60 :
6974 i == Xfake_acid_8 ? 70 :
6976 i == Xball_2B ? j + 8 :
6977 i == Yball_eat ? j + 1 :
6978 i == Ykey_1_eat ? j + 1 :
6979 i == Ykey_2_eat ? j + 1 :
6980 i == Ykey_3_eat ? j + 1 :
6981 i == Ykey_4_eat ? j + 1 :
6982 i == Ykey_5_eat ? j + 1 :
6983 i == Ykey_6_eat ? j + 1 :
6984 i == Ykey_7_eat ? j + 1 :
6985 i == Ykey_8_eat ? j + 1 :
6986 i == Ylenses_eat ? j + 1 :
6987 i == Ymagnify_eat ? j + 1 :
6988 i == Ygrass_eat ? j + 1 :
6989 i == Ydirt_eat ? j + 1 :
6990 i == Xamoeba_1 ? 0 :
6991 i == Xamoeba_2 ? 1 :
6992 i == Xamoeba_3 ? 2 :
6993 i == Xamoeba_4 ? 3 :
6994 i == Xamoeba_5 ? 0 :
6995 i == Xamoeba_6 ? 1 :
6996 i == Xamoeba_7 ? 2 :
6997 i == Xamoeba_8 ? 3 :
6998 i == Xexit_2 ? j + 8 :
6999 i == Xexit_3 ? j + 16 :
7000 i == Xdynamite_1 ? 0 :
7001 i == Xdynamite_2 ? 8 :
7002 i == Xdynamite_3 ? 16 :
7003 i == Xdynamite_4 ? 24 :
7004 i == Xsand_stonein_1 ? j + 1 :
7005 i == Xsand_stonein_2 ? j + 9 :
7006 i == Xsand_stonein_3 ? j + 17 :
7007 i == Xsand_stonein_4 ? j + 25 :
7008 i == Xsand_stoneout_1 && j == 0 ? 0 :
7009 i == Xsand_stoneout_1 && j == 1 ? 0 :
7010 i == Xsand_stoneout_1 && j == 2 ? 1 :
7011 i == Xsand_stoneout_1 && j == 3 ? 2 :
7012 i == Xsand_stoneout_1 && j == 4 ? 2 :
7013 i == Xsand_stoneout_1 && j == 5 ? 3 :
7014 i == Xsand_stoneout_1 && j == 6 ? 4 :
7015 i == Xsand_stoneout_1 && j == 7 ? 4 :
7016 i == Xsand_stoneout_2 && j == 0 ? 5 :
7017 i == Xsand_stoneout_2 && j == 1 ? 6 :
7018 i == Xsand_stoneout_2 && j == 2 ? 7 :
7019 i == Xsand_stoneout_2 && j == 3 ? 8 :
7020 i == Xsand_stoneout_2 && j == 4 ? 9 :
7021 i == Xsand_stoneout_2 && j == 5 ? 11 :
7022 i == Xsand_stoneout_2 && j == 6 ? 13 :
7023 i == Xsand_stoneout_2 && j == 7 ? 15 :
7024 i == Xboom_bug && j == 1 ? 2 :
7025 i == Xboom_bug && j == 2 ? 2 :
7026 i == Xboom_bug && j == 3 ? 4 :
7027 i == Xboom_bug && j == 4 ? 4 :
7028 i == Xboom_bug && j == 5 ? 2 :
7029 i == Xboom_bug && j == 6 ? 2 :
7030 i == Xboom_bug && j == 7 ? 0 :
7031 i == Xboom_bomb && j == 1 ? 2 :
7032 i == Xboom_bomb && j == 2 ? 2 :
7033 i == Xboom_bomb && j == 3 ? 4 :
7034 i == Xboom_bomb && j == 4 ? 4 :
7035 i == Xboom_bomb && j == 5 ? 2 :
7036 i == Xboom_bomb && j == 6 ? 2 :
7037 i == Xboom_bomb && j == 7 ? 0 :
7038 i == Xboom_android && j == 7 ? 6 :
7039 i == Xboom_1 && j == 1 ? 2 :
7040 i == Xboom_1 && j == 2 ? 2 :
7041 i == Xboom_1 && j == 3 ? 4 :
7042 i == Xboom_1 && j == 4 ? 4 :
7043 i == Xboom_1 && j == 5 ? 6 :
7044 i == Xboom_1 && j == 6 ? 6 :
7045 i == Xboom_1 && j == 7 ? 8 :
7046 i == Xboom_2 && j == 0 ? 8 :
7047 i == Xboom_2 && j == 1 ? 8 :
7048 i == Xboom_2 && j == 2 ? 10 :
7049 i == Xboom_2 && j == 3 ? 10 :
7050 i == Xboom_2 && j == 4 ? 10 :
7051 i == Xboom_2 && j == 5 ? 12 :
7052 i == Xboom_2 && j == 6 ? 12 :
7053 i == Xboom_2 && j == 7 ? 12 :
7054 special_animation && j == 4 ? 3 :
7055 effective_action != action ? 0 :
7058 xxx_effective_action = effective_action;
7059 xxx_has_action_graphics = has_action_graphics;
7064 int frame = getAnimationFrame(g->anim_frames,
7067 g->anim_start_frame,
7081 int old_src_x = g_em->src_x;
7082 int old_src_y = g_em->src_y;
7086 getGraphicSourceExt(graphic, frame, &g_em->bitmap, &g_em->src_x, &g_em->src_y,
7087 g->double_movement && is_backside);
7089 getGraphicSourceExt(graphic, frame, &g_em->bitmap,
7090 &g_em->src_x, &g_em->src_y, FALSE);
7101 if (graphic == IMG_BUG_MOVING_RIGHT)
7102 printf("::: %d, %d, %d: %d, %d [%d, %d -> %d, %d]\n", graphic, x, y,
7103 g->double_movement, is_backside,
7104 old_src_x, old_src_y, g_em->src_x, g_em->src_y);
7112 g_em->src_offset_x = 0;
7113 g_em->src_offset_y = 0;
7114 g_em->dst_offset_x = 0;
7115 g_em->dst_offset_y = 0;
7116 g_em->width = TILEX;
7117 g_em->height = TILEY;
7119 g_em->preserve_background = FALSE;
7122 /* (updating the "crumbled" graphic definitions is probably not really needed,
7123 as animations for crumbled graphics can't be longer than one EMC cycle) */
7125 set_crumbled_graphics_EM(g_em, has_crumbled_graphics, crumbled,
7130 g_em->crumbled_bitmap = NULL;
7131 g_em->crumbled_src_x = 0;
7132 g_em->crumbled_src_y = 0;
7134 g_em->has_crumbled_graphics = FALSE;
7136 if (has_crumbled_graphics && crumbled != IMG_EMPTY_SPACE)
7138 int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
7139 g_crumbled->anim_delay,
7140 g_crumbled->anim_mode,
7141 g_crumbled->anim_start_frame,
7144 getGraphicSource(crumbled, frame_crumbled, &g_em->crumbled_bitmap,
7145 &g_em->crumbled_src_x, &g_em->crumbled_src_y);
7147 g_em->has_crumbled_graphics = TRUE;
7153 int effective_action = xxx_effective_action;
7154 int has_action_graphics = xxx_has_action_graphics;
7156 if ((!g->double_movement && (effective_action == ACTION_FALLING ||
7157 effective_action == ACTION_MOVING ||
7158 effective_action == ACTION_PUSHING ||
7159 effective_action == ACTION_EATING)) ||
7160 (!has_action_graphics && (effective_action == ACTION_FILLING ||
7161 effective_action == ACTION_EMPTYING)))
7164 (effective_action == ACTION_FALLING ||
7165 effective_action == ACTION_FILLING ||
7166 effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
7167 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
7168 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? 1 : 0);
7169 int num_steps = (i == Ydrip_s1 ? 16 :
7170 i == Ydrip_s1B ? 16 :
7171 i == Ydrip_s2 ? 16 :
7172 i == Ydrip_s2B ? 16 :
7173 i == Xsand_stonein_1 ? 32 :
7174 i == Xsand_stonein_2 ? 32 :
7175 i == Xsand_stonein_3 ? 32 :
7176 i == Xsand_stonein_4 ? 32 :
7177 i == Xsand_stoneout_1 ? 16 :
7178 i == Xsand_stoneout_2 ? 16 : 8);
7179 int cx = ABS(dx) * (TILEX / num_steps);
7180 int cy = ABS(dy) * (TILEY / num_steps);
7181 int step_frame = (i == Ydrip_s2 ? j + 8 :
7182 i == Ydrip_s2B ? j + 8 :
7183 i == Xsand_stonein_2 ? j + 8 :
7184 i == Xsand_stonein_3 ? j + 16 :
7185 i == Xsand_stonein_4 ? j + 24 :
7186 i == Xsand_stoneout_2 ? j + 8 : j) + 1;
7187 int step = (is_backside ? step_frame : num_steps - step_frame);
7189 if (is_backside) /* tile where movement starts */
7191 if (dx < 0 || dy < 0)
7193 g_em->src_offset_x = cx * step;
7194 g_em->src_offset_y = cy * step;
7198 g_em->dst_offset_x = cx * step;
7199 g_em->dst_offset_y = cy * step;
7202 else /* tile where movement ends */
7204 if (dx < 0 || dy < 0)
7206 g_em->dst_offset_x = cx * step;
7207 g_em->dst_offset_y = cy * step;
7211 g_em->src_offset_x = cx * step;
7212 g_em->src_offset_y = cy * step;
7216 g_em->width = TILEX - cx * step;
7217 g_em->height = TILEY - cy * step;
7220 /* create unique graphic identifier to decide if tile must be redrawn */
7221 /* bit 31 - 16 (16 bit): EM style graphic
7222 bit 15 - 12 ( 4 bit): EM style frame
7223 bit 11 - 6 ( 6 bit): graphic width
7224 bit 5 - 0 ( 6 bit): graphic height */
7225 g_em->unique_identifier =
7226 (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
7232 void getGraphicSourcePlayerExt_EM(struct GraphicInfo_EM *g_em,
7233 int player_nr, int anim, int frame_em)
7235 int element = player_mapping[player_nr][anim].element_rnd;
7236 int action = player_mapping[player_nr][anim].action;
7237 int direction = player_mapping[player_nr][anim].direction;
7238 int graphic = (direction == MV_NONE ?
7239 el_act2img(element, action) :
7240 el_act_dir2img(element, action, direction));
7241 struct GraphicInfo *g = &graphic_info[graphic];
7244 InitPlayerGfxAnimation(&stored_player[player_nr], action, direction);
7246 stored_player[player_nr].StepFrame = frame_em;
7248 sync_frame = stored_player[player_nr].Frame;
7250 int frame = getAnimationFrame(g->anim_frames,
7253 g->anim_start_frame,
7256 getGraphicSourceExt(graphic, frame, &g_em->bitmap,
7257 &g_em->src_x, &g_em->src_y, FALSE);
7260 printf("::: %d: %d, %d [%d]\n",
7262 stored_player[player_nr].Frame,
7263 stored_player[player_nr].StepFrame,
7268 void InitGraphicInfo_EM(void)
7271 struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
7272 struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
7277 int num_em_gfx_errors = 0;
7279 if (graphic_info_em_object[0][0].bitmap == NULL)
7281 /* EM graphics not yet initialized in em_open_all() */
7286 printf("::: [4 errors can be ignored (1 x 'bomb', 3 x 'em_dynamite']\n");
7289 /* always start with reliable default values */
7290 for (i = 0; i < TILE_MAX; i++)
7292 object_mapping[i].element_rnd = EL_UNKNOWN;
7293 object_mapping[i].is_backside = FALSE;
7294 object_mapping[i].action = ACTION_DEFAULT;
7295 object_mapping[i].direction = MV_NONE;
7298 /* always start with reliable default values */
7299 for (p = 0; p < MAX_PLAYERS; p++)
7301 for (i = 0; i < SPR_MAX; i++)
7303 player_mapping[p][i].element_rnd = EL_UNKNOWN;
7304 player_mapping[p][i].action = ACTION_DEFAULT;
7305 player_mapping[p][i].direction = MV_NONE;
7309 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
7311 int e = em_object_mapping_list[i].element_em;
7313 object_mapping[e].element_rnd = em_object_mapping_list[i].element_rnd;
7314 object_mapping[e].is_backside = em_object_mapping_list[i].is_backside;
7316 if (em_object_mapping_list[i].action != -1)
7317 object_mapping[e].action = em_object_mapping_list[i].action;
7319 if (em_object_mapping_list[i].direction != -1)
7320 object_mapping[e].direction =
7321 MV_DIR_FROM_BIT(em_object_mapping_list[i].direction);
7324 for (i = 0; em_player_mapping_list[i].action_em != -1; i++)
7326 int a = em_player_mapping_list[i].action_em;
7327 int p = em_player_mapping_list[i].player_nr;
7329 player_mapping[p][a].element_rnd = em_player_mapping_list[i].element_rnd;
7331 if (em_player_mapping_list[i].action != -1)
7332 player_mapping[p][a].action = em_player_mapping_list[i].action;
7334 if (em_player_mapping_list[i].direction != -1)
7335 player_mapping[p][a].direction =
7336 MV_DIR_FROM_BIT(em_player_mapping_list[i].direction);
7339 for (i = 0; i < TILE_MAX; i++)
7341 int element = object_mapping[i].element_rnd;
7342 int action = object_mapping[i].action;
7343 int direction = object_mapping[i].direction;
7344 boolean is_backside = object_mapping[i].is_backside;
7346 boolean action_removing = (action == ACTION_DIGGING ||
7347 action == ACTION_SNAPPING ||
7348 action == ACTION_COLLECTING);
7350 boolean action_exploding = ((action == ACTION_EXPLODING ||
7351 action == ACTION_SMASHED_BY_ROCK ||
7352 action == ACTION_SMASHED_BY_SPRING) &&
7353 element != EL_DIAMOND);
7354 boolean action_active = (action == ACTION_ACTIVE);
7355 boolean action_other = (action == ACTION_OTHER);
7357 for (j = 0; j < 8; j++)
7360 int effective_element = get_effective_element_EM(i, j);
7362 int effective_element = (j > 5 && i == Yacid_splash_eB ? EL_EMPTY :
7363 j > 5 && i == Yacid_splash_wB ? EL_EMPTY :
7365 i == Xdrip_stretch ? element :
7366 i == Xdrip_stretchB ? element :
7367 i == Ydrip_s1 ? element :
7368 i == Ydrip_s1B ? element :
7369 i == Xball_1B ? element :
7370 i == Xball_2 ? element :
7371 i == Xball_2B ? element :
7372 i == Yball_eat ? element :
7373 i == Ykey_1_eat ? element :
7374 i == Ykey_2_eat ? element :
7375 i == Ykey_3_eat ? element :
7376 i == Ykey_4_eat ? element :
7377 i == Ykey_5_eat ? element :
7378 i == Ykey_6_eat ? element :
7379 i == Ykey_7_eat ? element :
7380 i == Ykey_8_eat ? element :
7381 i == Ylenses_eat ? element :
7382 i == Ymagnify_eat ? element :
7383 i == Ygrass_eat ? element :
7384 i == Ydirt_eat ? element :
7385 i == Yemerald_stone ? EL_EMERALD :
7386 i == Ydiamond_stone ? EL_ROCK :
7387 i == Xsand_stonein_1 ? element :
7388 i == Xsand_stonein_2 ? element :
7389 i == Xsand_stonein_3 ? element :
7390 i == Xsand_stonein_4 ? element :
7391 is_backside ? EL_EMPTY :
7392 action_removing ? EL_EMPTY :
7395 int effective_action = (j < 7 ? action :
7396 i == Xdrip_stretch ? action :
7397 i == Xdrip_stretchB ? action :
7398 i == Ydrip_s1 ? action :
7399 i == Ydrip_s1B ? action :
7400 i == Xball_1B ? action :
7401 i == Xball_2 ? action :
7402 i == Xball_2B ? action :
7403 i == Yball_eat ? action :
7404 i == Ykey_1_eat ? action :
7405 i == Ykey_2_eat ? action :
7406 i == Ykey_3_eat ? action :
7407 i == Ykey_4_eat ? action :
7408 i == Ykey_5_eat ? action :
7409 i == Ykey_6_eat ? action :
7410 i == Ykey_7_eat ? action :
7411 i == Ykey_8_eat ? action :
7412 i == Ylenses_eat ? action :
7413 i == Ymagnify_eat ? action :
7414 i == Ygrass_eat ? action :
7415 i == Ydirt_eat ? action :
7416 i == Xsand_stonein_1 ? action :
7417 i == Xsand_stonein_2 ? action :
7418 i == Xsand_stonein_3 ? action :
7419 i == Xsand_stonein_4 ? action :
7420 i == Xsand_stoneout_1 ? action :
7421 i == Xsand_stoneout_2 ? action :
7422 i == Xboom_android ? ACTION_EXPLODING :
7423 action_exploding ? ACTION_EXPLODING :
7424 action_active ? action :
7425 action_other ? action :
7427 int graphic = (el_act_dir2img(effective_element, effective_action,
7429 int crumbled = (el_act_dir2crm(effective_element, effective_action,
7431 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
7432 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
7433 boolean has_action_graphics = (graphic != base_graphic);
7434 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
7435 struct GraphicInfo *g = &graphic_info[graphic];
7437 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
7439 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
7442 /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
7443 boolean special_animation = (action != ACTION_DEFAULT &&
7444 g->anim_frames == 3 &&
7445 g->anim_delay == 2 &&
7446 g->anim_mode & ANIM_LINEAR);
7447 int sync_frame = (i == Xdrip_stretch ? 7 :
7448 i == Xdrip_stretchB ? 7 :
7449 i == Ydrip_s2 ? j + 8 :
7450 i == Ydrip_s2B ? j + 8 :
7459 i == Xfake_acid_1 ? 0 :
7460 i == Xfake_acid_2 ? 10 :
7461 i == Xfake_acid_3 ? 20 :
7462 i == Xfake_acid_4 ? 30 :
7463 i == Xfake_acid_5 ? 40 :
7464 i == Xfake_acid_6 ? 50 :
7465 i == Xfake_acid_7 ? 60 :
7466 i == Xfake_acid_8 ? 70 :
7468 i == Xball_2B ? j + 8 :
7469 i == Yball_eat ? j + 1 :
7470 i == Ykey_1_eat ? j + 1 :
7471 i == Ykey_2_eat ? j + 1 :
7472 i == Ykey_3_eat ? j + 1 :
7473 i == Ykey_4_eat ? j + 1 :
7474 i == Ykey_5_eat ? j + 1 :
7475 i == Ykey_6_eat ? j + 1 :
7476 i == Ykey_7_eat ? j + 1 :
7477 i == Ykey_8_eat ? j + 1 :
7478 i == Ylenses_eat ? j + 1 :
7479 i == Ymagnify_eat ? j + 1 :
7480 i == Ygrass_eat ? j + 1 :
7481 i == Ydirt_eat ? j + 1 :
7482 i == Xamoeba_1 ? 0 :
7483 i == Xamoeba_2 ? 1 :
7484 i == Xamoeba_3 ? 2 :
7485 i == Xamoeba_4 ? 3 :
7486 i == Xamoeba_5 ? 0 :
7487 i == Xamoeba_6 ? 1 :
7488 i == Xamoeba_7 ? 2 :
7489 i == Xamoeba_8 ? 3 :
7490 i == Xexit_2 ? j + 8 :
7491 i == Xexit_3 ? j + 16 :
7492 i == Xdynamite_1 ? 0 :
7493 i == Xdynamite_2 ? 8 :
7494 i == Xdynamite_3 ? 16 :
7495 i == Xdynamite_4 ? 24 :
7496 i == Xsand_stonein_1 ? j + 1 :
7497 i == Xsand_stonein_2 ? j + 9 :
7498 i == Xsand_stonein_3 ? j + 17 :
7499 i == Xsand_stonein_4 ? j + 25 :
7500 i == Xsand_stoneout_1 && j == 0 ? 0 :
7501 i == Xsand_stoneout_1 && j == 1 ? 0 :
7502 i == Xsand_stoneout_1 && j == 2 ? 1 :
7503 i == Xsand_stoneout_1 && j == 3 ? 2 :
7504 i == Xsand_stoneout_1 && j == 4 ? 2 :
7505 i == Xsand_stoneout_1 && j == 5 ? 3 :
7506 i == Xsand_stoneout_1 && j == 6 ? 4 :
7507 i == Xsand_stoneout_1 && j == 7 ? 4 :
7508 i == Xsand_stoneout_2 && j == 0 ? 5 :
7509 i == Xsand_stoneout_2 && j == 1 ? 6 :
7510 i == Xsand_stoneout_2 && j == 2 ? 7 :
7511 i == Xsand_stoneout_2 && j == 3 ? 8 :
7512 i == Xsand_stoneout_2 && j == 4 ? 9 :
7513 i == Xsand_stoneout_2 && j == 5 ? 11 :
7514 i == Xsand_stoneout_2 && j == 6 ? 13 :
7515 i == Xsand_stoneout_2 && j == 7 ? 15 :
7516 i == Xboom_bug && j == 1 ? 2 :
7517 i == Xboom_bug && j == 2 ? 2 :
7518 i == Xboom_bug && j == 3 ? 4 :
7519 i == Xboom_bug && j == 4 ? 4 :
7520 i == Xboom_bug && j == 5 ? 2 :
7521 i == Xboom_bug && j == 6 ? 2 :
7522 i == Xboom_bug && j == 7 ? 0 :
7523 i == Xboom_bomb && j == 1 ? 2 :
7524 i == Xboom_bomb && j == 2 ? 2 :
7525 i == Xboom_bomb && j == 3 ? 4 :
7526 i == Xboom_bomb && j == 4 ? 4 :
7527 i == Xboom_bomb && j == 5 ? 2 :
7528 i == Xboom_bomb && j == 6 ? 2 :
7529 i == Xboom_bomb && j == 7 ? 0 :
7530 i == Xboom_android && j == 7 ? 6 :
7531 i == Xboom_1 && j == 1 ? 2 :
7532 i == Xboom_1 && j == 2 ? 2 :
7533 i == Xboom_1 && j == 3 ? 4 :
7534 i == Xboom_1 && j == 4 ? 4 :
7535 i == Xboom_1 && j == 5 ? 6 :
7536 i == Xboom_1 && j == 6 ? 6 :
7537 i == Xboom_1 && j == 7 ? 8 :
7538 i == Xboom_2 && j == 0 ? 8 :
7539 i == Xboom_2 && j == 1 ? 8 :
7540 i == Xboom_2 && j == 2 ? 10 :
7541 i == Xboom_2 && j == 3 ? 10 :
7542 i == Xboom_2 && j == 4 ? 10 :
7543 i == Xboom_2 && j == 5 ? 12 :
7544 i == Xboom_2 && j == 6 ? 12 :
7545 i == Xboom_2 && j == 7 ? 12 :
7546 special_animation && j == 4 ? 3 :
7547 effective_action != action ? 0 :
7551 Bitmap *debug_bitmap = g_em->bitmap;
7552 int debug_src_x = g_em->src_x;
7553 int debug_src_y = g_em->src_y;
7556 int frame = getAnimationFrame(g->anim_frames,
7559 g->anim_start_frame,
7562 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y,
7563 g->double_movement && is_backside);
7565 g_em->bitmap = src_bitmap;
7566 g_em->src_x = src_x;
7567 g_em->src_y = src_y;
7568 g_em->src_offset_x = 0;
7569 g_em->src_offset_y = 0;
7570 g_em->dst_offset_x = 0;
7571 g_em->dst_offset_y = 0;
7572 g_em->width = TILEX;
7573 g_em->height = TILEY;
7575 g_em->preserve_background = FALSE;
7578 set_crumbled_graphics_EM(g_em, has_crumbled_graphics, crumbled,
7583 g_em->crumbled_bitmap = NULL;
7584 g_em->crumbled_src_x = 0;
7585 g_em->crumbled_src_y = 0;
7586 g_em->crumbled_border_size = 0;
7588 g_em->has_crumbled_graphics = FALSE;
7591 if (has_crumbled_graphics && crumbled == IMG_EMPTY_SPACE)
7592 printf("::: empty crumbled: %d [%s], %d, %d\n",
7593 effective_element, element_info[effective_element].token_name,
7594 effective_action, direction);
7597 /* if element can be crumbled, but certain action graphics are just empty
7598 space (like instantly snapping sand to empty space in 1 frame), do not
7599 treat these empty space graphics as crumbled graphics in EMC engine */
7600 if (has_crumbled_graphics && crumbled != IMG_EMPTY_SPACE)
7602 int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
7603 g_crumbled->anim_delay,
7604 g_crumbled->anim_mode,
7605 g_crumbled->anim_start_frame,
7608 getGraphicSource(crumbled, frame_crumbled, &src_bitmap, &src_x, &src_y);
7610 g_em->has_crumbled_graphics = TRUE;
7611 g_em->crumbled_bitmap = src_bitmap;
7612 g_em->crumbled_src_x = src_x;
7613 g_em->crumbled_src_y = src_y;
7614 g_em->crumbled_border_size = graphic_info[crumbled].border_size;
7618 if (g_em == &graphic_info_em_object[207][0])
7619 printf("... %d, %d [%d, %d, %d, %d] [%d, %d, %d, %d, %d, %d => %d]\n",
7620 graphic_info_em_object[207][0].crumbled_src_x,
7621 graphic_info_em_object[207][0].crumbled_src_y,
7623 crumbled, frame, src_x, src_y,
7628 g->anim_start_frame,
7630 gfx.anim_random_frame,
7635 printf("::: EMC tile %d is crumbled\n", i);
7641 if (element == EL_ROCK &&
7642 effective_action == ACTION_FILLING)
7643 printf("::: has_action_graphics == %d\n", has_action_graphics);
7646 if ((!g->double_movement && (effective_action == ACTION_FALLING ||
7647 effective_action == ACTION_MOVING ||
7648 effective_action == ACTION_PUSHING ||
7649 effective_action == ACTION_EATING)) ||
7650 (!has_action_graphics && (effective_action == ACTION_FILLING ||
7651 effective_action == ACTION_EMPTYING)))
7654 (effective_action == ACTION_FALLING ||
7655 effective_action == ACTION_FILLING ||
7656 effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
7657 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
7658 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? 1 : 0);
7659 int num_steps = (i == Ydrip_s1 ? 16 :
7660 i == Ydrip_s1B ? 16 :
7661 i == Ydrip_s2 ? 16 :
7662 i == Ydrip_s2B ? 16 :
7663 i == Xsand_stonein_1 ? 32 :
7664 i == Xsand_stonein_2 ? 32 :
7665 i == Xsand_stonein_3 ? 32 :
7666 i == Xsand_stonein_4 ? 32 :
7667 i == Xsand_stoneout_1 ? 16 :
7668 i == Xsand_stoneout_2 ? 16 : 8);
7669 int cx = ABS(dx) * (TILEX / num_steps);
7670 int cy = ABS(dy) * (TILEY / num_steps);
7671 int step_frame = (i == Ydrip_s2 ? j + 8 :
7672 i == Ydrip_s2B ? j + 8 :
7673 i == Xsand_stonein_2 ? j + 8 :
7674 i == Xsand_stonein_3 ? j + 16 :
7675 i == Xsand_stonein_4 ? j + 24 :
7676 i == Xsand_stoneout_2 ? j + 8 : j) + 1;
7677 int step = (is_backside ? step_frame : num_steps - step_frame);
7679 if (is_backside) /* tile where movement starts */
7681 if (dx < 0 || dy < 0)
7683 g_em->src_offset_x = cx * step;
7684 g_em->src_offset_y = cy * step;
7688 g_em->dst_offset_x = cx * step;
7689 g_em->dst_offset_y = cy * step;
7692 else /* tile where movement ends */
7694 if (dx < 0 || dy < 0)
7696 g_em->dst_offset_x = cx * step;
7697 g_em->dst_offset_y = cy * step;
7701 g_em->src_offset_x = cx * step;
7702 g_em->src_offset_y = cy * step;
7706 g_em->width = TILEX - cx * step;
7707 g_em->height = TILEY - cy * step;
7710 /* create unique graphic identifier to decide if tile must be redrawn */
7711 /* bit 31 - 16 (16 bit): EM style graphic
7712 bit 15 - 12 ( 4 bit): EM style frame
7713 bit 11 - 6 ( 6 bit): graphic width
7714 bit 5 - 0 ( 6 bit): graphic height */
7715 g_em->unique_identifier =
7716 (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
7720 /* skip check for EMC elements not contained in original EMC artwork */
7721 if (element == EL_EMC_FAKE_ACID)
7724 if (g_em->bitmap != debug_bitmap ||
7725 g_em->src_x != debug_src_x ||
7726 g_em->src_y != debug_src_y ||
7727 g_em->src_offset_x != 0 ||
7728 g_em->src_offset_y != 0 ||
7729 g_em->dst_offset_x != 0 ||
7730 g_em->dst_offset_y != 0 ||
7731 g_em->width != TILEX ||
7732 g_em->height != TILEY)
7734 static int last_i = -1;
7742 printf("::: EMC GFX ERROR for element %d -> %d ('%s', '%s', %d)",
7743 i, element, element_info[element].token_name,
7744 element_action_info[effective_action].suffix, direction);
7746 if (element != effective_element)
7747 printf(" [%d ('%s')]",
7749 element_info[effective_element].token_name);
7753 if (g_em->bitmap != debug_bitmap)
7754 printf(" %d (%d): different bitmap! (0x%08x != 0x%08x)\n",
7755 j, is_backside, (int)(g_em->bitmap), (int)(debug_bitmap));
7757 if (g_em->src_x != debug_src_x ||
7758 g_em->src_y != debug_src_y)
7759 printf(" frame %d (%c): %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
7760 j, (is_backside ? 'B' : 'F'),
7761 g_em->src_x, g_em->src_y,
7762 g_em->src_x / 32, g_em->src_y / 32,
7763 debug_src_x, debug_src_y,
7764 debug_src_x / 32, debug_src_y / 32);
7766 if (g_em->src_offset_x != 0 ||
7767 g_em->src_offset_y != 0 ||
7768 g_em->dst_offset_x != 0 ||
7769 g_em->dst_offset_y != 0)
7770 printf(" %d (%d): offsets %d,%d and %d,%d should be all 0\n",
7772 g_em->src_offset_x, g_em->src_offset_y,
7773 g_em->dst_offset_x, g_em->dst_offset_y);
7775 if (g_em->width != TILEX ||
7776 g_em->height != TILEY)
7777 printf(" %d (%d): size %d,%d should be %d,%d\n",
7779 g_em->width, g_em->height, TILEX, TILEY);
7781 num_em_gfx_errors++;
7788 for (i = 0; i < TILE_MAX; i++)
7790 for (j = 0; j < 8; j++)
7792 int element = object_mapping[i].element_rnd;
7793 int action = object_mapping[i].action;
7794 int direction = object_mapping[i].direction;
7795 boolean is_backside = object_mapping[i].is_backside;
7796 int graphic_action = el_act_dir2img(element, action, direction);
7797 int graphic_default = el_act_dir2img(element, ACTION_DEFAULT, direction);
7799 if ((action == ACTION_SMASHED_BY_ROCK ||
7800 action == ACTION_SMASHED_BY_SPRING ||
7801 action == ACTION_EATING) &&
7802 graphic_action == graphic_default)
7804 int e = (action == ACTION_SMASHED_BY_ROCK ? Ystone_s :
7805 action == ACTION_SMASHED_BY_SPRING ? Yspring_s :
7806 direction == MV_LEFT ? (is_backside? Yspring_wB: Yspring_w) :
7807 direction == MV_RIGHT ? (is_backside? Yspring_eB: Yspring_e) :
7810 /* no separate animation for "smashed by rock" -- use rock instead */
7811 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
7812 struct GraphicInfo_EM *g_xx = &graphic_info_em_object[e][7 - j];
7814 g_em->bitmap = g_xx->bitmap;
7815 g_em->src_x = g_xx->src_x;
7816 g_em->src_y = g_xx->src_y;
7817 g_em->src_offset_x = g_xx->src_offset_x;
7818 g_em->src_offset_y = g_xx->src_offset_y;
7819 g_em->dst_offset_x = g_xx->dst_offset_x;
7820 g_em->dst_offset_y = g_xx->dst_offset_y;
7821 g_em->width = g_xx->width;
7822 g_em->height = g_xx->height;
7823 g_em->unique_identifier = g_xx->unique_identifier;
7826 g_em->preserve_background = TRUE;
7831 for (p = 0; p < MAX_PLAYERS; p++)
7833 for (i = 0; i < SPR_MAX; i++)
7835 int element = player_mapping[p][i].element_rnd;
7836 int action = player_mapping[p][i].action;
7837 int direction = player_mapping[p][i].direction;
7839 for (j = 0; j < 8; j++)
7841 int effective_element = element;
7842 int effective_action = action;
7843 int graphic = (direction == MV_NONE ?
7844 el_act2img(effective_element, effective_action) :
7845 el_act_dir2img(effective_element, effective_action,
7847 struct GraphicInfo *g = &graphic_info[graphic];
7848 struct GraphicInfo_EM *g_em = &graphic_info_em_player[p][i][7 - j];
7854 Bitmap *debug_bitmap = g_em->bitmap;
7855 int debug_src_x = g_em->src_x;
7856 int debug_src_y = g_em->src_y;
7859 int frame = getAnimationFrame(g->anim_frames,
7862 g->anim_start_frame,
7865 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
7867 g_em->bitmap = src_bitmap;
7868 g_em->src_x = src_x;
7869 g_em->src_y = src_y;
7870 g_em->src_offset_x = 0;
7871 g_em->src_offset_y = 0;
7872 g_em->dst_offset_x = 0;
7873 g_em->dst_offset_y = 0;
7874 g_em->width = TILEX;
7875 g_em->height = TILEY;
7879 /* skip check for EMC elements not contained in original EMC artwork */
7880 if (element == EL_PLAYER_3 ||
7881 element == EL_PLAYER_4)
7884 if (g_em->bitmap != debug_bitmap ||
7885 g_em->src_x != debug_src_x ||
7886 g_em->src_y != debug_src_y)
7888 static int last_i = -1;
7896 printf("::: EMC GFX ERROR for p/a %d/%d -> %d ('%s', '%s', %d)",
7897 p, i, element, element_info[element].token_name,
7898 element_action_info[effective_action].suffix, direction);
7900 if (element != effective_element)
7901 printf(" [%d ('%s')]",
7903 element_info[effective_element].token_name);
7907 if (g_em->bitmap != debug_bitmap)
7908 printf(" %d: different bitmap! (0x%08x != 0x%08x)\n",
7909 j, (int)(g_em->bitmap), (int)(debug_bitmap));
7911 if (g_em->src_x != debug_src_x ||
7912 g_em->src_y != debug_src_y)
7913 printf(" frame %d: %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
7915 g_em->src_x, g_em->src_y,
7916 g_em->src_x / 32, g_em->src_y / 32,
7917 debug_src_x, debug_src_y,
7918 debug_src_x / 32, debug_src_y / 32);
7920 num_em_gfx_errors++;
7930 printf("::: [%d errors found]\n", num_em_gfx_errors);
7936 void getGraphicSource_SP(struct GraphicInfo_SP *g_sp,
7937 int graphic, int sync_frame, int x, int y)
7939 int frame = getGraphicAnimationFrame(graphic, sync_frame);
7941 getGraphicSource(graphic, frame, &g_sp->bitmap, &g_sp->src_x, &g_sp->src_y);
7944 boolean isNextAnimationFrame_SP(int graphic, int sync_frame)
7946 return (IS_NEXT_FRAME(sync_frame, graphic));
7949 int getGraphicInfo_Delay(int graphic)
7951 return graphic_info[graphic].anim_delay;
7954 void PlayMenuSoundExt(int sound)
7956 if (sound == SND_UNDEFINED)
7959 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
7960 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
7963 if (IS_LOOP_SOUND(sound))
7964 PlaySoundLoop(sound);
7969 void PlayMenuSound()
7971 PlayMenuSoundExt(menu.sound[game_status]);
7974 void PlayMenuSoundStereo(int sound, int stereo_position)
7976 if (sound == SND_UNDEFINED)
7979 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
7980 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
7983 if (IS_LOOP_SOUND(sound))
7984 PlaySoundExt(sound, SOUND_MAX_VOLUME, stereo_position, SND_CTRL_PLAY_LOOP);
7986 PlaySoundStereo(sound, stereo_position);
7989 void PlayMenuSoundIfLoopExt(int sound)
7991 if (sound == SND_UNDEFINED)
7994 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
7995 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
7998 if (IS_LOOP_SOUND(sound))
7999 PlaySoundLoop(sound);
8002 void PlayMenuSoundIfLoop()
8004 PlayMenuSoundIfLoopExt(menu.sound[game_status]);
8007 void PlayMenuMusicExt(int music)
8009 if (music == MUS_UNDEFINED)
8012 if (!setup.sound_music)
8018 void PlayMenuMusic()
8020 PlayMenuMusicExt(menu.music[game_status]);
8023 void PlaySoundActivating()
8026 PlaySound(SND_MENU_ITEM_ACTIVATING);
8030 void PlaySoundSelecting()
8033 PlaySound(SND_MENU_ITEM_SELECTING);
8037 void ToggleFullscreenIfNeeded()
8039 boolean change_fullscreen = (setup.fullscreen !=
8040 video.fullscreen_enabled);
8041 boolean change_fullscreen_mode = (video.fullscreen_enabled &&
8042 !strEqual(setup.fullscreen_mode,
8043 video.fullscreen_mode_current));
8045 if (!video.fullscreen_available)
8049 if (change_fullscreen || change_fullscreen_mode)
8051 if (setup.fullscreen != video.fullscreen_enabled ||
8052 setup.fullscreen_mode != video.fullscreen_mode_current)
8055 Bitmap *tmp_backbuffer = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
8057 /* save backbuffer content which gets lost when toggling fullscreen mode */
8058 BlitBitmap(backbuffer, tmp_backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
8061 if (change_fullscreen_mode)
8063 if (setup.fullscreen && video.fullscreen_enabled)
8066 /* keep fullscreen, but change fullscreen mode (screen resolution) */
8068 /* (this is now set in sdl.c) */
8070 video.fullscreen_mode_current = setup.fullscreen_mode;
8072 video.fullscreen_enabled = FALSE; /* force new fullscreen mode */
8075 /* toggle fullscreen */
8076 ChangeVideoModeIfNeeded(setup.fullscreen);
8078 setup.fullscreen = video.fullscreen_enabled;
8080 /* restore backbuffer content from temporary backbuffer backup bitmap */
8081 BlitBitmap(tmp_backbuffer, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
8083 FreeBitmap(tmp_backbuffer);
8086 /* update visible window/screen */
8087 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
8089 redraw_mask = REDRAW_ALL;