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 DrawLevelFieldCrumbledSandExt(int x, int y, int graphic, int frame)
1449 int sx = SCREENX(x), sy = SCREENY(y);
1451 int width, height, cx, cy, i;
1452 int crumbled_border_size = graphic_info[graphic].border_size;
1453 static int xy[4][2] =
1461 if (!IN_LEV_FIELD(x, y))
1464 element = TILE_GFX_ELEMENT(x, y);
1466 /* crumble field itself */
1468 if (IS_CRUMBLED_TILE(x, y, element))
1470 if (GFX_CRUMBLED(element) && !IS_MOVING(x, y))
1473 if (!IN_SCR_FIELD(sx, sy))
1476 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1478 for (i = 0; i < 4; i++)
1480 int xx = x + xy[i][0];
1481 int yy = y + xy[i][1];
1483 element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1486 /* check if neighbour field is of same type */
1488 if (IS_CRUMBLED_TILE(xx, yy, element))
1491 if (GFX_CRUMBLED(element) && !IS_MOVING(xx, yy))
1495 if (i == 1 || i == 2)
1497 width = crumbled_border_size;
1499 cx = (i == 2 ? TILEX - crumbled_border_size : 0);
1505 height = crumbled_border_size;
1507 cy = (i == 3 ? TILEY - crumbled_border_size : 0);
1510 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1511 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
1514 MarkTileDirty(sx, sy);
1516 else /* crumble neighbour fields */
1518 for (i = 0; i < 4; i++)
1520 int xx = x + xy[i][0];
1521 int yy = y + xy[i][1];
1522 int sxx = sx + xy[i][0];
1523 int syy = sy + xy[i][1];
1526 if (!IN_LEV_FIELD(xx, yy) ||
1527 !IN_SCR_FIELD(sxx, syy))
1530 if (!IN_LEV_FIELD(xx, yy) ||
1531 !IN_SCR_FIELD(sxx, syy) ||
1536 if (Feld[xx][yy] == EL_ELEMENT_SNAPPING)
1539 element = TILE_GFX_ELEMENT(xx, yy);
1542 if (!IS_CRUMBLED_TILE(xx, yy, element))
1545 if (!GFX_CRUMBLED(element))
1549 graphic = el_act2crm(element, ACTION_DEFAULT);
1550 crumbled_border_size = graphic_info[graphic].border_size;
1552 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1554 if (i == 1 || i == 2)
1556 width = crumbled_border_size;
1558 cx = (i == 1 ? TILEX - crumbled_border_size : 0);
1564 height = crumbled_border_size;
1566 cy = (i == 0 ? TILEY - crumbled_border_size : 0);
1569 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1570 width, height, FX + sxx * TILEX + cx, FY + syy * TILEY + cy);
1572 MarkTileDirty(sxx, syy);
1577 void DrawLevelFieldCrumbledSand(int x, int y)
1581 if (!IN_LEV_FIELD(x, y))
1585 /* !!! CHECK THIS !!! */
1588 if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
1589 GFX_CRUMBLED(GfxElement[x][y]))
1592 if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
1593 GfxElement[x][y] != EL_UNDEFINED &&
1594 GFX_CRUMBLED(GfxElement[x][y]))
1596 DrawLevelFieldCrumbledSandDigging(x, y, GfxDir[x][y], GfxFrame[x][y]);
1603 graphic = el_act2crm(TILE_GFX_ELEMENT(x, y), ACTION_DEFAULT);
1605 graphic = el_act2crm(Feld[x][y], ACTION_DEFAULT);
1608 DrawLevelFieldCrumbledSandExt(x, y, graphic, 0);
1611 void DrawLevelFieldCrumbledSandDigging(int x, int y, int direction,
1614 int graphic1 = el_act_dir2img(GfxElement[x][y], ACTION_DIGGING, direction);
1615 int graphic2 = el_act_dir2crm(GfxElement[x][y], ACTION_DIGGING, direction);
1616 int frame1 = getGraphicAnimationFrame(graphic1, step_frame);
1617 int frame2 = getGraphicAnimationFrame(graphic2, step_frame);
1618 int sx = SCREENX(x), sy = SCREENY(y);
1620 DrawGraphic(sx, sy, graphic1, frame1);
1621 DrawLevelFieldCrumbledSandExt(x, y, graphic2, frame2);
1624 void DrawLevelFieldCrumbledSandNeighbours(int x, int y)
1626 int sx = SCREENX(x), sy = SCREENY(y);
1627 static int xy[4][2] =
1636 for (i = 0; i < 4; i++)
1638 int xx = x + xy[i][0];
1639 int yy = y + xy[i][1];
1640 int sxx = sx + xy[i][0];
1641 int syy = sy + xy[i][1];
1643 if (!IN_LEV_FIELD(xx, yy) ||
1644 !IN_SCR_FIELD(sxx, syy) ||
1645 !GFX_CRUMBLED(Feld[xx][yy]) ||
1649 DrawLevelField(xx, yy);
1653 static int getBorderElement(int x, int y)
1657 { EL_STEELWALL_TOPLEFT, EL_INVISIBLE_STEELWALL_TOPLEFT },
1658 { EL_STEELWALL_TOPRIGHT, EL_INVISIBLE_STEELWALL_TOPRIGHT },
1659 { EL_STEELWALL_BOTTOMLEFT, EL_INVISIBLE_STEELWALL_BOTTOMLEFT },
1660 { EL_STEELWALL_BOTTOMRIGHT, EL_INVISIBLE_STEELWALL_BOTTOMRIGHT },
1661 { EL_STEELWALL_VERTICAL, EL_INVISIBLE_STEELWALL_VERTICAL },
1662 { EL_STEELWALL_HORIZONTAL, EL_INVISIBLE_STEELWALL_HORIZONTAL },
1663 { EL_STEELWALL, EL_INVISIBLE_STEELWALL }
1665 int steel_type = (BorderElement == EL_STEELWALL ? 0 : 1);
1666 int steel_position = (x == -1 && y == -1 ? 0 :
1667 x == lev_fieldx && y == -1 ? 1 :
1668 x == -1 && y == lev_fieldy ? 2 :
1669 x == lev_fieldx && y == lev_fieldy ? 3 :
1670 x == -1 || x == lev_fieldx ? 4 :
1671 y == -1 || y == lev_fieldy ? 5 : 6);
1673 return border[steel_position][steel_type];
1676 void DrawScreenElement(int x, int y, int element)
1678 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
1679 DrawLevelFieldCrumbledSand(LEVELX(x), LEVELY(y));
1682 void DrawLevelElement(int x, int y, int element)
1684 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1685 DrawScreenElement(SCREENX(x), SCREENY(y), element);
1688 void DrawScreenField(int x, int y)
1690 int lx = LEVELX(x), ly = LEVELY(y);
1691 int element, content;
1693 if (!IN_LEV_FIELD(lx, ly))
1695 if (lx < -1 || lx > lev_fieldx || ly < -1 || ly > lev_fieldy)
1698 element = getBorderElement(lx, ly);
1700 DrawScreenElement(x, y, element);
1705 element = Feld[lx][ly];
1706 content = Store[lx][ly];
1708 if (IS_MOVING(lx, ly))
1710 int horiz_move = (MovDir[lx][ly] == MV_LEFT || MovDir[lx][ly] == MV_RIGHT);
1711 boolean cut_mode = NO_CUTTING;
1713 if (element == EL_QUICKSAND_EMPTYING ||
1714 element == EL_QUICKSAND_FAST_EMPTYING ||
1715 element == EL_MAGIC_WALL_EMPTYING ||
1716 element == EL_BD_MAGIC_WALL_EMPTYING ||
1717 element == EL_DC_MAGIC_WALL_EMPTYING ||
1718 element == EL_AMOEBA_DROPPING)
1719 cut_mode = CUT_ABOVE;
1720 else if (element == EL_QUICKSAND_FILLING ||
1721 element == EL_QUICKSAND_FAST_FILLING ||
1722 element == EL_MAGIC_WALL_FILLING ||
1723 element == EL_BD_MAGIC_WALL_FILLING ||
1724 element == EL_DC_MAGIC_WALL_FILLING)
1725 cut_mode = CUT_BELOW;
1728 if (lx == 9 && ly == 1)
1729 printf("::: %s [%d] [%d, %d] [%d]\n",
1730 EL_NAME(TILE_GFX_ELEMENT(lx, ly)),
1731 el_act2crm(TILE_GFX_ELEMENT(lx, ly), ACTION_DEFAULT),
1732 element_info[EL_QUICKSAND_EMPTYING].graphic[ACTION_DEFAULT],
1733 element_info[EL_QUICKSAND_EMPTYING].crumbled[ACTION_DEFAULT],
1734 GFX_CRUMBLED(TILE_GFX_ELEMENT(lx, ly)));
1737 if (cut_mode == CUT_ABOVE)
1739 DrawScreenElement(x, y, element);
1741 DrawScreenElementShifted(x, y, 0, 0, element, NO_CUTTING);
1744 DrawScreenElement(x, y, EL_EMPTY);
1747 DrawScreenElementShifted(x, y, MovPos[lx][ly], 0, element, NO_CUTTING);
1748 else if (cut_mode == NO_CUTTING)
1749 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], element, cut_mode);
1752 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], content, cut_mode);
1755 if (cut_mode == CUT_BELOW &&
1756 IN_LEV_FIELD(lx, ly + 1) && IN_SCR_FIELD(x, y + 1))
1757 DrawLevelElement(lx, ly + 1, element);
1761 if (content == EL_ACID)
1763 int dir = MovDir[lx][ly];
1764 int newlx = lx + (dir == MV_LEFT ? -1 : dir == MV_RIGHT ? +1 : 0);
1765 int newly = ly + (dir == MV_UP ? -1 : dir == MV_DOWN ? +1 : 0);
1767 DrawLevelElementThruMask(newlx, newly, EL_ACID);
1770 else if (IS_BLOCKED(lx, ly))
1775 boolean cut_mode = NO_CUTTING;
1776 int element_old, content_old;
1778 Blocked2Moving(lx, ly, &oldx, &oldy);
1781 horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
1782 MovDir[oldx][oldy] == MV_RIGHT);
1784 element_old = Feld[oldx][oldy];
1785 content_old = Store[oldx][oldy];
1787 if (element_old == EL_QUICKSAND_EMPTYING ||
1788 element_old == EL_QUICKSAND_FAST_EMPTYING ||
1789 element_old == EL_MAGIC_WALL_EMPTYING ||
1790 element_old == EL_BD_MAGIC_WALL_EMPTYING ||
1791 element_old == EL_DC_MAGIC_WALL_EMPTYING ||
1792 element_old == EL_AMOEBA_DROPPING)
1793 cut_mode = CUT_ABOVE;
1795 DrawScreenElement(x, y, EL_EMPTY);
1798 DrawScreenElementShifted(sx, sy, MovPos[oldx][oldy], 0, element_old,
1800 else if (cut_mode == NO_CUTTING)
1801 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], element_old,
1804 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], content_old,
1807 else if (IS_DRAWABLE(element))
1808 DrawScreenElement(x, y, element);
1810 DrawScreenElement(x, y, EL_EMPTY);
1813 void DrawLevelField(int x, int y)
1815 if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1816 DrawScreenField(SCREENX(x), SCREENY(y));
1817 else if (IS_MOVING(x, y))
1821 Moving2Blocked(x, y, &newx, &newy);
1822 if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
1823 DrawScreenField(SCREENX(newx), SCREENY(newy));
1825 else if (IS_BLOCKED(x, y))
1829 Blocked2Moving(x, y, &oldx, &oldy);
1830 if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
1831 DrawScreenField(SCREENX(oldx), SCREENY(oldy));
1835 void DrawMiniElement(int x, int y, int element)
1839 graphic = el2edimg(element);
1840 DrawMiniGraphic(x, y, graphic);
1843 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
1845 int x = sx + scroll_x, y = sy + scroll_y;
1847 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
1848 DrawMiniElement(sx, sy, EL_EMPTY);
1849 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
1850 DrawMiniElement(sx, sy, Feld[x][y]);
1852 DrawMiniGraphic(sx, sy, el2edimg(getBorderElement(x, y)));
1855 void DrawEnvelopeBackground(int envelope_nr, int startx, int starty,
1856 int x, int y, int xsize, int ysize, int font_nr)
1858 int font_width = getFontWidth(font_nr);
1859 int font_height = getFontHeight(font_nr);
1860 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1863 int dst_x = SX + startx + x * font_width;
1864 int dst_y = SY + starty + y * font_height;
1865 int width = graphic_info[graphic].width;
1866 int height = graphic_info[graphic].height;
1867 int inner_width = MAX(width - 2 * font_width, font_width);
1868 int inner_height = MAX(height - 2 * font_height, font_height);
1869 int inner_sx = (width >= 3 * font_width ? font_width : 0);
1870 int inner_sy = (height >= 3 * font_height ? font_height : 0);
1871 boolean draw_masked = graphic_info[graphic].draw_masked;
1873 getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
1875 if (src_bitmap == NULL || width < font_width || height < font_height)
1877 ClearRectangle(drawto, dst_x, dst_y, font_width, font_height);
1881 src_x += (x == 0 ? 0 : x == xsize - 1 ? width - font_width :
1882 inner_sx + (x - 1) * font_width % inner_width);
1883 src_y += (y == 0 ? 0 : y == ysize - 1 ? height - font_height :
1884 inner_sy + (y - 1) * font_height % inner_height);
1888 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1889 dst_x - src_x, dst_y - src_y);
1890 BlitBitmapMasked(src_bitmap, drawto, src_x, src_y, font_width, font_height,
1894 BlitBitmap(src_bitmap, drawto, src_x, src_y, font_width, font_height,
1898 void AnimateEnvelope(int envelope_nr, int anim_mode, int action)
1900 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1901 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
1902 int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
1903 boolean ffwd_delay = (tape.playing && tape.fast_forward);
1904 boolean no_delay = (tape.warp_forward);
1905 unsigned long anim_delay = 0;
1906 int frame_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
1907 int anim_delay_value = (no_delay ? 0 : frame_delay_value);
1908 int font_nr = FONT_ENVELOPE_1 + envelope_nr;
1909 int font_width = getFontWidth(font_nr);
1910 int font_height = getFontHeight(font_nr);
1911 int max_xsize = level.envelope[envelope_nr].xsize;
1912 int max_ysize = level.envelope[envelope_nr].ysize;
1913 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize : 0);
1914 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize : 0);
1915 int xend = max_xsize;
1916 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize : 0);
1917 int xstep = (xstart < xend ? 1 : 0);
1918 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
1921 for (x = xstart, y = ystart; x <= xend && y <= yend; x += xstep, y += ystep)
1923 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
1924 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
1925 int sx = (SXSIZE - xsize * font_width) / 2;
1926 int sy = (SYSIZE - ysize * font_height) / 2;
1929 SetDrawtoField(DRAW_BUFFERED);
1931 BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
1933 SetDrawtoField(DRAW_BACKBUFFER);
1935 for (yy = 0; yy < ysize; yy++) for (xx = 0; xx < xsize; xx++)
1936 DrawEnvelopeBackground(envelope_nr, sx,sy, xx,yy, xsize, ysize, font_nr);
1939 DrawTextBuffer(SX + sx + font_width, SY + sy + font_height,
1940 level.envelope[envelope_nr].text, font_nr, max_xsize,
1941 xsize - 2, ysize - 2, mask_mode,
1942 level.envelope[envelope_nr].autowrap,
1943 level.envelope[envelope_nr].centered, FALSE);
1945 DrawTextToTextArea(SX + sx + font_width, SY + sy + font_height,
1946 level.envelope[envelope_nr].text, font_nr, max_xsize,
1947 xsize - 2, ysize - 2, mask_mode);
1950 redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
1953 WaitUntilDelayReached(&anim_delay, anim_delay_value / 2);
1957 void ShowEnvelope(int envelope_nr)
1959 int element = EL_ENVELOPE_1 + envelope_nr;
1960 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1961 int sound_opening = element_info[element].sound[ACTION_OPENING];
1962 int sound_closing = element_info[element].sound[ACTION_CLOSING];
1963 boolean ffwd_delay = (tape.playing && tape.fast_forward);
1964 boolean no_delay = (tape.warp_forward);
1965 int normal_delay_value = ONE_SECOND_DELAY / (ffwd_delay ? 2 : 1);
1966 int wait_delay_value = (no_delay ? 0 : normal_delay_value);
1967 int anim_mode = graphic_info[graphic].anim_mode;
1968 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
1969 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
1971 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
1973 PlayMenuSoundStereo(sound_opening, SOUND_MIDDLE);
1975 if (anim_mode == ANIM_DEFAULT)
1976 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_OPENING);
1978 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_OPENING);
1981 Delay(wait_delay_value);
1983 WaitForEventToContinue();
1985 PlayMenuSoundStereo(sound_closing, SOUND_MIDDLE);
1987 if (anim_mode != ANIM_NONE)
1988 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_CLOSING);
1990 if (anim_mode == ANIM_DEFAULT)
1991 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_CLOSING);
1993 game.envelope_active = FALSE;
1995 SetDrawtoField(DRAW_BUFFERED);
1997 redraw_mask |= REDRAW_FIELD;
2001 void DrawPreviewElement(int dst_x, int dst_y, int element, int tilesize)
2005 int graphic = el2preimg(element);
2007 getSizedGraphicSource(graphic, 0, tilesize, &src_bitmap, &src_x, &src_y);
2008 BlitBitmap(src_bitmap, drawto, src_x, src_y, tilesize, tilesize, dst_x,dst_y);
2016 SetMainBackgroundImage(IMG_BACKGROUND_PLAYING);
2017 SetDrawBackgroundMask(REDRAW_FIELD);
2019 SetDrawBackgroundMask(REDRAW_NONE);
2024 for (x = BX1; x <= BX2; x++)
2025 for (y = BY1; y <= BY2; y++)
2026 DrawScreenField(x, y);
2028 redraw_mask |= REDRAW_FIELD;
2031 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
2035 for (x = 0; x < size_x; x++)
2036 for (y = 0; y < size_y; y++)
2037 DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
2039 redraw_mask |= REDRAW_FIELD;
2042 static void DrawPreviewLevelExt(int from_x, int from_y)
2044 boolean show_level_border = (BorderElement != EL_EMPTY);
2045 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
2046 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
2047 int tile_size = preview.tile_size;
2048 int preview_width = preview.xsize * tile_size;
2049 int preview_height = preview.ysize * tile_size;
2050 int real_preview_xsize = MIN(level_xsize, preview.xsize);
2051 int real_preview_ysize = MIN(level_ysize, preview.ysize);
2052 int dst_x = SX + ALIGNED_XPOS(preview.x, preview_width, preview.align);
2053 int dst_y = SY + ALIGNED_YPOS(preview.y, preview_height, preview.valign);
2056 DrawBackground(dst_x, dst_y, preview_width, preview_height);
2058 dst_x += (preview_width - real_preview_xsize * tile_size) / 2;
2059 dst_y += (preview_height - real_preview_ysize * tile_size) / 2;
2061 for (x = 0; x < real_preview_xsize; x++)
2063 for (y = 0; y < real_preview_ysize; y++)
2065 int lx = from_x + x + (show_level_border ? -1 : 0);
2066 int ly = from_y + y + (show_level_border ? -1 : 0);
2067 int element = (IN_LEV_FIELD(lx, ly) ? level.field[lx][ly] :
2068 getBorderElement(lx, ly));
2070 DrawPreviewElement(dst_x + x * tile_size, dst_y + y * tile_size,
2071 element, tile_size);
2075 redraw_mask |= REDRAW_MICROLEVEL;
2078 #define MICROLABEL_EMPTY 0
2079 #define MICROLABEL_LEVEL_NAME 1
2080 #define MICROLABEL_LEVEL_AUTHOR_HEAD 2
2081 #define MICROLABEL_LEVEL_AUTHOR 3
2082 #define MICROLABEL_IMPORTED_FROM_HEAD 4
2083 #define MICROLABEL_IMPORTED_FROM 5
2084 #define MICROLABEL_IMPORTED_BY_HEAD 6
2085 #define MICROLABEL_IMPORTED_BY 7
2087 static int getMaxTextLength(struct TextPosInfo *pos, int font_nr)
2089 int max_text_width = SXSIZE;
2090 int font_width = getFontWidth(font_nr);
2092 if (pos->align == ALIGN_CENTER)
2093 max_text_width = (pos->x < SXSIZE / 2 ? pos->x * 2 : (SXSIZE - pos->x) * 2);
2094 else if (pos->align == ALIGN_RIGHT)
2095 max_text_width = pos->x;
2097 max_text_width = SXSIZE - pos->x;
2099 return max_text_width / font_width;
2102 static void DrawPreviewLevelLabelExt(int mode)
2104 struct TextPosInfo *pos = &menu.main.text.level_info_2;
2105 char label_text[MAX_OUTPUT_LINESIZE + 1];
2106 int max_len_label_text;
2108 int font_nr = pos->font;
2111 if (mode == MICROLABEL_LEVEL_AUTHOR_HEAD ||
2112 mode == MICROLABEL_IMPORTED_FROM_HEAD ||
2113 mode == MICROLABEL_IMPORTED_BY_HEAD)
2114 font_nr = pos->font_alt;
2116 int font_nr = FONT_TEXT_2;
2119 if (mode == MICROLABEL_LEVEL_AUTHOR_HEAD ||
2120 mode == MICROLABEL_IMPORTED_FROM_HEAD ||
2121 mode == MICROLABEL_IMPORTED_BY_HEAD)
2122 font_nr = FONT_TEXT_3;
2126 max_len_label_text = getMaxTextLength(pos, font_nr);
2128 max_len_label_text = SXSIZE / getFontWidth(font_nr);
2132 if (pos->size != -1)
2133 max_len_label_text = pos->size;
2136 for (i = 0; i < max_len_label_text; i++)
2137 label_text[i] = ' ';
2138 label_text[max_len_label_text] = '\0';
2140 if (strlen(label_text) > 0)
2143 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
2145 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
2146 int lypos = MICROLABEL2_YPOS;
2148 DrawText(lxpos, lypos, label_text, font_nr);
2153 (mode == MICROLABEL_LEVEL_NAME ? level.name :
2154 mode == MICROLABEL_LEVEL_AUTHOR_HEAD ? "created by" :
2155 mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
2156 mode == MICROLABEL_IMPORTED_FROM_HEAD ? "imported from" :
2157 mode == MICROLABEL_IMPORTED_FROM ? leveldir_current->imported_from :
2158 mode == MICROLABEL_IMPORTED_BY_HEAD ? "imported by" :
2159 mode == MICROLABEL_IMPORTED_BY ? leveldir_current->imported_by :""),
2160 max_len_label_text);
2161 label_text[max_len_label_text] = '\0';
2163 if (strlen(label_text) > 0)
2166 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
2168 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
2169 int lypos = MICROLABEL2_YPOS;
2171 DrawText(lxpos, lypos, label_text, font_nr);
2175 redraw_mask |= REDRAW_MICROLEVEL;
2178 void DrawPreviewLevel(boolean restart)
2180 static unsigned long scroll_delay = 0;
2181 static unsigned long label_delay = 0;
2182 static int from_x, from_y, scroll_direction;
2183 static int label_state, label_counter;
2184 unsigned long scroll_delay_value = preview.step_delay;
2185 boolean show_level_border = (BorderElement != EL_EMPTY);
2186 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
2187 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
2188 int last_game_status = game_status; /* save current game status */
2191 /* force PREVIEW font on preview level */
2192 game_status = GAME_MODE_PSEUDO_PREVIEW;
2200 if (preview.anim_mode == ANIM_CENTERED)
2202 if (level_xsize > preview.xsize)
2203 from_x = (level_xsize - preview.xsize) / 2;
2204 if (level_ysize > preview.ysize)
2205 from_y = (level_ysize - preview.ysize) / 2;
2208 from_x += preview.xoffset;
2209 from_y += preview.yoffset;
2211 scroll_direction = MV_RIGHT;
2215 DrawPreviewLevelExt(from_x, from_y);
2216 DrawPreviewLevelLabelExt(label_state);
2218 /* initialize delay counters */
2219 DelayReached(&scroll_delay, 0);
2220 DelayReached(&label_delay, 0);
2222 if (leveldir_current->name)
2224 struct TextPosInfo *pos = &menu.main.text.level_info_1;
2225 char label_text[MAX_OUTPUT_LINESIZE + 1];
2227 int font_nr = pos->font;
2229 int font_nr = FONT_TEXT_1;
2232 int max_len_label_text = getMaxTextLength(pos, font_nr);
2234 int max_len_label_text = SXSIZE / getFontWidth(font_nr);
2242 if (pos->size != -1)
2243 max_len_label_text = pos->size;
2246 strncpy(label_text, leveldir_current->name, max_len_label_text);
2247 label_text[max_len_label_text] = '\0';
2250 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
2252 lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
2253 lypos = SY + MICROLABEL1_YPOS;
2255 DrawText(lxpos, lypos, label_text, font_nr);
2259 game_status = last_game_status; /* restore current game status */
2264 /* scroll preview level, if needed */
2265 if (preview.anim_mode != ANIM_NONE &&
2266 (level_xsize > preview.xsize || level_ysize > preview.ysize) &&
2267 DelayReached(&scroll_delay, scroll_delay_value))
2269 switch (scroll_direction)
2274 from_x -= preview.step_offset;
2275 from_x = (from_x < 0 ? 0 : from_x);
2278 scroll_direction = MV_UP;
2282 if (from_x < level_xsize - preview.xsize)
2284 from_x += preview.step_offset;
2285 from_x = (from_x > level_xsize - preview.xsize ?
2286 level_xsize - preview.xsize : from_x);
2289 scroll_direction = MV_DOWN;
2295 from_y -= preview.step_offset;
2296 from_y = (from_y < 0 ? 0 : from_y);
2299 scroll_direction = MV_RIGHT;
2303 if (from_y < level_ysize - preview.ysize)
2305 from_y += preview.step_offset;
2306 from_y = (from_y > level_ysize - preview.ysize ?
2307 level_ysize - preview.ysize : from_y);
2310 scroll_direction = MV_LEFT;
2317 DrawPreviewLevelExt(from_x, from_y);
2320 /* !!! THIS ALL SUCKS -- SHOULD BE CLEANLY REWRITTEN !!! */
2321 /* redraw micro level label, if needed */
2322 if (!strEqual(level.name, NAMELESS_LEVEL_NAME) &&
2323 !strEqual(level.author, ANONYMOUS_NAME) &&
2324 !strEqual(level.author, leveldir_current->name) &&
2325 DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
2327 int max_label_counter = 23;
2329 if (leveldir_current->imported_from != NULL &&
2330 strlen(leveldir_current->imported_from) > 0)
2331 max_label_counter += 14;
2332 if (leveldir_current->imported_by != NULL &&
2333 strlen(leveldir_current->imported_by) > 0)
2334 max_label_counter += 14;
2336 label_counter = (label_counter + 1) % max_label_counter;
2337 label_state = (label_counter >= 0 && label_counter <= 7 ?
2338 MICROLABEL_LEVEL_NAME :
2339 label_counter >= 9 && label_counter <= 12 ?
2340 MICROLABEL_LEVEL_AUTHOR_HEAD :
2341 label_counter >= 14 && label_counter <= 21 ?
2342 MICROLABEL_LEVEL_AUTHOR :
2343 label_counter >= 23 && label_counter <= 26 ?
2344 MICROLABEL_IMPORTED_FROM_HEAD :
2345 label_counter >= 28 && label_counter <= 35 ?
2346 MICROLABEL_IMPORTED_FROM :
2347 label_counter >= 37 && label_counter <= 40 ?
2348 MICROLABEL_IMPORTED_BY_HEAD :
2349 label_counter >= 42 && label_counter <= 49 ?
2350 MICROLABEL_IMPORTED_BY : MICROLABEL_EMPTY);
2352 if (leveldir_current->imported_from == NULL &&
2353 (label_state == MICROLABEL_IMPORTED_FROM_HEAD ||
2354 label_state == MICROLABEL_IMPORTED_FROM))
2355 label_state = (label_state == MICROLABEL_IMPORTED_FROM_HEAD ?
2356 MICROLABEL_IMPORTED_BY_HEAD : MICROLABEL_IMPORTED_BY);
2358 DrawPreviewLevelLabelExt(label_state);
2361 game_status = last_game_status; /* restore current game status */
2364 inline void DrawGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
2365 int graphic, int sync_frame, int mask_mode)
2367 int frame = getGraphicAnimationFrame(graphic, sync_frame);
2369 if (mask_mode == USE_MASKING)
2370 DrawGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
2372 DrawGraphicExt(dst_bitmap, x, y, graphic, frame);
2375 inline void DrawGraphicAnimation(int x, int y, int graphic)
2377 int lx = LEVELX(x), ly = LEVELY(y);
2379 if (!IN_SCR_FIELD(x, y))
2382 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
2383 graphic, GfxFrame[lx][ly], NO_MASKING);
2384 MarkTileDirty(x, y);
2387 void DrawLevelGraphicAnimation(int x, int y, int graphic)
2389 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
2392 void DrawLevelElementAnimation(int x, int y, int element)
2394 int graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
2396 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
2399 inline void DrawLevelGraphicAnimationIfNeeded(int x, int y, int graphic)
2401 int sx = SCREENX(x), sy = SCREENY(y);
2403 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
2406 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
2409 DrawGraphicAnimation(sx, sy, graphic);
2412 if (GFX_CRUMBLED(TILE_GFX_ELEMENT(x, y)))
2413 DrawLevelFieldCrumbledSand(x, y);
2415 if (GFX_CRUMBLED(Feld[x][y]))
2416 DrawLevelFieldCrumbledSand(x, y);
2420 void DrawLevelElementAnimationIfNeeded(int x, int y, int element)
2422 int sx = SCREENX(x), sy = SCREENY(y);
2425 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
2428 graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
2430 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
2433 DrawGraphicAnimation(sx, sy, graphic);
2435 if (GFX_CRUMBLED(element))
2436 DrawLevelFieldCrumbledSand(x, y);
2439 static int getPlayerGraphic(struct PlayerInfo *player, int move_dir)
2441 if (player->use_murphy)
2443 /* this works only because currently only one player can be "murphy" ... */
2444 static int last_horizontal_dir = MV_LEFT;
2445 int graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, move_dir);
2447 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
2448 last_horizontal_dir = move_dir;
2450 if (graphic == IMG_SP_MURPHY) /* undefined => use special graphic */
2452 int direction = (player->is_snapping ? move_dir : last_horizontal_dir);
2454 graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, direction);
2460 return el_act_dir2img(player->artwork_element, player->GfxAction,move_dir);
2463 static boolean equalGraphics(int graphic1, int graphic2)
2465 struct GraphicInfo *g1 = &graphic_info[graphic1];
2466 struct GraphicInfo *g2 = &graphic_info[graphic2];
2468 return (g1->bitmap == g2->bitmap &&
2469 g1->src_x == g2->src_x &&
2470 g1->src_y == g2->src_y &&
2471 g1->anim_frames == g2->anim_frames &&
2472 g1->anim_delay == g2->anim_delay &&
2473 g1->anim_mode == g2->anim_mode);
2476 void DrawAllPlayers()
2480 for (i = 0; i < MAX_PLAYERS; i++)
2481 if (stored_player[i].active)
2482 DrawPlayer(&stored_player[i]);
2485 void DrawPlayerField(int x, int y)
2487 if (!IS_PLAYER(x, y))
2490 DrawPlayer(PLAYERINFO(x, y));
2493 #define DRAW_PLAYER_OVER_PUSHED_ELEMENT 1
2495 void DrawPlayer(struct PlayerInfo *player)
2497 int jx = player->jx;
2498 int jy = player->jy;
2499 int move_dir = player->MovDir;
2500 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? +1 : 0);
2501 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? +1 : 0);
2502 int last_jx = (player->is_moving ? jx - dx : jx);
2503 int last_jy = (player->is_moving ? jy - dy : jy);
2504 int next_jx = jx + dx;
2505 int next_jy = jy + dy;
2506 boolean player_is_moving = (player->MovPos ? TRUE : FALSE);
2507 boolean player_is_opaque = FALSE;
2508 int sx = SCREENX(jx), sy = SCREENY(jy);
2509 int sxx = 0, syy = 0;
2510 int element = Feld[jx][jy], last_element = Feld[last_jx][last_jy];
2512 int action = ACTION_DEFAULT;
2513 int last_player_graphic = getPlayerGraphic(player, move_dir);
2514 int last_player_frame = player->Frame;
2517 /* GfxElement[][] is set to the element the player is digging or collecting;
2518 remove also for off-screen player if the player is not moving anymore */
2519 if (IN_LEV_FIELD(jx, jy) && !player_is_moving)
2520 GfxElement[jx][jy] = EL_UNDEFINED;
2522 if (!player->active || !IN_SCR_FIELD(SCREENX(last_jx), SCREENY(last_jy)))
2526 if (!IN_LEV_FIELD(jx, jy))
2528 printf("DrawPlayerField(): x = %d, y = %d\n",jx,jy);
2529 printf("DrawPlayerField(): sx = %d, sy = %d\n",sx,sy);
2530 printf("DrawPlayerField(): This should never happen!\n");
2535 if (element == EL_EXPLOSION)
2538 action = (player->is_pushing ? ACTION_PUSHING :
2539 player->is_digging ? ACTION_DIGGING :
2540 player->is_collecting ? ACTION_COLLECTING :
2541 player->is_moving ? ACTION_MOVING :
2542 player->is_snapping ? ACTION_SNAPPING :
2543 player->is_dropping ? ACTION_DROPPING :
2544 player->is_waiting ? player->action_waiting : ACTION_DEFAULT);
2546 if (player->is_waiting)
2547 move_dir = player->dir_waiting;
2549 InitPlayerGfxAnimation(player, action, move_dir);
2551 /* ----------------------------------------------------------------------- */
2552 /* draw things in the field the player is leaving, if needed */
2553 /* ----------------------------------------------------------------------- */
2555 if (player->is_moving)
2557 if (Back[last_jx][last_jy] && IS_DRAWABLE(last_element))
2559 DrawLevelElement(last_jx, last_jy, Back[last_jx][last_jy]);
2561 if (last_element == EL_DYNAMITE_ACTIVE ||
2562 last_element == EL_EM_DYNAMITE_ACTIVE ||
2563 last_element == EL_SP_DISK_RED_ACTIVE)
2564 DrawDynamite(last_jx, last_jy);
2566 DrawLevelFieldThruMask(last_jx, last_jy);
2568 else if (last_element == EL_DYNAMITE_ACTIVE ||
2569 last_element == EL_EM_DYNAMITE_ACTIVE ||
2570 last_element == EL_SP_DISK_RED_ACTIVE)
2571 DrawDynamite(last_jx, last_jy);
2573 /* !!! this is not enough to prevent flickering of players which are
2574 moving next to each others without a free tile between them -- this
2575 can only be solved by drawing all players layer by layer (first the
2576 background, then the foreground etc.) !!! => TODO */
2577 else if (!IS_PLAYER(last_jx, last_jy))
2578 DrawLevelField(last_jx, last_jy);
2581 DrawLevelField(last_jx, last_jy);
2584 if (player->is_pushing && IN_SCR_FIELD(SCREENX(next_jx), SCREENY(next_jy)))
2585 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
2588 if (!IN_SCR_FIELD(sx, sy))
2591 /* ----------------------------------------------------------------------- */
2592 /* draw things behind the player, if needed */
2593 /* ----------------------------------------------------------------------- */
2596 DrawLevelElement(jx, jy, Back[jx][jy]);
2597 else if (IS_ACTIVE_BOMB(element))
2598 DrawLevelElement(jx, jy, EL_EMPTY);
2601 if (player_is_moving && GfxElement[jx][jy] != EL_UNDEFINED)
2603 int old_element = GfxElement[jx][jy];
2604 int old_graphic = el_act_dir2img(old_element, action, move_dir);
2605 int frame = getGraphicAnimationFrame(old_graphic, player->StepFrame);
2607 if (GFX_CRUMBLED(old_element))
2608 DrawLevelFieldCrumbledSandDigging(jx, jy, move_dir, player->StepFrame);
2610 DrawGraphic(sx, sy, old_graphic, frame);
2612 if (graphic_info[old_graphic].anim_mode & ANIM_OPAQUE_PLAYER)
2613 player_is_opaque = TRUE;
2617 GfxElement[jx][jy] = EL_UNDEFINED;
2619 /* make sure that pushed elements are drawn with correct frame rate */
2621 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
2623 if (player->is_pushing && player->is_moving && !IS_ANIM_MODE_CE(graphic))
2624 GfxFrame[jx][jy] = player->StepFrame;
2626 if (player->is_pushing && player->is_moving)
2627 GfxFrame[jx][jy] = player->StepFrame;
2630 DrawLevelField(jx, jy);
2634 #if !DRAW_PLAYER_OVER_PUSHED_ELEMENT
2635 /* ----------------------------------------------------------------------- */
2636 /* draw player himself */
2637 /* ----------------------------------------------------------------------- */
2639 graphic = getPlayerGraphic(player, move_dir);
2641 /* in the case of changed player action or direction, prevent the current
2642 animation frame from being restarted for identical animations */
2643 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
2644 player->Frame = last_player_frame;
2646 frame = getGraphicAnimationFrame(graphic, player->Frame);
2650 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
2651 sxx = player->GfxPos;
2653 syy = player->GfxPos;
2656 if (!setup.soft_scrolling && ScreenMovPos)
2659 if (player_is_opaque)
2660 DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
2662 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
2664 if (SHIELD_ON(player))
2666 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
2667 IMG_SHIELD_NORMAL_ACTIVE);
2668 int frame = getGraphicAnimationFrame(graphic, -1);
2670 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
2674 #if DRAW_PLAYER_OVER_PUSHED_ELEMENT
2677 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
2678 sxx = player->GfxPos;
2680 syy = player->GfxPos;
2684 /* ----------------------------------------------------------------------- */
2685 /* draw things the player is pushing, if needed */
2686 /* ----------------------------------------------------------------------- */
2689 printf("::: %d, %d [%d, %d] [%d]\n",
2690 player->is_pushing, player_is_moving, player->GfxAction,
2691 player->is_moving, player_is_moving);
2695 if (player->is_pushing && player->is_moving)
2697 int px = SCREENX(jx), py = SCREENY(jy);
2698 int pxx = (TILEX - ABS(sxx)) * dx;
2699 int pyy = (TILEY - ABS(syy)) * dy;
2700 int gfx_frame = GfxFrame[jx][jy];
2706 if (!IS_MOVING(jx, jy)) /* push movement already finished */
2708 element = Feld[next_jx][next_jy];
2709 gfx_frame = GfxFrame[next_jx][next_jy];
2712 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
2715 sync_frame = (IS_ANIM_MODE_CE(graphic) ? gfx_frame : player->StepFrame);
2716 frame = getGraphicAnimationFrame(graphic, sync_frame);
2718 frame = getGraphicAnimationFrame(graphic, player->StepFrame);
2721 /* draw background element under pushed element (like the Sokoban field) */
2722 if (Back[next_jx][next_jy])
2723 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
2726 printf("::: %d, %d, %d, %d [%d] [%d, %d, %d] [%d] [%d, %d] [%d, %d]\n",
2727 jx, px, player->GfxPos, player->StepFrame,
2732 GfxFrame[jx][jy], GfxFrame[next_jx][next_jy]);
2736 /* do not draw (EM style) pushing animation when pushing is finished */
2737 /* (two-tile animations usually do not contain start and end frame) */
2738 if (graphic_info[graphic].double_movement && !IS_MOVING(jx, jy))
2739 DrawLevelElement(next_jx, next_jy, Feld[next_jx][next_jy]);
2741 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
2743 /* masked drawing is needed for EMC style (double) movement graphics */
2744 /* !!! (ONLY WHEN DRAWING PUSHED ELEMENT OVER THE PLAYER) !!! */
2745 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
2750 #if DRAW_PLAYER_OVER_PUSHED_ELEMENT
2751 /* ----------------------------------------------------------------------- */
2752 /* draw player himself */
2753 /* ----------------------------------------------------------------------- */
2755 graphic = getPlayerGraphic(player, move_dir);
2757 /* in the case of changed player action or direction, prevent the current
2758 animation frame from being restarted for identical animations */
2759 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
2760 player->Frame = last_player_frame;
2762 frame = getGraphicAnimationFrame(graphic, player->Frame);
2766 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
2767 sxx = player->GfxPos;
2769 syy = player->GfxPos;
2772 if (!setup.soft_scrolling && ScreenMovPos)
2775 if (player_is_opaque)
2776 DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
2778 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
2780 if (SHIELD_ON(player))
2782 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
2783 IMG_SHIELD_NORMAL_ACTIVE);
2784 int frame = getGraphicAnimationFrame(graphic, -1);
2786 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
2790 /* ----------------------------------------------------------------------- */
2791 /* draw things in front of player (active dynamite or dynabombs) */
2792 /* ----------------------------------------------------------------------- */
2794 if (IS_ACTIVE_BOMB(element))
2796 graphic = el2img(element);
2797 frame = getGraphicAnimationFrame(graphic, GfxFrame[jx][jy]);
2799 if (game.emulation == EMU_SUPAPLEX)
2800 DrawGraphic(sx, sy, IMG_SP_DISK_RED, frame);
2802 DrawGraphicThruMask(sx, sy, graphic, frame);
2805 if (player_is_moving && last_element == EL_EXPLOSION)
2807 int element = (GfxElement[last_jx][last_jy] != EL_UNDEFINED ?
2808 GfxElement[last_jx][last_jy] : EL_EMPTY);
2809 int graphic = el_act2img(element, ACTION_EXPLODING);
2810 int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
2811 int phase = ExplodePhase[last_jx][last_jy] - 1;
2812 int frame = getGraphicAnimationFrame(graphic, phase - delay);
2815 DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy), graphic, frame);
2818 /* ----------------------------------------------------------------------- */
2819 /* draw elements the player is just walking/passing through/under */
2820 /* ----------------------------------------------------------------------- */
2822 if (player_is_moving)
2824 /* handle the field the player is leaving ... */
2825 if (IS_ACCESSIBLE_INSIDE(last_element))
2826 DrawLevelField(last_jx, last_jy);
2827 else if (IS_ACCESSIBLE_UNDER(last_element))
2828 DrawLevelFieldThruMask(last_jx, last_jy);
2831 /* do not redraw accessible elements if the player is just pushing them */
2832 if (!player_is_moving || !player->is_pushing)
2834 /* ... and the field the player is entering */
2835 if (IS_ACCESSIBLE_INSIDE(element))
2836 DrawLevelField(jx, jy);
2837 else if (IS_ACCESSIBLE_UNDER(element))
2838 DrawLevelFieldThruMask(jx, jy);
2841 MarkTileDirty(sx, sy);
2844 /* ------------------------------------------------------------------------- */
2846 void WaitForEventToContinue()
2848 boolean still_wait = TRUE;
2850 /* simulate releasing mouse button over last gadget, if still pressed */
2852 HandleGadgets(-1, -1, 0);
2854 button_status = MB_RELEASED;
2870 case EVENT_BUTTONPRESS:
2871 case EVENT_KEYPRESS:
2875 case EVENT_KEYRELEASE:
2876 ClearPlayerAction();
2880 HandleOtherEvents(&event);
2884 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
2891 /* don't eat all CPU time */
2896 #define MAX_REQUEST_LINES 13
2897 #define MAX_REQUEST_LINE_FONT1_LEN 7
2898 #define MAX_REQUEST_LINE_FONT2_LEN 10
2900 boolean Request(char *text, unsigned int req_state)
2902 int mx, my, ty, result = -1;
2903 unsigned int old_door_state;
2904 int last_game_status = game_status; /* save current game status */
2905 int max_request_line_len = MAX_REQUEST_LINE_FONT1_LEN;
2906 int font_nr = FONT_TEXT_2;
2907 int max_word_len = 0;
2910 for (text_ptr = text; *text_ptr; text_ptr++)
2912 max_word_len = (*text_ptr != ' ' ? max_word_len + 1 : 0);
2914 if (max_word_len > MAX_REQUEST_LINE_FONT1_LEN)
2916 max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
2918 font_nr = FONT_TEXT_1;
2920 font_nr = FONT_LEVEL_NUMBER;
2927 if (game_status == GAME_MODE_PLAYING)
2929 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
2930 BlitScreenToBitmap_EM(backbuffer);
2931 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
2932 BlitScreenToBitmap_SP(backbuffer);
2935 /* disable deactivated drawing when quick-loading level tape recording */
2936 if (tape.playing && tape.deactivate_display)
2937 TapeDeactivateDisplayOff(TRUE);
2939 SetMouseCursor(CURSOR_DEFAULT);
2941 #if defined(NETWORK_AVALIABLE)
2942 /* pause network game while waiting for request to answer */
2943 if (options.network &&
2944 game_status == GAME_MODE_PLAYING &&
2945 req_state & REQUEST_WAIT_FOR_INPUT)
2946 SendToServer_PausePlaying();
2949 old_door_state = GetDoorState();
2951 /* simulate releasing mouse button over last gadget, if still pressed */
2953 HandleGadgets(-1, -1, 0);
2957 if (old_door_state & DOOR_OPEN_1)
2959 CloseDoor(DOOR_CLOSE_1);
2961 /* save old door content */
2962 BlitBitmap(bitmap_db_door, bitmap_db_door,
2963 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
2964 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
2968 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
2971 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
2973 /* clear door drawing field */
2974 DrawBackground(DX, DY, DXSIZE, DYSIZE);
2976 /* force DOOR font inside door area */
2977 game_status = GAME_MODE_PSEUDO_DOOR;
2979 /* write text for request */
2980 for (ty = 0; ty < MAX_REQUEST_LINES; ty++)
2982 char text_line[max_request_line_len + 1];
2988 for (tl = 0, tx = 0; tx < max_request_line_len; tl++, tx++)
2991 if (!tc || tc == ' ')
3002 strncpy(text_line, text, tl);
3005 DrawText(DX + (DXSIZE - tl * getFontWidth(font_nr)) / 2,
3006 DY + 8 + ty * (getFontHeight(font_nr) + 2),
3007 text_line, font_nr);
3009 text += tl + (tc == ' ' ? 1 : 0);
3012 game_status = last_game_status; /* restore current game status */
3014 if (req_state & REQ_ASK)
3016 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
3017 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
3019 else if (req_state & REQ_CONFIRM)
3021 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
3023 else if (req_state & REQ_PLAYER)
3025 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
3026 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
3027 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
3028 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
3031 /* copy request gadgets to door backbuffer */
3032 BlitBitmap(drawto, bitmap_db_door,
3033 DX, DY, DXSIZE, DYSIZE,
3034 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
3036 OpenDoor(DOOR_OPEN_1);
3038 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
3040 if (game_status == GAME_MODE_PLAYING)
3042 SetPanelBackground();
3043 SetDrawBackgroundMask(REDRAW_DOOR_1);
3047 SetDrawBackgroundMask(REDRAW_FIELD);
3053 if (game_status != GAME_MODE_MAIN)
3056 button_status = MB_RELEASED;
3058 request_gadget_id = -1;
3060 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
3072 case EVENT_BUTTONPRESS:
3073 case EVENT_BUTTONRELEASE:
3074 case EVENT_MOTIONNOTIFY:
3076 if (event.type == EVENT_MOTIONNOTIFY)
3078 if (!PointerInWindow(window))
3079 continue; /* window and pointer are on different screens */
3084 motion_status = TRUE;
3085 mx = ((MotionEvent *) &event)->x;
3086 my = ((MotionEvent *) &event)->y;
3090 motion_status = FALSE;
3091 mx = ((ButtonEvent *) &event)->x;
3092 my = ((ButtonEvent *) &event)->y;
3093 if (event.type == EVENT_BUTTONPRESS)
3094 button_status = ((ButtonEvent *) &event)->button;
3096 button_status = MB_RELEASED;
3099 /* this sets 'request_gadget_id' */
3100 HandleGadgets(mx, my, button_status);
3102 switch (request_gadget_id)
3104 case TOOL_CTRL_ID_YES:
3107 case TOOL_CTRL_ID_NO:
3110 case TOOL_CTRL_ID_CONFIRM:
3111 result = TRUE | FALSE;
3114 case TOOL_CTRL_ID_PLAYER_1:
3117 case TOOL_CTRL_ID_PLAYER_2:
3120 case TOOL_CTRL_ID_PLAYER_3:
3123 case TOOL_CTRL_ID_PLAYER_4:
3134 case EVENT_KEYPRESS:
3135 switch (GetEventKey((KeyEvent *)&event, TRUE))
3138 if (req_state & REQ_CONFIRM)
3154 if (req_state & REQ_PLAYER)
3158 case EVENT_KEYRELEASE:
3159 ClearPlayerAction();
3163 HandleOtherEvents(&event);
3167 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
3169 int joy = AnyJoystick();
3171 if (joy & JOY_BUTTON_1)
3173 else if (joy & JOY_BUTTON_2)
3179 if (game_status == GAME_MODE_PLAYING && local_player->LevelSolved_GameEnd)
3181 HandleGameActions();
3187 if (!PendingEvent()) /* delay only if no pending events */
3198 if (!PendingEvent()) /* delay only if no pending events */
3201 /* don't eat all CPU time */
3208 if (game_status != GAME_MODE_MAIN)
3213 if (!(req_state & REQ_STAY_OPEN))
3215 CloseDoor(DOOR_CLOSE_1);
3217 if (((old_door_state & DOOR_OPEN_1) && !(req_state & REQ_STAY_CLOSED)) ||
3218 (req_state & REQ_REOPEN))
3219 OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
3224 if (game_status == GAME_MODE_PLAYING)
3226 SetPanelBackground();
3227 SetDrawBackgroundMask(REDRAW_DOOR_1);
3231 SetDrawBackgroundMask(REDRAW_FIELD);
3234 #if defined(NETWORK_AVALIABLE)
3235 /* continue network game after request */
3236 if (options.network &&
3237 game_status == GAME_MODE_PLAYING &&
3238 req_state & REQUEST_WAIT_FOR_INPUT)
3239 SendToServer_ContinuePlaying();
3242 /* restore deactivated drawing when quick-loading level tape recording */
3243 if (tape.playing && tape.deactivate_display)
3244 TapeDeactivateDisplayOn();
3249 unsigned int OpenDoor(unsigned int door_state)
3251 if (door_state & DOOR_COPY_BACK)
3253 if (door_state & DOOR_OPEN_1)
3254 BlitBitmap(bitmap_db_door, bitmap_db_door,
3255 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
3256 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
3258 if (door_state & DOOR_OPEN_2)
3259 BlitBitmap(bitmap_db_door, bitmap_db_door,
3260 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY2, VXSIZE, VYSIZE,
3261 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
3263 door_state &= ~DOOR_COPY_BACK;
3266 return MoveDoor(door_state);
3269 unsigned int CloseDoor(unsigned int door_state)
3271 unsigned int old_door_state = GetDoorState();
3273 if (!(door_state & DOOR_NO_COPY_BACK))
3275 if (old_door_state & DOOR_OPEN_1)
3276 BlitBitmap(backbuffer, bitmap_db_door,
3277 DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
3279 if (old_door_state & DOOR_OPEN_2)
3280 BlitBitmap(backbuffer, bitmap_db_door,
3281 VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
3283 door_state &= ~DOOR_NO_COPY_BACK;
3286 return MoveDoor(door_state);
3289 unsigned int GetDoorState()
3291 return MoveDoor(DOOR_GET_STATE);
3294 unsigned int SetDoorState(unsigned int door_state)
3296 return MoveDoor(door_state | DOOR_SET_STATE);
3299 unsigned int MoveDoor(unsigned int door_state)
3301 static int door1 = DOOR_OPEN_1;
3302 static int door2 = DOOR_CLOSE_2;
3303 unsigned long door_delay = 0;
3304 unsigned long door_delay_value;
3307 if (door_1.width < 0 || door_1.width > DXSIZE)
3308 door_1.width = DXSIZE;
3309 if (door_1.height < 0 || door_1.height > DYSIZE)
3310 door_1.height = DYSIZE;
3311 if (door_2.width < 0 || door_2.width > VXSIZE)
3312 door_2.width = VXSIZE;
3313 if (door_2.height < 0 || door_2.height > VYSIZE)
3314 door_2.height = VYSIZE;
3316 if (door_state == DOOR_GET_STATE)
3317 return (door1 | door2);
3319 if (door_state & DOOR_SET_STATE)
3321 if (door_state & DOOR_ACTION_1)
3322 door1 = door_state & DOOR_ACTION_1;
3323 if (door_state & DOOR_ACTION_2)
3324 door2 = door_state & DOOR_ACTION_2;
3326 return (door1 | door2);
3329 if (!(door_state & DOOR_FORCE_REDRAW))
3331 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
3332 door_state &= ~DOOR_OPEN_1;
3333 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
3334 door_state &= ~DOOR_CLOSE_1;
3335 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
3336 door_state &= ~DOOR_OPEN_2;
3337 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
3338 door_state &= ~DOOR_CLOSE_2;
3341 door_delay_value = (door_state & DOOR_ACTION_1 ? door_1.step_delay :
3344 if (setup.quick_doors)
3346 stepsize = 20; /* must be chosen to always draw last frame */
3347 door_delay_value = 0;
3350 if (global.autoplay_leveldir)
3352 door_state |= DOOR_NO_DELAY;
3353 door_state &= ~DOOR_CLOSE_ALL;
3357 if (game_status == GAME_MODE_EDITOR)
3358 door_state |= DOOR_NO_DELAY;
3361 if (door_state & DOOR_ACTION)
3363 boolean handle_door_1 = (door_state & DOOR_ACTION_1);
3364 boolean handle_door_2 = (door_state & DOOR_ACTION_2);
3365 boolean door_1_done = (!handle_door_1);
3366 boolean door_2_done = (!handle_door_2);
3367 boolean door_1_vertical = (door_1.anim_mode & ANIM_VERTICAL);
3368 boolean door_2_vertical = (door_2.anim_mode & ANIM_VERTICAL);
3369 int door_size_1 = (door_1_vertical ? door_1.height : door_1.width);
3370 int door_size_2 = (door_2_vertical ? door_2.height : door_2.width);
3371 int max_door_size_1 = (door_1_vertical ? DYSIZE : DXSIZE);
3372 int max_door_size_2 = (door_2_vertical ? VYSIZE : VXSIZE);
3373 int door_size = (handle_door_1 ? door_size_1 : door_size_2);
3374 int max_door_size = (handle_door_1 ? max_door_size_1 : max_door_size_2);
3375 int door_skip = max_door_size - door_size;
3376 int end = door_size;
3377 int start = ((door_state & DOOR_NO_DELAY) ? end : 0);
3380 if (!(door_state & DOOR_NO_DELAY) && !setup.quick_doors)
3382 /* opening door sound has priority over simultaneously closing door */
3383 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
3384 PlayMenuSoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
3385 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
3386 PlayMenuSoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
3389 for (k = start; k <= end && !(door_1_done && door_2_done); k += stepsize)
3392 Bitmap *bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
3393 GC gc = bitmap->stored_clip_gc;
3395 if (door_state & DOOR_ACTION_1)
3397 int a = MIN(x * door_1.step_offset, end);
3398 int p = (door_state & DOOR_OPEN_1 ? end - a : a);
3399 int i = p + door_skip;
3401 if (door_1.anim_mode & ANIM_STATIC_PANEL)
3403 BlitBitmap(bitmap_db_door, drawto,
3404 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1,
3405 DXSIZE, DYSIZE, DX, DY);
3409 BlitBitmap(bitmap_db_door, drawto,
3410 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + p / 2,
3411 DXSIZE, DYSIZE - p / 2, DX, DY);
3413 ClearRectangle(drawto, DX, DY + DYSIZE - p / 2, DXSIZE, p / 2);
3416 if (door_1.anim_mode & ANIM_HORIZONTAL && x <= DXSIZE)
3418 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
3419 int dst1_x = DX + DXSIZE - i, dst1_y = DY;
3420 int src2_x = DXSIZE - i, src2_y = DOOR_GFX_PAGEY1;
3421 int dst2_x = DX, dst2_y = DY;
3422 int width = i, height = DYSIZE;
3424 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
3425 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
3428 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
3429 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
3432 else if (door_1.anim_mode & ANIM_VERTICAL && x <= DYSIZE)
3434 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
3435 int dst1_x = DX, dst1_y = DY + DYSIZE - i;
3436 int src2_x = 0, src2_y = DOOR_GFX_PAGEY1 + DYSIZE - i;
3437 int dst2_x = DX, dst2_y = DY;
3438 int width = DXSIZE, height = i;
3440 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
3441 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
3444 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
3445 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
3448 else if (x <= DXSIZE) /* ANIM_DEFAULT */
3450 int j = (door_1.anim_mode == ANIM_DEFAULT ? (DXSIZE - i) / 3 : 0);
3452 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
3453 BlitBitmapMasked(bitmap, drawto,
3454 DXSIZE, DOOR_GFX_PAGEY1, i, 77,
3455 DX + DXSIZE - i, DY + j);
3456 BlitBitmapMasked(bitmap, drawto,
3457 DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63,
3458 DX + DXSIZE - i, DY + 140 + j);
3459 SetClipOrigin(bitmap, gc, DX - DXSIZE + i,
3460 DY - (DOOR_GFX_PAGEY1 + j));
3461 BlitBitmapMasked(bitmap, drawto,
3462 DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j,
3464 BlitBitmapMasked(bitmap, drawto,
3465 DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63,
3468 BlitBitmapMasked(bitmap, drawto,
3469 DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
3471 BlitBitmapMasked(bitmap, drawto,
3472 DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
3474 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
3475 BlitBitmapMasked(bitmap, drawto,
3476 DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
3477 DX + DXSIZE - i, DY + 77 + j);
3478 BlitBitmapMasked(bitmap, drawto,
3479 DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
3480 DX + DXSIZE - i, DY + 203 + j);
3483 redraw_mask |= REDRAW_DOOR_1;
3484 door_1_done = (a == end);
3487 if (door_state & DOOR_ACTION_2)
3489 int a = MIN(x * door_2.step_offset, door_size);
3490 int p = (door_state & DOOR_OPEN_2 ? door_size - a : a);
3491 int i = p + door_skip;
3493 if (door_2.anim_mode & ANIM_STATIC_PANEL)
3495 BlitBitmap(bitmap_db_door, drawto,
3496 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2,
3497 VXSIZE, VYSIZE, VX, VY);
3499 else if (x <= VYSIZE)
3501 BlitBitmap(bitmap_db_door, drawto,
3502 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + p / 2,
3503 VXSIZE, VYSIZE - p / 2, VX, VY);
3505 ClearRectangle(drawto, VX, VY + VYSIZE - p / 2, VXSIZE, p / 2);
3508 if (door_2.anim_mode & ANIM_HORIZONTAL && x <= VXSIZE)
3510 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
3511 int dst1_x = VX + VXSIZE - i, dst1_y = VY;
3512 int src2_x = VXSIZE - i, src2_y = DOOR_GFX_PAGEY2;
3513 int dst2_x = VX, dst2_y = VY;
3514 int width = i, height = VYSIZE;
3516 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
3517 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
3520 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
3521 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
3524 else if (door_2.anim_mode & ANIM_VERTICAL && x <= VYSIZE)
3526 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
3527 int dst1_x = VX, dst1_y = VY + VYSIZE - i;
3528 int src2_x = 0, src2_y = DOOR_GFX_PAGEY2 + VYSIZE - i;
3529 int dst2_x = VX, dst2_y = VY;
3530 int width = VXSIZE, height = i;
3532 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
3533 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
3536 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
3537 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
3540 else if (x <= VXSIZE) /* ANIM_DEFAULT */
3542 int j = (door_2.anim_mode == ANIM_DEFAULT ? (VXSIZE - i) / 3 : 0);
3544 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
3545 BlitBitmapMasked(bitmap, drawto,
3546 VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2,
3547 VX + VXSIZE - i, VY + j);
3548 SetClipOrigin(bitmap, gc,
3549 VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
3550 BlitBitmapMasked(bitmap, drawto,
3551 VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j,
3554 BlitBitmapMasked(bitmap, drawto,
3555 VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2,
3556 i, VYSIZE / 2, VX, VY + VYSIZE / 2 - j);
3557 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
3558 BlitBitmapMasked(bitmap, drawto,
3559 VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2,
3561 VX + VXSIZE - i, VY + VYSIZE / 2 + j);
3564 redraw_mask |= REDRAW_DOOR_2;
3565 door_2_done = (a == VXSIZE);
3568 if (!(door_state & DOOR_NO_DELAY))
3572 if (game_status == GAME_MODE_MAIN)
3575 WaitUntilDelayReached(&door_delay, door_delay_value);
3580 if (door_state & DOOR_ACTION_1)
3581 door1 = door_state & DOOR_ACTION_1;
3582 if (door_state & DOOR_ACTION_2)
3583 door2 = door_state & DOOR_ACTION_2;
3585 return (door1 | door2);
3588 void DrawSpecialEditorDoor()
3590 /* draw bigger toolbox window */
3591 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
3592 DOOR_GFX_PAGEX7, 0, EXSIZE + 8, 8,
3594 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
3595 EX - 6, VY - 4, EXSIZE + 12, EYSIZE - VYSIZE + 4,
3598 redraw_mask |= REDRAW_ALL;
3601 void UndrawSpecialEditorDoor()
3603 /* draw normal tape recorder window */
3604 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
3605 EX - 6, EY - 12, EXSIZE + 12, EYSIZE - VYSIZE + 12,
3608 redraw_mask |= REDRAW_ALL;
3612 /* ---------- new tool button stuff ---------------------------------------- */
3614 /* graphic position values for tool buttons */
3615 #define TOOL_BUTTON_YES_XPOS 2
3616 #define TOOL_BUTTON_YES_YPOS 250
3617 #define TOOL_BUTTON_YES_GFX_YPOS 0
3618 #define TOOL_BUTTON_YES_XSIZE 46
3619 #define TOOL_BUTTON_YES_YSIZE 28
3620 #define TOOL_BUTTON_NO_XPOS 52
3621 #define TOOL_BUTTON_NO_YPOS TOOL_BUTTON_YES_YPOS
3622 #define TOOL_BUTTON_NO_GFX_YPOS TOOL_BUTTON_YES_GFX_YPOS
3623 #define TOOL_BUTTON_NO_XSIZE TOOL_BUTTON_YES_XSIZE
3624 #define TOOL_BUTTON_NO_YSIZE TOOL_BUTTON_YES_YSIZE
3625 #define TOOL_BUTTON_CONFIRM_XPOS TOOL_BUTTON_YES_XPOS
3626 #define TOOL_BUTTON_CONFIRM_YPOS TOOL_BUTTON_YES_YPOS
3627 #define TOOL_BUTTON_CONFIRM_GFX_YPOS 30
3628 #define TOOL_BUTTON_CONFIRM_XSIZE 96
3629 #define TOOL_BUTTON_CONFIRM_YSIZE TOOL_BUTTON_YES_YSIZE
3630 #define TOOL_BUTTON_PLAYER_XSIZE 30
3631 #define TOOL_BUTTON_PLAYER_YSIZE 30
3632 #define TOOL_BUTTON_PLAYER_GFX_XPOS 5
3633 #define TOOL_BUTTON_PLAYER_GFX_YPOS 185
3634 #define TOOL_BUTTON_PLAYER_XPOS (5 + TOOL_BUTTON_PLAYER_XSIZE / 2)
3635 #define TOOL_BUTTON_PLAYER_YPOS (215 - TOOL_BUTTON_PLAYER_YSIZE / 2)
3636 #define TOOL_BUTTON_PLAYER1_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3637 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
3638 #define TOOL_BUTTON_PLAYER2_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3639 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
3640 #define TOOL_BUTTON_PLAYER3_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3641 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
3642 #define TOOL_BUTTON_PLAYER4_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3643 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
3644 #define TOOL_BUTTON_PLAYER1_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3645 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
3646 #define TOOL_BUTTON_PLAYER2_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3647 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
3648 #define TOOL_BUTTON_PLAYER3_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3649 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
3650 #define TOOL_BUTTON_PLAYER4_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3651 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
3660 } toolbutton_info[NUM_TOOL_BUTTONS] =
3663 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_GFX_YPOS,
3664 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_YPOS,
3665 TOOL_BUTTON_YES_XSIZE, TOOL_BUTTON_YES_YSIZE,
3670 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_GFX_YPOS,
3671 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_YPOS,
3672 TOOL_BUTTON_NO_XSIZE, TOOL_BUTTON_NO_YSIZE,
3677 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_GFX_YPOS,
3678 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_YPOS,
3679 TOOL_BUTTON_CONFIRM_XSIZE, TOOL_BUTTON_CONFIRM_YSIZE,
3680 TOOL_CTRL_ID_CONFIRM,
3684 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3685 TOOL_BUTTON_PLAYER1_XPOS, TOOL_BUTTON_PLAYER1_YPOS,
3686 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3687 TOOL_CTRL_ID_PLAYER_1,
3691 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3692 TOOL_BUTTON_PLAYER2_XPOS, TOOL_BUTTON_PLAYER2_YPOS,
3693 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3694 TOOL_CTRL_ID_PLAYER_2,
3698 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3699 TOOL_BUTTON_PLAYER3_XPOS, TOOL_BUTTON_PLAYER3_YPOS,
3700 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3701 TOOL_CTRL_ID_PLAYER_3,
3705 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3706 TOOL_BUTTON_PLAYER4_XPOS, TOOL_BUTTON_PLAYER4_YPOS,
3707 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3708 TOOL_CTRL_ID_PLAYER_4,
3713 void CreateToolButtons()
3717 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3719 Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
3720 Bitmap *deco_bitmap = None;
3721 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
3722 struct GadgetInfo *gi;
3723 unsigned long event_mask;
3724 int gd_xoffset, gd_yoffset;
3725 int gd_x1, gd_x2, gd_y;
3728 event_mask = GD_EVENT_RELEASED;
3730 gd_xoffset = toolbutton_info[i].xpos;
3731 gd_yoffset = toolbutton_info[i].ypos;
3732 gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
3733 gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
3734 gd_y = DOOR_GFX_PAGEY1 + gd_yoffset;
3736 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
3738 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
3740 getMiniGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr),
3741 &deco_bitmap, &deco_x, &deco_y);
3742 deco_xpos = (toolbutton_info[i].width - MINI_TILEX) / 2;
3743 deco_ypos = (toolbutton_info[i].height - MINI_TILEY) / 2;
3746 gi = CreateGadget(GDI_CUSTOM_ID, id,
3747 GDI_INFO_TEXT, toolbutton_info[i].infotext,
3748 GDI_X, DX + toolbutton_info[i].x,
3749 GDI_Y, DY + toolbutton_info[i].y,
3750 GDI_WIDTH, toolbutton_info[i].width,
3751 GDI_HEIGHT, toolbutton_info[i].height,
3752 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
3753 GDI_STATE, GD_BUTTON_UNPRESSED,
3754 GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
3755 GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
3756 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
3757 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
3758 GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
3759 GDI_DECORATION_SHIFTING, 1, 1,
3760 GDI_DIRECT_DRAW, FALSE,
3761 GDI_EVENT_MASK, event_mask,
3762 GDI_CALLBACK_ACTION, HandleToolButtons,
3766 Error(ERR_EXIT, "cannot create gadget");
3768 tool_gadget[id] = gi;
3772 void FreeToolButtons()
3776 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3777 FreeGadget(tool_gadget[i]);
3780 static void UnmapToolButtons()
3784 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3785 UnmapGadget(tool_gadget[i]);
3788 static void HandleToolButtons(struct GadgetInfo *gi)
3790 request_gadget_id = gi->custom_id;
3793 static struct Mapping_EM_to_RND_object
3796 boolean is_rnd_to_em_mapping; /* unique mapping EM <-> RND */
3797 boolean is_backside; /* backside of moving element */
3803 em_object_mapping_list[] =
3806 Xblank, TRUE, FALSE,
3810 Yacid_splash_eB, FALSE, FALSE,
3811 EL_ACID_SPLASH_RIGHT, -1, -1
3814 Yacid_splash_wB, FALSE, FALSE,
3815 EL_ACID_SPLASH_LEFT, -1, -1
3818 #ifdef EM_ENGINE_BAD_ROLL
3820 Xstone_force_e, FALSE, FALSE,
3821 EL_ROCK, -1, MV_BIT_RIGHT
3824 Xstone_force_w, FALSE, FALSE,
3825 EL_ROCK, -1, MV_BIT_LEFT
3828 Xnut_force_e, FALSE, FALSE,
3829 EL_NUT, -1, MV_BIT_RIGHT
3832 Xnut_force_w, FALSE, FALSE,
3833 EL_NUT, -1, MV_BIT_LEFT
3836 Xspring_force_e, FALSE, FALSE,
3837 EL_SPRING, -1, MV_BIT_RIGHT
3840 Xspring_force_w, FALSE, FALSE,
3841 EL_SPRING, -1, MV_BIT_LEFT
3844 Xemerald_force_e, FALSE, FALSE,
3845 EL_EMERALD, -1, MV_BIT_RIGHT
3848 Xemerald_force_w, FALSE, FALSE,
3849 EL_EMERALD, -1, MV_BIT_LEFT
3852 Xdiamond_force_e, FALSE, FALSE,
3853 EL_DIAMOND, -1, MV_BIT_RIGHT
3856 Xdiamond_force_w, FALSE, FALSE,
3857 EL_DIAMOND, -1, MV_BIT_LEFT
3860 Xbomb_force_e, FALSE, FALSE,
3861 EL_BOMB, -1, MV_BIT_RIGHT
3864 Xbomb_force_w, FALSE, FALSE,
3865 EL_BOMB, -1, MV_BIT_LEFT
3867 #endif /* EM_ENGINE_BAD_ROLL */
3870 Xstone, TRUE, FALSE,
3874 Xstone_pause, FALSE, FALSE,
3878 Xstone_fall, FALSE, FALSE,
3882 Ystone_s, FALSE, FALSE,
3883 EL_ROCK, ACTION_FALLING, -1
3886 Ystone_sB, FALSE, TRUE,
3887 EL_ROCK, ACTION_FALLING, -1
3890 Ystone_e, FALSE, FALSE,
3891 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
3894 Ystone_eB, FALSE, TRUE,
3895 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
3898 Ystone_w, FALSE, FALSE,
3899 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
3902 Ystone_wB, FALSE, TRUE,
3903 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
3910 Xnut_pause, FALSE, FALSE,
3914 Xnut_fall, FALSE, FALSE,
3918 Ynut_s, FALSE, FALSE,
3919 EL_NUT, ACTION_FALLING, -1
3922 Ynut_sB, FALSE, TRUE,
3923 EL_NUT, ACTION_FALLING, -1
3926 Ynut_e, FALSE, FALSE,
3927 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
3930 Ynut_eB, FALSE, TRUE,
3931 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
3934 Ynut_w, FALSE, FALSE,
3935 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
3938 Ynut_wB, FALSE, TRUE,
3939 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
3942 Xbug_n, TRUE, FALSE,
3946 Xbug_e, TRUE, FALSE,
3947 EL_BUG_RIGHT, -1, -1
3950 Xbug_s, TRUE, FALSE,
3954 Xbug_w, TRUE, FALSE,
3958 Xbug_gon, FALSE, FALSE,
3962 Xbug_goe, FALSE, FALSE,
3963 EL_BUG_RIGHT, -1, -1
3966 Xbug_gos, FALSE, FALSE,
3970 Xbug_gow, FALSE, FALSE,
3974 Ybug_n, FALSE, FALSE,
3975 EL_BUG, ACTION_MOVING, MV_BIT_UP
3978 Ybug_nB, FALSE, TRUE,
3979 EL_BUG, ACTION_MOVING, MV_BIT_UP
3982 Ybug_e, FALSE, FALSE,
3983 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
3986 Ybug_eB, FALSE, TRUE,
3987 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
3990 Ybug_s, FALSE, FALSE,
3991 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
3994 Ybug_sB, FALSE, TRUE,
3995 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
3998 Ybug_w, FALSE, FALSE,
3999 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
4002 Ybug_wB, FALSE, TRUE,
4003 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
4006 Ybug_w_n, FALSE, FALSE,
4007 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
4010 Ybug_n_e, FALSE, FALSE,
4011 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
4014 Ybug_e_s, FALSE, FALSE,
4015 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
4018 Ybug_s_w, FALSE, FALSE,
4019 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
4022 Ybug_e_n, FALSE, FALSE,
4023 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
4026 Ybug_s_e, FALSE, FALSE,
4027 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
4030 Ybug_w_s, FALSE, FALSE,
4031 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
4034 Ybug_n_w, FALSE, FALSE,
4035 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
4038 Ybug_stone, FALSE, FALSE,
4039 EL_BUG, ACTION_SMASHED_BY_ROCK, -1
4042 Ybug_spring, FALSE, FALSE,
4043 EL_BUG, ACTION_SMASHED_BY_SPRING, -1
4046 Xtank_n, TRUE, FALSE,
4047 EL_SPACESHIP_UP, -1, -1
4050 Xtank_e, TRUE, FALSE,
4051 EL_SPACESHIP_RIGHT, -1, -1
4054 Xtank_s, TRUE, FALSE,
4055 EL_SPACESHIP_DOWN, -1, -1
4058 Xtank_w, TRUE, FALSE,
4059 EL_SPACESHIP_LEFT, -1, -1
4062 Xtank_gon, FALSE, FALSE,
4063 EL_SPACESHIP_UP, -1, -1
4066 Xtank_goe, FALSE, FALSE,
4067 EL_SPACESHIP_RIGHT, -1, -1
4070 Xtank_gos, FALSE, FALSE,
4071 EL_SPACESHIP_DOWN, -1, -1
4074 Xtank_gow, FALSE, FALSE,
4075 EL_SPACESHIP_LEFT, -1, -1
4078 Ytank_n, FALSE, FALSE,
4079 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
4082 Ytank_nB, FALSE, TRUE,
4083 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
4086 Ytank_e, FALSE, FALSE,
4087 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
4090 Ytank_eB, FALSE, TRUE,
4091 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
4094 Ytank_s, FALSE, FALSE,
4095 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
4098 Ytank_sB, FALSE, TRUE,
4099 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
4102 Ytank_w, FALSE, FALSE,
4103 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
4106 Ytank_wB, FALSE, TRUE,
4107 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
4110 Ytank_w_n, FALSE, FALSE,
4111 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
4114 Ytank_n_e, FALSE, FALSE,
4115 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
4118 Ytank_e_s, FALSE, FALSE,
4119 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
4122 Ytank_s_w, FALSE, FALSE,
4123 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
4126 Ytank_e_n, FALSE, FALSE,
4127 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
4130 Ytank_s_e, FALSE, FALSE,
4131 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
4134 Ytank_w_s, FALSE, FALSE,
4135 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
4138 Ytank_n_w, FALSE, FALSE,
4139 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
4142 Ytank_stone, FALSE, FALSE,
4143 EL_SPACESHIP, ACTION_SMASHED_BY_ROCK, -1
4146 Ytank_spring, FALSE, FALSE,
4147 EL_SPACESHIP, ACTION_SMASHED_BY_SPRING, -1
4150 Xandroid, TRUE, FALSE,
4151 EL_EMC_ANDROID, ACTION_ACTIVE, -1
4154 Xandroid_1_n, FALSE, FALSE,
4155 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
4158 Xandroid_2_n, FALSE, FALSE,
4159 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
4162 Xandroid_1_e, FALSE, FALSE,
4163 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
4166 Xandroid_2_e, FALSE, FALSE,
4167 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
4170 Xandroid_1_w, FALSE, FALSE,
4171 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
4174 Xandroid_2_w, FALSE, FALSE,
4175 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
4178 Xandroid_1_s, FALSE, FALSE,
4179 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
4182 Xandroid_2_s, FALSE, FALSE,
4183 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
4186 Yandroid_n, FALSE, FALSE,
4187 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
4190 Yandroid_nB, FALSE, TRUE,
4191 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
4194 Yandroid_ne, FALSE, FALSE,
4195 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPRIGHT
4198 Yandroid_neB, FALSE, TRUE,
4199 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPRIGHT
4202 Yandroid_e, FALSE, FALSE,
4203 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
4206 Yandroid_eB, FALSE, TRUE,
4207 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
4210 Yandroid_se, FALSE, FALSE,
4211 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNRIGHT
4214 Yandroid_seB, FALSE, TRUE,
4215 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNRIGHT
4218 Yandroid_s, FALSE, FALSE,
4219 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
4222 Yandroid_sB, FALSE, TRUE,
4223 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
4226 Yandroid_sw, FALSE, FALSE,
4227 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNLEFT
4230 Yandroid_swB, FALSE, TRUE,
4231 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNLEFT
4234 Yandroid_w, FALSE, FALSE,
4235 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
4238 Yandroid_wB, FALSE, TRUE,
4239 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
4242 Yandroid_nw, FALSE, FALSE,
4243 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPLEFT
4246 Yandroid_nwB, FALSE, TRUE,
4247 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPLEFT
4250 Xspring, TRUE, FALSE,
4254 Xspring_pause, FALSE, FALSE,
4258 Xspring_e, FALSE, FALSE,
4262 Xspring_w, FALSE, FALSE,
4266 Xspring_fall, FALSE, FALSE,
4270 Yspring_s, FALSE, FALSE,
4271 EL_SPRING, ACTION_FALLING, -1
4274 Yspring_sB, FALSE, TRUE,
4275 EL_SPRING, ACTION_FALLING, -1
4278 Yspring_e, FALSE, FALSE,
4279 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
4282 Yspring_eB, FALSE, TRUE,
4283 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
4286 Yspring_w, FALSE, FALSE,
4287 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
4290 Yspring_wB, FALSE, TRUE,
4291 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
4294 Yspring_kill_e, FALSE, FALSE,
4295 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
4298 Yspring_kill_eB, FALSE, TRUE,
4299 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
4302 Yspring_kill_w, FALSE, FALSE,
4303 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
4306 Yspring_kill_wB, FALSE, TRUE,
4307 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
4310 Xeater_n, TRUE, FALSE,
4311 EL_YAMYAM_UP, -1, -1
4314 Xeater_e, TRUE, FALSE,
4315 EL_YAMYAM_RIGHT, -1, -1
4318 Xeater_w, TRUE, FALSE,
4319 EL_YAMYAM_LEFT, -1, -1
4322 Xeater_s, TRUE, FALSE,
4323 EL_YAMYAM_DOWN, -1, -1
4326 Yeater_n, FALSE, FALSE,
4327 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
4330 Yeater_nB, FALSE, TRUE,
4331 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
4334 Yeater_e, FALSE, FALSE,
4335 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
4338 Yeater_eB, FALSE, TRUE,
4339 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
4342 Yeater_s, FALSE, FALSE,
4343 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
4346 Yeater_sB, FALSE, TRUE,
4347 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
4350 Yeater_w, FALSE, FALSE,
4351 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
4354 Yeater_wB, FALSE, TRUE,
4355 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
4358 Yeater_stone, FALSE, FALSE,
4359 EL_YAMYAM, ACTION_SMASHED_BY_ROCK, -1
4362 Yeater_spring, FALSE, FALSE,
4363 EL_YAMYAM, ACTION_SMASHED_BY_SPRING, -1
4366 Xalien, TRUE, FALSE,
4370 Xalien_pause, FALSE, FALSE,
4374 Yalien_n, FALSE, FALSE,
4375 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
4378 Yalien_nB, FALSE, TRUE,
4379 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
4382 Yalien_e, FALSE, FALSE,
4383 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
4386 Yalien_eB, FALSE, TRUE,
4387 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
4390 Yalien_s, FALSE, FALSE,
4391 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
4394 Yalien_sB, FALSE, TRUE,
4395 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
4398 Yalien_w, FALSE, FALSE,
4399 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
4402 Yalien_wB, FALSE, TRUE,
4403 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
4406 Yalien_stone, FALSE, FALSE,
4407 EL_ROBOT, ACTION_SMASHED_BY_ROCK, -1
4410 Yalien_spring, FALSE, FALSE,
4411 EL_ROBOT, ACTION_SMASHED_BY_SPRING, -1
4414 Xemerald, TRUE, FALSE,
4418 Xemerald_pause, FALSE, FALSE,
4422 Xemerald_fall, FALSE, FALSE,
4426 Xemerald_shine, FALSE, FALSE,
4427 EL_EMERALD, ACTION_TWINKLING, -1
4430 Yemerald_s, FALSE, FALSE,
4431 EL_EMERALD, ACTION_FALLING, -1
4434 Yemerald_sB, FALSE, TRUE,
4435 EL_EMERALD, ACTION_FALLING, -1
4438 Yemerald_e, FALSE, FALSE,
4439 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
4442 Yemerald_eB, FALSE, TRUE,
4443 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
4446 Yemerald_w, FALSE, FALSE,
4447 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
4450 Yemerald_wB, FALSE, TRUE,
4451 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
4454 Yemerald_eat, FALSE, FALSE,
4455 EL_EMERALD, ACTION_COLLECTING, -1
4458 Yemerald_stone, FALSE, FALSE,
4459 EL_NUT, ACTION_BREAKING, -1
4462 Xdiamond, TRUE, FALSE,
4466 Xdiamond_pause, FALSE, FALSE,
4470 Xdiamond_fall, FALSE, FALSE,
4474 Xdiamond_shine, FALSE, FALSE,
4475 EL_DIAMOND, ACTION_TWINKLING, -1
4478 Ydiamond_s, FALSE, FALSE,
4479 EL_DIAMOND, ACTION_FALLING, -1
4482 Ydiamond_sB, FALSE, TRUE,
4483 EL_DIAMOND, ACTION_FALLING, -1
4486 Ydiamond_e, FALSE, FALSE,
4487 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
4490 Ydiamond_eB, FALSE, TRUE,
4491 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
4494 Ydiamond_w, FALSE, FALSE,
4495 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
4498 Ydiamond_wB, FALSE, TRUE,
4499 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
4502 Ydiamond_eat, FALSE, FALSE,
4503 EL_DIAMOND, ACTION_COLLECTING, -1
4506 Ydiamond_stone, FALSE, FALSE,
4507 EL_DIAMOND, ACTION_SMASHED_BY_ROCK, -1
4510 Xdrip_fall, TRUE, FALSE,
4511 EL_AMOEBA_DROP, -1, -1
4514 Xdrip_stretch, FALSE, FALSE,
4515 EL_AMOEBA_DROP, ACTION_FALLING, -1
4518 Xdrip_stretchB, FALSE, TRUE,
4519 EL_AMOEBA_DROP, ACTION_FALLING, -1
4522 Xdrip_eat, FALSE, FALSE,
4523 EL_AMOEBA_DROP, ACTION_GROWING, -1
4526 Ydrip_s1, FALSE, FALSE,
4527 EL_AMOEBA_DROP, ACTION_FALLING, -1
4530 Ydrip_s1B, FALSE, TRUE,
4531 EL_AMOEBA_DROP, ACTION_FALLING, -1
4534 Ydrip_s2, FALSE, FALSE,
4535 EL_AMOEBA_DROP, ACTION_FALLING, -1
4538 Ydrip_s2B, FALSE, TRUE,
4539 EL_AMOEBA_DROP, ACTION_FALLING, -1
4546 Xbomb_pause, FALSE, FALSE,
4550 Xbomb_fall, FALSE, FALSE,
4554 Ybomb_s, FALSE, FALSE,
4555 EL_BOMB, ACTION_FALLING, -1
4558 Ybomb_sB, FALSE, TRUE,
4559 EL_BOMB, ACTION_FALLING, -1
4562 Ybomb_e, FALSE, FALSE,
4563 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
4566 Ybomb_eB, FALSE, TRUE,
4567 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
4570 Ybomb_w, FALSE, FALSE,
4571 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
4574 Ybomb_wB, FALSE, TRUE,
4575 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
4578 Ybomb_eat, FALSE, FALSE,
4579 EL_BOMB, ACTION_ACTIVATING, -1
4582 Xballoon, TRUE, FALSE,
4586 Yballoon_n, FALSE, FALSE,
4587 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
4590 Yballoon_nB, FALSE, TRUE,
4591 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
4594 Yballoon_e, FALSE, FALSE,
4595 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
4598 Yballoon_eB, FALSE, TRUE,
4599 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
4602 Yballoon_s, FALSE, FALSE,
4603 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
4606 Yballoon_sB, FALSE, TRUE,
4607 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
4610 Yballoon_w, FALSE, FALSE,
4611 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
4614 Yballoon_wB, FALSE, TRUE,
4615 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
4618 Xgrass, TRUE, FALSE,
4619 EL_EMC_GRASS, -1, -1
4622 Ygrass_nB, FALSE, FALSE,
4623 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_UP
4626 Ygrass_eB, FALSE, FALSE,
4627 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_RIGHT
4630 Ygrass_sB, FALSE, FALSE,
4631 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_DOWN
4634 Ygrass_wB, FALSE, FALSE,
4635 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_LEFT
4642 Ydirt_nB, FALSE, FALSE,
4643 EL_SAND, ACTION_DIGGING, MV_BIT_UP
4646 Ydirt_eB, FALSE, FALSE,
4647 EL_SAND, ACTION_DIGGING, MV_BIT_RIGHT
4650 Ydirt_sB, FALSE, FALSE,
4651 EL_SAND, ACTION_DIGGING, MV_BIT_DOWN
4654 Ydirt_wB, FALSE, FALSE,
4655 EL_SAND, ACTION_DIGGING, MV_BIT_LEFT
4658 Xacid_ne, TRUE, FALSE,
4659 EL_ACID_POOL_TOPRIGHT, -1, -1
4662 Xacid_se, TRUE, FALSE,
4663 EL_ACID_POOL_BOTTOMRIGHT, -1, -1
4666 Xacid_s, TRUE, FALSE,
4667 EL_ACID_POOL_BOTTOM, -1, -1
4670 Xacid_sw, TRUE, FALSE,
4671 EL_ACID_POOL_BOTTOMLEFT, -1, -1
4674 Xacid_nw, TRUE, FALSE,
4675 EL_ACID_POOL_TOPLEFT, -1, -1
4678 Xacid_1, TRUE, FALSE,
4682 Xacid_2, FALSE, FALSE,
4686 Xacid_3, FALSE, FALSE,
4690 Xacid_4, FALSE, FALSE,
4694 Xacid_5, FALSE, FALSE,
4698 Xacid_6, FALSE, FALSE,
4702 Xacid_7, FALSE, FALSE,
4706 Xacid_8, FALSE, FALSE,
4710 Xball_1, TRUE, FALSE,
4711 EL_EMC_MAGIC_BALL, -1, -1
4714 Xball_1B, FALSE, FALSE,
4715 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
4718 Xball_2, FALSE, FALSE,
4719 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
4722 Xball_2B, FALSE, FALSE,
4723 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
4726 Yball_eat, FALSE, FALSE,
4727 EL_EMC_MAGIC_BALL, ACTION_DROPPING, -1
4730 Ykey_1_eat, FALSE, FALSE,
4731 EL_EM_KEY_1, ACTION_COLLECTING, -1
4734 Ykey_2_eat, FALSE, FALSE,
4735 EL_EM_KEY_2, ACTION_COLLECTING, -1
4738 Ykey_3_eat, FALSE, FALSE,
4739 EL_EM_KEY_3, ACTION_COLLECTING, -1
4742 Ykey_4_eat, FALSE, FALSE,
4743 EL_EM_KEY_4, ACTION_COLLECTING, -1
4746 Ykey_5_eat, FALSE, FALSE,
4747 EL_EMC_KEY_5, ACTION_COLLECTING, -1
4750 Ykey_6_eat, FALSE, FALSE,
4751 EL_EMC_KEY_6, ACTION_COLLECTING, -1
4754 Ykey_7_eat, FALSE, FALSE,
4755 EL_EMC_KEY_7, ACTION_COLLECTING, -1
4758 Ykey_8_eat, FALSE, FALSE,
4759 EL_EMC_KEY_8, ACTION_COLLECTING, -1
4762 Ylenses_eat, FALSE, FALSE,
4763 EL_EMC_LENSES, ACTION_COLLECTING, -1
4766 Ymagnify_eat, FALSE, FALSE,
4767 EL_EMC_MAGNIFIER, ACTION_COLLECTING, -1
4770 Ygrass_eat, FALSE, FALSE,
4771 EL_EMC_GRASS, ACTION_SNAPPING, -1
4774 Ydirt_eat, FALSE, FALSE,
4775 EL_SAND, ACTION_SNAPPING, -1
4778 Xgrow_ns, TRUE, FALSE,
4779 EL_EXPANDABLE_WALL_VERTICAL, -1, -1
4782 Ygrow_ns_eat, FALSE, FALSE,
4783 EL_EXPANDABLE_WALL_VERTICAL, ACTION_GROWING, -1
4786 Xgrow_ew, TRUE, FALSE,
4787 EL_EXPANDABLE_WALL_HORIZONTAL, -1, -1
4790 Ygrow_ew_eat, FALSE, FALSE,
4791 EL_EXPANDABLE_WALL_HORIZONTAL, ACTION_GROWING, -1
4794 Xwonderwall, TRUE, FALSE,
4795 EL_MAGIC_WALL, -1, -1
4798 XwonderwallB, FALSE, FALSE,
4799 EL_MAGIC_WALL, ACTION_ACTIVE, -1
4802 Xamoeba_1, TRUE, FALSE,
4803 EL_AMOEBA_DRY, ACTION_OTHER, -1
4806 Xamoeba_2, FALSE, FALSE,
4807 EL_AMOEBA_DRY, ACTION_OTHER, -1
4810 Xamoeba_3, FALSE, FALSE,
4811 EL_AMOEBA_DRY, ACTION_OTHER, -1
4814 Xamoeba_4, FALSE, FALSE,
4815 EL_AMOEBA_DRY, ACTION_OTHER, -1
4818 Xamoeba_5, TRUE, FALSE,
4819 EL_AMOEBA_WET, ACTION_OTHER, -1
4822 Xamoeba_6, FALSE, FALSE,
4823 EL_AMOEBA_WET, ACTION_OTHER, -1
4826 Xamoeba_7, FALSE, FALSE,
4827 EL_AMOEBA_WET, ACTION_OTHER, -1
4830 Xamoeba_8, FALSE, FALSE,
4831 EL_AMOEBA_WET, ACTION_OTHER, -1
4834 Xdoor_1, TRUE, FALSE,
4835 EL_EM_GATE_1, -1, -1
4838 Xdoor_2, TRUE, FALSE,
4839 EL_EM_GATE_2, -1, -1
4842 Xdoor_3, TRUE, FALSE,
4843 EL_EM_GATE_3, -1, -1
4846 Xdoor_4, TRUE, FALSE,
4847 EL_EM_GATE_4, -1, -1
4850 Xdoor_5, TRUE, FALSE,
4851 EL_EMC_GATE_5, -1, -1
4854 Xdoor_6, TRUE, FALSE,
4855 EL_EMC_GATE_6, -1, -1
4858 Xdoor_7, TRUE, FALSE,
4859 EL_EMC_GATE_7, -1, -1
4862 Xdoor_8, TRUE, FALSE,
4863 EL_EMC_GATE_8, -1, -1
4866 Xkey_1, TRUE, FALSE,
4870 Xkey_2, TRUE, FALSE,
4874 Xkey_3, TRUE, FALSE,
4878 Xkey_4, TRUE, FALSE,
4882 Xkey_5, TRUE, FALSE,
4883 EL_EMC_KEY_5, -1, -1
4886 Xkey_6, TRUE, FALSE,
4887 EL_EMC_KEY_6, -1, -1
4890 Xkey_7, TRUE, FALSE,
4891 EL_EMC_KEY_7, -1, -1
4894 Xkey_8, TRUE, FALSE,
4895 EL_EMC_KEY_8, -1, -1
4898 Xwind_n, TRUE, FALSE,
4899 EL_BALLOON_SWITCH_UP, -1, -1
4902 Xwind_e, TRUE, FALSE,
4903 EL_BALLOON_SWITCH_RIGHT, -1, -1
4906 Xwind_s, TRUE, FALSE,
4907 EL_BALLOON_SWITCH_DOWN, -1, -1
4910 Xwind_w, TRUE, FALSE,
4911 EL_BALLOON_SWITCH_LEFT, -1, -1
4914 Xwind_nesw, TRUE, FALSE,
4915 EL_BALLOON_SWITCH_ANY, -1, -1
4918 Xwind_stop, TRUE, FALSE,
4919 EL_BALLOON_SWITCH_NONE, -1, -1
4923 EL_EM_EXIT_CLOSED, -1, -1
4926 Xexit_1, TRUE, FALSE,
4927 EL_EM_EXIT_OPEN, -1, -1
4930 Xexit_2, FALSE, FALSE,
4931 EL_EM_EXIT_OPEN, -1, -1
4934 Xexit_3, FALSE, FALSE,
4935 EL_EM_EXIT_OPEN, -1, -1
4938 Xdynamite, TRUE, FALSE,
4939 EL_EM_DYNAMITE, -1, -1
4942 Ydynamite_eat, FALSE, FALSE,
4943 EL_EM_DYNAMITE, ACTION_COLLECTING, -1
4946 Xdynamite_1, TRUE, FALSE,
4947 EL_EM_DYNAMITE_ACTIVE, -1, -1
4950 Xdynamite_2, FALSE, FALSE,
4951 EL_EM_DYNAMITE_ACTIVE, -1, -1
4954 Xdynamite_3, FALSE, FALSE,
4955 EL_EM_DYNAMITE_ACTIVE, -1, -1
4958 Xdynamite_4, FALSE, FALSE,
4959 EL_EM_DYNAMITE_ACTIVE, -1, -1
4962 Xbumper, TRUE, FALSE,
4963 EL_EMC_SPRING_BUMPER, -1, -1
4966 XbumperB, FALSE, FALSE,
4967 EL_EMC_SPRING_BUMPER, ACTION_ACTIVE, -1
4970 Xwheel, TRUE, FALSE,
4971 EL_ROBOT_WHEEL, -1, -1
4974 XwheelB, FALSE, FALSE,
4975 EL_ROBOT_WHEEL, ACTION_ACTIVE, -1
4978 Xswitch, TRUE, FALSE,
4979 EL_EMC_MAGIC_BALL_SWITCH, -1, -1
4982 XswitchB, FALSE, FALSE,
4983 EL_EMC_MAGIC_BALL_SWITCH, ACTION_ACTIVE, -1
4987 EL_QUICKSAND_EMPTY, -1, -1
4990 Xsand_stone, TRUE, FALSE,
4991 EL_QUICKSAND_FULL, -1, -1
4994 Xsand_stonein_1, FALSE, TRUE,
4995 EL_ROCK, ACTION_FILLING, -1
4998 Xsand_stonein_2, FALSE, TRUE,
4999 EL_ROCK, ACTION_FILLING, -1
5002 Xsand_stonein_3, FALSE, TRUE,
5003 EL_ROCK, ACTION_FILLING, -1
5006 Xsand_stonein_4, FALSE, TRUE,
5007 EL_ROCK, ACTION_FILLING, -1
5011 Xsand_stonesand_1, FALSE, FALSE,
5012 EL_QUICKSAND_EMPTYING, -1, -1
5015 Xsand_stonesand_2, FALSE, FALSE,
5016 EL_QUICKSAND_EMPTYING, -1, -1
5019 Xsand_stonesand_3, FALSE, FALSE,
5020 EL_QUICKSAND_EMPTYING, -1, -1
5023 Xsand_stonesand_4, FALSE, FALSE,
5024 EL_QUICKSAND_EMPTYING, -1, -1
5027 Xsand_stonesand_quickout_1, FALSE, FALSE,
5028 EL_QUICKSAND_EMPTYING, -1, -1
5031 Xsand_stonesand_quickout_2, FALSE, FALSE,
5032 EL_QUICKSAND_EMPTYING, -1, -1
5036 Xsand_stonesand_1, FALSE, FALSE,
5037 EL_QUICKSAND_FULL, -1, -1
5040 Xsand_stonesand_2, FALSE, FALSE,
5041 EL_QUICKSAND_FULL, -1, -1
5044 Xsand_stonesand_3, FALSE, FALSE,
5045 EL_QUICKSAND_FULL, -1, -1
5048 Xsand_stonesand_4, FALSE, FALSE,
5049 EL_QUICKSAND_FULL, -1, -1
5053 Xsand_stoneout_1, FALSE, FALSE,
5054 EL_ROCK, ACTION_EMPTYING, -1
5057 Xsand_stoneout_2, FALSE, FALSE,
5058 EL_ROCK, ACTION_EMPTYING, -1
5062 Xsand_sandstone_1, FALSE, FALSE,
5063 EL_QUICKSAND_FILLING, -1, -1
5066 Xsand_sandstone_2, FALSE, FALSE,
5067 EL_QUICKSAND_FILLING, -1, -1
5070 Xsand_sandstone_3, FALSE, FALSE,
5071 EL_QUICKSAND_FILLING, -1, -1
5074 Xsand_sandstone_4, FALSE, FALSE,
5075 EL_QUICKSAND_FILLING, -1, -1
5079 Xsand_sandstone_1, FALSE, FALSE,
5080 EL_QUICKSAND_FULL, -1, -1
5083 Xsand_sandstone_2, FALSE, FALSE,
5084 EL_QUICKSAND_FULL, -1, -1
5087 Xsand_sandstone_3, FALSE, FALSE,
5088 EL_QUICKSAND_FULL, -1, -1
5091 Xsand_sandstone_4, FALSE, FALSE,
5092 EL_QUICKSAND_FULL, -1, -1
5096 Xplant, TRUE, FALSE,
5097 EL_EMC_PLANT, -1, -1
5100 Yplant, FALSE, FALSE,
5101 EL_EMC_PLANT, -1, -1
5104 Xlenses, TRUE, FALSE,
5105 EL_EMC_LENSES, -1, -1
5108 Xmagnify, TRUE, FALSE,
5109 EL_EMC_MAGNIFIER, -1, -1
5112 Xdripper, TRUE, FALSE,
5113 EL_EMC_DRIPPER, -1, -1
5116 XdripperB, FALSE, FALSE,
5117 EL_EMC_DRIPPER, ACTION_ACTIVE, -1
5120 Xfake_blank, TRUE, FALSE,
5121 EL_INVISIBLE_WALL, -1, -1
5124 Xfake_blankB, FALSE, FALSE,
5125 EL_INVISIBLE_WALL, ACTION_ACTIVE, -1
5128 Xfake_grass, TRUE, FALSE,
5129 EL_EMC_FAKE_GRASS, -1, -1
5132 Xfake_grassB, FALSE, FALSE,
5133 EL_EMC_FAKE_GRASS, ACTION_ACTIVE, -1
5136 Xfake_door_1, TRUE, FALSE,
5137 EL_EM_GATE_1_GRAY, -1, -1
5140 Xfake_door_2, TRUE, FALSE,
5141 EL_EM_GATE_2_GRAY, -1, -1
5144 Xfake_door_3, TRUE, FALSE,
5145 EL_EM_GATE_3_GRAY, -1, -1
5148 Xfake_door_4, TRUE, FALSE,
5149 EL_EM_GATE_4_GRAY, -1, -1
5152 Xfake_door_5, TRUE, FALSE,
5153 EL_EMC_GATE_5_GRAY, -1, -1
5156 Xfake_door_6, TRUE, FALSE,
5157 EL_EMC_GATE_6_GRAY, -1, -1
5160 Xfake_door_7, TRUE, FALSE,
5161 EL_EMC_GATE_7_GRAY, -1, -1
5164 Xfake_door_8, TRUE, FALSE,
5165 EL_EMC_GATE_8_GRAY, -1, -1
5168 Xfake_acid_1, TRUE, FALSE,
5169 EL_EMC_FAKE_ACID, -1, -1
5172 Xfake_acid_2, FALSE, FALSE,
5173 EL_EMC_FAKE_ACID, -1, -1
5176 Xfake_acid_3, FALSE, FALSE,
5177 EL_EMC_FAKE_ACID, -1, -1
5180 Xfake_acid_4, FALSE, FALSE,
5181 EL_EMC_FAKE_ACID, -1, -1
5184 Xfake_acid_5, FALSE, FALSE,
5185 EL_EMC_FAKE_ACID, -1, -1
5188 Xfake_acid_6, FALSE, FALSE,
5189 EL_EMC_FAKE_ACID, -1, -1
5192 Xfake_acid_7, FALSE, FALSE,
5193 EL_EMC_FAKE_ACID, -1, -1
5196 Xfake_acid_8, FALSE, FALSE,
5197 EL_EMC_FAKE_ACID, -1, -1
5200 Xsteel_1, TRUE, FALSE,
5201 EL_STEELWALL, -1, -1
5204 Xsteel_2, TRUE, FALSE,
5205 EL_EMC_STEELWALL_2, -1, -1
5208 Xsteel_3, TRUE, FALSE,
5209 EL_EMC_STEELWALL_3, -1, -1
5212 Xsteel_4, TRUE, FALSE,
5213 EL_EMC_STEELWALL_4, -1, -1
5216 Xwall_1, TRUE, FALSE,
5220 Xwall_2, TRUE, FALSE,
5221 EL_EMC_WALL_14, -1, -1
5224 Xwall_3, TRUE, FALSE,
5225 EL_EMC_WALL_15, -1, -1
5228 Xwall_4, TRUE, FALSE,
5229 EL_EMC_WALL_16, -1, -1
5232 Xround_wall_1, TRUE, FALSE,
5233 EL_WALL_SLIPPERY, -1, -1
5236 Xround_wall_2, TRUE, FALSE,
5237 EL_EMC_WALL_SLIPPERY_2, -1, -1
5240 Xround_wall_3, TRUE, FALSE,
5241 EL_EMC_WALL_SLIPPERY_3, -1, -1
5244 Xround_wall_4, TRUE, FALSE,
5245 EL_EMC_WALL_SLIPPERY_4, -1, -1
5248 Xdecor_1, TRUE, FALSE,
5249 EL_EMC_WALL_8, -1, -1
5252 Xdecor_2, TRUE, FALSE,
5253 EL_EMC_WALL_6, -1, -1
5256 Xdecor_3, TRUE, FALSE,
5257 EL_EMC_WALL_4, -1, -1
5260 Xdecor_4, TRUE, FALSE,
5261 EL_EMC_WALL_7, -1, -1
5264 Xdecor_5, TRUE, FALSE,
5265 EL_EMC_WALL_5, -1, -1
5268 Xdecor_6, TRUE, FALSE,
5269 EL_EMC_WALL_9, -1, -1
5272 Xdecor_7, TRUE, FALSE,
5273 EL_EMC_WALL_10, -1, -1
5276 Xdecor_8, TRUE, FALSE,
5277 EL_EMC_WALL_1, -1, -1
5280 Xdecor_9, TRUE, FALSE,
5281 EL_EMC_WALL_2, -1, -1
5284 Xdecor_10, TRUE, FALSE,
5285 EL_EMC_WALL_3, -1, -1
5288 Xdecor_11, TRUE, FALSE,
5289 EL_EMC_WALL_11, -1, -1
5292 Xdecor_12, TRUE, FALSE,
5293 EL_EMC_WALL_12, -1, -1
5296 Xalpha_0, TRUE, FALSE,
5297 EL_CHAR('0'), -1, -1
5300 Xalpha_1, TRUE, FALSE,
5301 EL_CHAR('1'), -1, -1
5304 Xalpha_2, TRUE, FALSE,
5305 EL_CHAR('2'), -1, -1
5308 Xalpha_3, TRUE, FALSE,
5309 EL_CHAR('3'), -1, -1
5312 Xalpha_4, TRUE, FALSE,
5313 EL_CHAR('4'), -1, -1
5316 Xalpha_5, TRUE, FALSE,
5317 EL_CHAR('5'), -1, -1
5320 Xalpha_6, TRUE, FALSE,
5321 EL_CHAR('6'), -1, -1
5324 Xalpha_7, TRUE, FALSE,
5325 EL_CHAR('7'), -1, -1
5328 Xalpha_8, TRUE, FALSE,
5329 EL_CHAR('8'), -1, -1
5332 Xalpha_9, TRUE, FALSE,
5333 EL_CHAR('9'), -1, -1
5336 Xalpha_excla, TRUE, FALSE,
5337 EL_CHAR('!'), -1, -1
5340 Xalpha_quote, TRUE, FALSE,
5341 EL_CHAR('"'), -1, -1
5344 Xalpha_comma, TRUE, FALSE,
5345 EL_CHAR(','), -1, -1
5348 Xalpha_minus, TRUE, FALSE,
5349 EL_CHAR('-'), -1, -1
5352 Xalpha_perio, TRUE, FALSE,
5353 EL_CHAR('.'), -1, -1
5356 Xalpha_colon, TRUE, FALSE,
5357 EL_CHAR(':'), -1, -1
5360 Xalpha_quest, TRUE, FALSE,
5361 EL_CHAR('?'), -1, -1
5364 Xalpha_a, TRUE, FALSE,
5365 EL_CHAR('A'), -1, -1
5368 Xalpha_b, TRUE, FALSE,
5369 EL_CHAR('B'), -1, -1
5372 Xalpha_c, TRUE, FALSE,
5373 EL_CHAR('C'), -1, -1
5376 Xalpha_d, TRUE, FALSE,
5377 EL_CHAR('D'), -1, -1
5380 Xalpha_e, TRUE, FALSE,
5381 EL_CHAR('E'), -1, -1
5384 Xalpha_f, TRUE, FALSE,
5385 EL_CHAR('F'), -1, -1
5388 Xalpha_g, TRUE, FALSE,
5389 EL_CHAR('G'), -1, -1
5392 Xalpha_h, TRUE, FALSE,
5393 EL_CHAR('H'), -1, -1
5396 Xalpha_i, TRUE, FALSE,
5397 EL_CHAR('I'), -1, -1
5400 Xalpha_j, TRUE, FALSE,
5401 EL_CHAR('J'), -1, -1
5404 Xalpha_k, TRUE, FALSE,
5405 EL_CHAR('K'), -1, -1
5408 Xalpha_l, TRUE, FALSE,
5409 EL_CHAR('L'), -1, -1
5412 Xalpha_m, TRUE, FALSE,
5413 EL_CHAR('M'), -1, -1
5416 Xalpha_n, TRUE, FALSE,
5417 EL_CHAR('N'), -1, -1
5420 Xalpha_o, TRUE, FALSE,
5421 EL_CHAR('O'), -1, -1
5424 Xalpha_p, TRUE, FALSE,
5425 EL_CHAR('P'), -1, -1
5428 Xalpha_q, TRUE, FALSE,
5429 EL_CHAR('Q'), -1, -1
5432 Xalpha_r, TRUE, FALSE,
5433 EL_CHAR('R'), -1, -1
5436 Xalpha_s, TRUE, FALSE,
5437 EL_CHAR('S'), -1, -1
5440 Xalpha_t, TRUE, FALSE,
5441 EL_CHAR('T'), -1, -1
5444 Xalpha_u, TRUE, FALSE,
5445 EL_CHAR('U'), -1, -1
5448 Xalpha_v, TRUE, FALSE,
5449 EL_CHAR('V'), -1, -1
5452 Xalpha_w, TRUE, FALSE,
5453 EL_CHAR('W'), -1, -1
5456 Xalpha_x, TRUE, FALSE,
5457 EL_CHAR('X'), -1, -1
5460 Xalpha_y, TRUE, FALSE,
5461 EL_CHAR('Y'), -1, -1
5464 Xalpha_z, TRUE, FALSE,
5465 EL_CHAR('Z'), -1, -1
5468 Xalpha_arrow_e, TRUE, FALSE,
5469 EL_CHAR('>'), -1, -1
5472 Xalpha_arrow_w, TRUE, FALSE,
5473 EL_CHAR('<'), -1, -1
5476 Xalpha_copyr, TRUE, FALSE,
5477 EL_CHAR('©'), -1, -1
5481 Xboom_bug, FALSE, FALSE,
5482 EL_BUG, ACTION_EXPLODING, -1
5485 Xboom_bomb, FALSE, FALSE,
5486 EL_BOMB, ACTION_EXPLODING, -1
5489 Xboom_android, FALSE, FALSE,
5490 EL_EMC_ANDROID, ACTION_OTHER, -1
5493 Xboom_1, FALSE, FALSE,
5494 EL_DEFAULT, ACTION_EXPLODING, -1
5497 Xboom_2, FALSE, FALSE,
5498 EL_DEFAULT, ACTION_EXPLODING, -1
5501 Znormal, FALSE, FALSE,
5505 Zdynamite, FALSE, FALSE,
5509 Zplayer, FALSE, FALSE,
5513 ZBORDER, FALSE, FALSE,
5523 static struct Mapping_EM_to_RND_player
5532 em_player_mapping_list[] =
5536 EL_PLAYER_1, ACTION_MOVING, MV_BIT_UP,
5540 EL_PLAYER_1, ACTION_MOVING, MV_BIT_RIGHT,
5544 EL_PLAYER_1, ACTION_MOVING, MV_BIT_DOWN,
5548 EL_PLAYER_1, ACTION_MOVING, MV_BIT_LEFT,
5552 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_UP,
5556 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_RIGHT,
5560 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_DOWN,
5564 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_LEFT,
5568 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_UP,
5572 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_RIGHT,
5576 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_DOWN,
5580 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_LEFT,
5584 EL_PLAYER_2, ACTION_MOVING, MV_BIT_UP,
5588 EL_PLAYER_2, ACTION_MOVING, MV_BIT_RIGHT,
5592 EL_PLAYER_2, ACTION_MOVING, MV_BIT_DOWN,
5596 EL_PLAYER_2, ACTION_MOVING, MV_BIT_LEFT,
5600 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_UP,
5604 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_RIGHT,
5608 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_DOWN,
5612 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_LEFT,
5616 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_UP,
5620 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_RIGHT,
5624 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_DOWN,
5628 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_LEFT,
5632 EL_PLAYER_1, ACTION_DEFAULT, -1,
5636 EL_PLAYER_2, ACTION_DEFAULT, -1,
5640 EL_PLAYER_3, ACTION_MOVING, MV_BIT_UP,
5644 EL_PLAYER_3, ACTION_MOVING, MV_BIT_RIGHT,
5648 EL_PLAYER_3, ACTION_MOVING, MV_BIT_DOWN,
5652 EL_PLAYER_3, ACTION_MOVING, MV_BIT_LEFT,
5656 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_UP,
5660 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_RIGHT,
5664 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_DOWN,
5668 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_LEFT,
5672 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_UP,
5676 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_RIGHT,
5680 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_DOWN,
5684 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_LEFT,
5688 EL_PLAYER_4, ACTION_MOVING, MV_BIT_UP,
5692 EL_PLAYER_4, ACTION_MOVING, MV_BIT_RIGHT,
5696 EL_PLAYER_4, ACTION_MOVING, MV_BIT_DOWN,
5700 EL_PLAYER_4, ACTION_MOVING, MV_BIT_LEFT,
5704 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_UP,
5708 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_RIGHT,
5712 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_DOWN,
5716 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_LEFT,
5720 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_UP,
5724 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_RIGHT,
5728 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_DOWN,
5732 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_LEFT,
5736 EL_PLAYER_3, ACTION_DEFAULT, -1,
5740 EL_PLAYER_4, ACTION_DEFAULT, -1,
5749 int map_element_RND_to_EM(int element_rnd)
5751 static unsigned short mapping_RND_to_EM[NUM_FILE_ELEMENTS];
5752 static boolean mapping_initialized = FALSE;
5754 if (!mapping_initialized)
5758 /* return "Xalpha_quest" for all undefined elements in mapping array */
5759 for (i = 0; i < NUM_FILE_ELEMENTS; i++)
5760 mapping_RND_to_EM[i] = Xalpha_quest;
5762 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5763 if (em_object_mapping_list[i].is_rnd_to_em_mapping)
5764 mapping_RND_to_EM[em_object_mapping_list[i].element_rnd] =
5765 em_object_mapping_list[i].element_em;
5767 mapping_initialized = TRUE;
5770 if (element_rnd >= 0 && element_rnd < NUM_FILE_ELEMENTS)
5771 return mapping_RND_to_EM[element_rnd];
5773 Error(ERR_WARN, "invalid RND level element %d", element_rnd);
5778 int map_element_EM_to_RND(int element_em)
5780 static unsigned short mapping_EM_to_RND[TILE_MAX];
5781 static boolean mapping_initialized = FALSE;
5783 if (!mapping_initialized)
5787 /* return "EL_UNKNOWN" for all undefined elements in mapping array */
5788 for (i = 0; i < TILE_MAX; i++)
5789 mapping_EM_to_RND[i] = EL_UNKNOWN;
5791 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5792 mapping_EM_to_RND[em_object_mapping_list[i].element_em] =
5793 em_object_mapping_list[i].element_rnd;
5795 mapping_initialized = TRUE;
5798 if (element_em >= 0 && element_em < TILE_MAX)
5799 return mapping_EM_to_RND[element_em];
5801 Error(ERR_WARN, "invalid EM level element %d", element_em);
5806 void map_android_clone_elements_RND_to_EM(struct LevelInfo *level)
5808 struct LevelInfo_EM *level_em = level->native_em_level;
5809 struct LEVEL *lev = level_em->lev;
5812 for (i = 0; i < TILE_MAX; i++)
5813 lev->android_array[i] = Xblank;
5815 for (i = 0; i < level->num_android_clone_elements; i++)
5817 int element_rnd = level->android_clone_element[i];
5818 int element_em = map_element_RND_to_EM(element_rnd);
5820 for (j = 0; em_object_mapping_list[j].element_em != -1; j++)
5821 if (em_object_mapping_list[j].element_rnd == element_rnd)
5822 lev->android_array[em_object_mapping_list[j].element_em] = element_em;
5826 void map_android_clone_elements_EM_to_RND(struct LevelInfo *level)
5828 struct LevelInfo_EM *level_em = level->native_em_level;
5829 struct LEVEL *lev = level_em->lev;
5832 level->num_android_clone_elements = 0;
5834 for (i = 0; i < TILE_MAX; i++)
5836 int element_em = lev->android_array[i];
5838 boolean element_found = FALSE;
5840 if (element_em == Xblank)
5843 element_rnd = map_element_EM_to_RND(element_em);
5845 for (j = 0; j < level->num_android_clone_elements; j++)
5846 if (level->android_clone_element[j] == element_rnd)
5847 element_found = TRUE;
5851 level->android_clone_element[level->num_android_clone_elements++] =
5854 if (level->num_android_clone_elements == MAX_ANDROID_ELEMENTS)
5859 if (level->num_android_clone_elements == 0)
5861 level->num_android_clone_elements = 1;
5862 level->android_clone_element[0] = EL_EMPTY;
5866 int map_direction_RND_to_EM(int direction)
5868 return (direction == MV_UP ? 0 :
5869 direction == MV_RIGHT ? 1 :
5870 direction == MV_DOWN ? 2 :
5871 direction == MV_LEFT ? 3 :
5875 int map_direction_EM_to_RND(int direction)
5877 return (direction == 0 ? MV_UP :
5878 direction == 1 ? MV_RIGHT :
5879 direction == 2 ? MV_DOWN :
5880 direction == 3 ? MV_LEFT :
5884 int get_next_element(int element)
5888 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
5889 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
5890 case EL_QUICKSAND_FAST_FILLING: return EL_QUICKSAND_FAST_FULL;
5891 case EL_QUICKSAND_FAST_EMPTYING: return EL_QUICKSAND_FAST_EMPTY;
5892 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
5893 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
5894 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
5895 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
5896 case EL_DC_MAGIC_WALL_FILLING: return EL_DC_MAGIC_WALL_FULL;
5897 case EL_DC_MAGIC_WALL_EMPTYING: return EL_DC_MAGIC_WALL_ACTIVE;
5898 case EL_AMOEBA_DROPPING: return EL_AMOEBA_WET;
5900 default: return element;
5905 int el_act_dir2img(int element, int action, int direction)
5907 element = GFX_ELEMENT(element);
5909 if (direction == MV_NONE)
5910 return element_info[element].graphic[action];
5912 direction = MV_DIR_TO_BIT(direction);
5914 return element_info[element].direction_graphic[action][direction];
5917 int el_act_dir2img(int element, int action, int direction)
5919 element = GFX_ELEMENT(element);
5920 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
5922 /* direction_graphic[][] == graphic[] for undefined direction graphics */
5923 return element_info[element].direction_graphic[action][direction];
5928 static int el_act_dir2crm(int element, int action, int direction)
5930 element = GFX_ELEMENT(element);
5932 if (direction == MV_NONE)
5933 return element_info[element].crumbled[action];
5935 direction = MV_DIR_TO_BIT(direction);
5937 return element_info[element].direction_crumbled[action][direction];
5940 static int el_act_dir2crm(int element, int action, int direction)
5942 element = GFX_ELEMENT(element);
5943 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
5945 /* direction_graphic[][] == graphic[] for undefined direction graphics */
5946 return element_info[element].direction_crumbled[action][direction];
5950 int el_act2img(int element, int action)
5952 element = GFX_ELEMENT(element);
5954 return element_info[element].graphic[action];
5957 int el_act2crm(int element, int action)
5959 element = GFX_ELEMENT(element);
5961 return element_info[element].crumbled[action];
5964 int el_dir2img(int element, int direction)
5966 element = GFX_ELEMENT(element);
5968 return el_act_dir2img(element, ACTION_DEFAULT, direction);
5971 int el2baseimg(int element)
5973 return element_info[element].graphic[ACTION_DEFAULT];
5976 int el2img(int element)
5978 element = GFX_ELEMENT(element);
5980 return element_info[element].graphic[ACTION_DEFAULT];
5983 int el2edimg(int element)
5985 element = GFX_ELEMENT(element);
5987 return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
5990 int el2preimg(int element)
5992 element = GFX_ELEMENT(element);
5994 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];
5997 int el2panelimg(int element)
5999 element = GFX_ELEMENT(element);
6001 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PANEL];
6004 int font2baseimg(int font_nr)
6006 return font_info[font_nr].special_graphic[GFX_SPECIAL_ARG_DEFAULT];
6009 int getBeltNrFromBeltElement(int element)
6011 return (element < EL_CONVEYOR_BELT_2_LEFT ? 0 :
6012 element < EL_CONVEYOR_BELT_3_LEFT ? 1 :
6013 element < EL_CONVEYOR_BELT_4_LEFT ? 2 : 3);
6016 int getBeltNrFromBeltActiveElement(int element)
6018 return (element < EL_CONVEYOR_BELT_2_LEFT_ACTIVE ? 0 :
6019 element < EL_CONVEYOR_BELT_3_LEFT_ACTIVE ? 1 :
6020 element < EL_CONVEYOR_BELT_4_LEFT_ACTIVE ? 2 : 3);
6023 int getBeltNrFromBeltSwitchElement(int element)
6025 return (element < EL_CONVEYOR_BELT_2_SWITCH_LEFT ? 0 :
6026 element < EL_CONVEYOR_BELT_3_SWITCH_LEFT ? 1 :
6027 element < EL_CONVEYOR_BELT_4_SWITCH_LEFT ? 2 : 3);
6030 int getBeltDirNrFromBeltElement(int element)
6032 static int belt_base_element[4] =
6034 EL_CONVEYOR_BELT_1_LEFT,
6035 EL_CONVEYOR_BELT_2_LEFT,
6036 EL_CONVEYOR_BELT_3_LEFT,
6037 EL_CONVEYOR_BELT_4_LEFT
6040 int belt_nr = getBeltNrFromBeltElement(element);
6041 int belt_dir_nr = element - belt_base_element[belt_nr];
6043 return (belt_dir_nr % 3);
6046 int getBeltDirNrFromBeltSwitchElement(int element)
6048 static int belt_base_element[4] =
6050 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
6051 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
6052 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
6053 EL_CONVEYOR_BELT_4_SWITCH_LEFT
6056 int belt_nr = getBeltNrFromBeltSwitchElement(element);
6057 int belt_dir_nr = element - belt_base_element[belt_nr];
6059 return (belt_dir_nr % 3);
6062 int getBeltDirFromBeltElement(int element)
6064 static int belt_move_dir[3] =
6071 int belt_dir_nr = getBeltDirNrFromBeltElement(element);
6073 return belt_move_dir[belt_dir_nr];
6076 int getBeltDirFromBeltSwitchElement(int element)
6078 static int belt_move_dir[3] =
6085 int belt_dir_nr = getBeltDirNrFromBeltSwitchElement(element);
6087 return belt_move_dir[belt_dir_nr];
6090 int getBeltElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
6092 static int belt_base_element[4] =
6094 EL_CONVEYOR_BELT_1_LEFT,
6095 EL_CONVEYOR_BELT_2_LEFT,
6096 EL_CONVEYOR_BELT_3_LEFT,
6097 EL_CONVEYOR_BELT_4_LEFT
6100 return belt_base_element[belt_nr] + belt_dir_nr;
6103 int getBeltElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
6105 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
6107 return getBeltElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
6110 int getBeltSwitchElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
6112 static int belt_base_element[4] =
6114 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
6115 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
6116 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
6117 EL_CONVEYOR_BELT_4_SWITCH_LEFT
6120 return belt_base_element[belt_nr] + belt_dir_nr;
6123 int getBeltSwitchElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
6125 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
6127 return getBeltSwitchElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
6130 int getNumActivePlayers_EM()
6132 int num_players = 0;
6138 for (i = 0; i < MAX_PLAYERS; i++)
6139 if (tape.player_participates[i])
6145 int getGameFrameDelay_EM(int native_em_game_frame_delay)
6147 int game_frame_delay_value;
6149 game_frame_delay_value =
6150 (tape.playing && tape.fast_forward ? FfwdFrameDelay :
6151 GameFrameDelay == GAME_FRAME_DELAY ? native_em_game_frame_delay :
6154 if (tape.playing && tape.warp_forward && !tape.pausing)
6155 game_frame_delay_value = 0;
6157 return game_frame_delay_value;
6160 unsigned int InitRND(long seed)
6162 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
6163 return InitEngineRandom_EM(seed);
6164 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
6165 return InitEngineRandom_SP(seed);
6167 return InitEngineRandom_RND(seed);
6171 static struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
6172 static struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
6175 inline static int get_effective_element_EM(int tile, int frame_em)
6177 int element = object_mapping[tile].element_rnd;
6178 int action = object_mapping[tile].action;
6179 boolean is_backside = object_mapping[tile].is_backside;
6180 boolean action_removing = (action == ACTION_DIGGING ||
6181 action == ACTION_SNAPPING ||
6182 action == ACTION_COLLECTING);
6188 case Yacid_splash_eB:
6189 case Yacid_splash_wB:
6190 return (frame_em > 5 ? EL_EMPTY : element);
6196 else /* frame_em == 7 */
6200 case Yacid_splash_eB:
6201 case Yacid_splash_wB:
6204 case Yemerald_stone:
6207 case Ydiamond_stone:
6211 case Xdrip_stretchB:
6230 case Xsand_stonein_1:
6231 case Xsand_stonein_2:
6232 case Xsand_stonein_3:
6233 case Xsand_stonein_4:
6237 return (is_backside || action_removing ? EL_EMPTY : element);
6242 inline static boolean check_linear_animation_EM(int tile)
6246 case Xsand_stonesand_1:
6247 case Xsand_stonesand_quickout_1:
6248 case Xsand_sandstone_1:
6249 case Xsand_stonein_1:
6250 case Xsand_stoneout_1:
6275 inline static void set_crumbled_graphics_EM(struct GraphicInfo_EM *g_em,
6276 boolean has_crumbled_graphics,
6277 int crumbled, int sync_frame)
6279 /* if element can be crumbled, but certain action graphics are just empty
6280 space (like instantly snapping sand to empty space in 1 frame), do not
6281 treat these empty space graphics as crumbled graphics in EMC engine */
6282 if (crumbled == IMG_EMPTY_SPACE)
6283 has_crumbled_graphics = FALSE;
6285 if (has_crumbled_graphics)
6287 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
6288 int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
6289 g_crumbled->anim_delay,
6290 g_crumbled->anim_mode,
6291 g_crumbled->anim_start_frame,
6294 getGraphicSource(crumbled, frame_crumbled, &g_em->crumbled_bitmap,
6295 &g_em->crumbled_src_x, &g_em->crumbled_src_y);
6297 g_em->crumbled_border_size = graphic_info[crumbled].border_size;
6299 g_em->has_crumbled_graphics = TRUE;
6303 g_em->crumbled_bitmap = NULL;
6304 g_em->crumbled_src_x = 0;
6305 g_em->crumbled_src_y = 0;
6306 g_em->crumbled_border_size = 0;
6308 g_em->has_crumbled_graphics = FALSE;
6312 void ResetGfxAnimation_EM(int x, int y, int tile)
6317 void SetGfxAnimation_EM(struct GraphicInfo_EM *g_em,
6318 int tile, int frame_em, int x, int y)
6320 int action = object_mapping[tile].action;
6322 int direction = object_mapping[tile].direction;
6323 int effective_element = get_effective_element_EM(tile, frame_em);
6324 int graphic = (direction == MV_NONE ?
6325 el_act2img(effective_element, action) :
6326 el_act_dir2img(effective_element, action, direction));
6327 struct GraphicInfo *g = &graphic_info[graphic];
6330 boolean action_removing = (action == ACTION_DIGGING ||
6331 action == ACTION_SNAPPING ||
6332 action == ACTION_COLLECTING);
6333 boolean action_moving = (action == ACTION_FALLING ||
6334 action == ACTION_MOVING ||
6335 action == ACTION_PUSHING ||
6336 action == ACTION_EATING ||
6337 action == ACTION_FILLING ||
6338 action == ACTION_EMPTYING);
6339 boolean action_falling = (action == ACTION_FALLING ||
6340 action == ACTION_FILLING ||
6341 action == ACTION_EMPTYING);
6343 /* special case: graphic uses "2nd movement tile" and has defined
6344 7 frames for movement animation (or less) => use default graphic
6345 for last (8th) frame which ends the movement animation */
6346 if (g->double_movement && g->anim_frames < 8 && frame_em == 7)
6348 action = ACTION_DEFAULT; /* (keep action_* unchanged for now) */
6349 graphic = (direction == MV_NONE ?
6350 el_act2img(effective_element, action) :
6351 el_act_dir2img(effective_element, action, direction));
6353 g = &graphic_info[graphic];
6357 if (tile == Xsand_stonesand_1 ||
6358 tile == Xsand_stonesand_2 ||
6359 tile == Xsand_stonesand_3 ||
6360 tile == Xsand_stonesand_4)
6361 printf("::: 1: quicksand frame %d [%d]\n", GfxFrame[x][y], tile);
6365 if ((action_removing || check_linear_animation_EM(tile)) && frame_em == 0)
6369 // printf("::: resetting... [%d]\n", tile);
6372 if (action_removing || check_linear_animation_EM(tile))
6374 GfxFrame[x][y] = frame_em;
6376 // printf("::: resetting... [%d]\n", tile);
6379 else if (action_moving)
6381 boolean is_backside = object_mapping[tile].is_backside;
6385 int direction = object_mapping[tile].direction;
6386 int move_dir = (action_falling ? MV_DOWN : direction);
6391 /* !!! TEST !!! NEW !!! DOES NOT WORK RIGHT YET !!! */
6392 if (g->double_movement && frame_em == 0)
6396 // printf("::: resetting... [%d]\n", tile);
6400 if (move_dir == MV_LEFT)
6401 GfxFrame[x - 1][y] = GfxFrame[x][y];
6402 else if (move_dir == MV_RIGHT)
6403 GfxFrame[x + 1][y] = GfxFrame[x][y];
6404 else if (move_dir == MV_UP)
6405 GfxFrame[x][y - 1] = GfxFrame[x][y];
6406 else if (move_dir == MV_DOWN)
6407 GfxFrame[x][y + 1] = GfxFrame[x][y];
6414 /* special case: animation for Xsand_stonesand_quickout_1/2 twice as fast */
6415 if (tile == Xsand_stonesand_quickout_1 ||
6416 tile == Xsand_stonesand_quickout_2)
6421 if (tile == Xsand_stonesand_1 ||
6422 tile == Xsand_stonesand_2 ||
6423 tile == Xsand_stonesand_3 ||
6424 tile == Xsand_stonesand_4)
6425 printf("::: 2: quicksand frame %d [%d]\n", GfxFrame[x][y], tile);
6429 if (graphic_info[graphic].anim_global_sync)
6430 sync_frame = FrameCounter;
6431 else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY))
6432 sync_frame = GfxFrame[x][y];
6434 sync_frame = 0; /* playfield border (pseudo steel) */
6436 SetRandomAnimationValue(x, y);
6438 int frame = getAnimationFrame(g->anim_frames,
6441 g->anim_start_frame,
6444 g_em->unique_identifier =
6445 (graphic << 16) | ((frame % 8) << 12) | (g_em->width << 6) | g_em->height;
6449 void getGraphicSourceObjectExt_EM(struct GraphicInfo_EM *g_em,
6450 int tile, int frame_em, int x, int y)
6452 int action = object_mapping[tile].action;
6453 int direction = object_mapping[tile].direction;
6454 boolean is_backside = object_mapping[tile].is_backside;
6455 int effective_element = get_effective_element_EM(tile, frame_em);
6457 int effective_action = action;
6459 int effective_action = (frame_em < 7 ? action : ACTION_DEFAULT);
6461 int graphic = (direction == MV_NONE ?
6462 el_act2img(effective_element, effective_action) :
6463 el_act_dir2img(effective_element, effective_action,
6465 int crumbled = (direction == MV_NONE ?
6466 el_act2crm(effective_element, effective_action) :
6467 el_act_dir2crm(effective_element, effective_action,
6469 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
6470 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
6471 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
6472 struct GraphicInfo *g = &graphic_info[graphic];
6474 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
6478 /* special case: graphic uses "2nd movement tile" and has defined
6479 7 frames for movement animation (or less) => use default graphic
6480 for last (8th) frame which ends the movement animation */
6481 if (g->double_movement && g->anim_frames < 8 && frame_em == 7)
6483 effective_action = ACTION_DEFAULT;
6484 graphic = (direction == MV_NONE ?
6485 el_act2img(effective_element, effective_action) :
6486 el_act_dir2img(effective_element, effective_action,
6488 crumbled = (direction == MV_NONE ?
6489 el_act2crm(effective_element, effective_action) :
6490 el_act_dir2crm(effective_element, effective_action,
6493 g = &graphic_info[graphic];
6503 if (frame_em == 0) /* reset animation frame for certain elements */
6505 if (check_linear_animation_EM(tile))
6510 if (graphic_info[graphic].anim_global_sync)
6511 sync_frame = FrameCounter;
6512 else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY))
6513 sync_frame = GfxFrame[x][y];
6515 sync_frame = 0; /* playfield border (pseudo steel) */
6517 SetRandomAnimationValue(x, y);
6522 int xxx_sync_frame = (i == Xdrip_stretch ? 7 :
6523 i == Xdrip_stretchB ? 7 :
6524 i == Ydrip_s2 ? j + 8 :
6525 i == Ydrip_s2B ? j + 8 :
6534 i == Xfake_acid_1 ? 0 :
6535 i == Xfake_acid_2 ? 10 :
6536 i == Xfake_acid_3 ? 20 :
6537 i == Xfake_acid_4 ? 30 :
6538 i == Xfake_acid_5 ? 40 :
6539 i == Xfake_acid_6 ? 50 :
6540 i == Xfake_acid_7 ? 60 :
6541 i == Xfake_acid_8 ? 70 :
6543 i == Xball_2B ? j + 8 :
6544 i == Yball_eat ? j + 1 :
6545 i == Ykey_1_eat ? j + 1 :
6546 i == Ykey_2_eat ? j + 1 :
6547 i == Ykey_3_eat ? j + 1 :
6548 i == Ykey_4_eat ? j + 1 :
6549 i == Ykey_5_eat ? j + 1 :
6550 i == Ykey_6_eat ? j + 1 :
6551 i == Ykey_7_eat ? j + 1 :
6552 i == Ykey_8_eat ? j + 1 :
6553 i == Ylenses_eat ? j + 1 :
6554 i == Ymagnify_eat ? j + 1 :
6555 i == Ygrass_eat ? j + 1 :
6556 i == Ydirt_eat ? j + 1 :
6557 i == Xamoeba_1 ? 0 :
6558 i == Xamoeba_2 ? 1 :
6559 i == Xamoeba_3 ? 2 :
6560 i == Xamoeba_4 ? 3 :
6561 i == Xamoeba_5 ? 0 :
6562 i == Xamoeba_6 ? 1 :
6563 i == Xamoeba_7 ? 2 :
6564 i == Xamoeba_8 ? 3 :
6565 i == Xexit_2 ? j + 8 :
6566 i == Xexit_3 ? j + 16 :
6567 i == Xdynamite_1 ? 0 :
6568 i == Xdynamite_2 ? 8 :
6569 i == Xdynamite_3 ? 16 :
6570 i == Xdynamite_4 ? 24 :
6571 i == Xsand_stonein_1 ? j + 1 :
6572 i == Xsand_stonein_2 ? j + 9 :
6573 i == Xsand_stonein_3 ? j + 17 :
6574 i == Xsand_stonein_4 ? j + 25 :
6575 i == Xsand_stoneout_1 && j == 0 ? 0 :
6576 i == Xsand_stoneout_1 && j == 1 ? 0 :
6577 i == Xsand_stoneout_1 && j == 2 ? 1 :
6578 i == Xsand_stoneout_1 && j == 3 ? 2 :
6579 i == Xsand_stoneout_1 && j == 4 ? 2 :
6580 i == Xsand_stoneout_1 && j == 5 ? 3 :
6581 i == Xsand_stoneout_1 && j == 6 ? 4 :
6582 i == Xsand_stoneout_1 && j == 7 ? 4 :
6583 i == Xsand_stoneout_2 && j == 0 ? 5 :
6584 i == Xsand_stoneout_2 && j == 1 ? 6 :
6585 i == Xsand_stoneout_2 && j == 2 ? 7 :
6586 i == Xsand_stoneout_2 && j == 3 ? 8 :
6587 i == Xsand_stoneout_2 && j == 4 ? 9 :
6588 i == Xsand_stoneout_2 && j == 5 ? 11 :
6589 i == Xsand_stoneout_2 && j == 6 ? 13 :
6590 i == Xsand_stoneout_2 && j == 7 ? 15 :
6591 i == Xboom_bug && j == 1 ? 2 :
6592 i == Xboom_bug && j == 2 ? 2 :
6593 i == Xboom_bug && j == 3 ? 4 :
6594 i == Xboom_bug && j == 4 ? 4 :
6595 i == Xboom_bug && j == 5 ? 2 :
6596 i == Xboom_bug && j == 6 ? 2 :
6597 i == Xboom_bug && j == 7 ? 0 :
6598 i == Xboom_bomb && j == 1 ? 2 :
6599 i == Xboom_bomb && j == 2 ? 2 :
6600 i == Xboom_bomb && j == 3 ? 4 :
6601 i == Xboom_bomb && j == 4 ? 4 :
6602 i == Xboom_bomb && j == 5 ? 2 :
6603 i == Xboom_bomb && j == 6 ? 2 :
6604 i == Xboom_bomb && j == 7 ? 0 :
6605 i == Xboom_android && j == 7 ? 6 :
6606 i == Xboom_1 && j == 1 ? 2 :
6607 i == Xboom_1 && j == 2 ? 2 :
6608 i == Xboom_1 && j == 3 ? 4 :
6609 i == Xboom_1 && j == 4 ? 4 :
6610 i == Xboom_1 && j == 5 ? 6 :
6611 i == Xboom_1 && j == 6 ? 6 :
6612 i == Xboom_1 && j == 7 ? 8 :
6613 i == Xboom_2 && j == 0 ? 8 :
6614 i == Xboom_2 && j == 1 ? 8 :
6615 i == Xboom_2 && j == 2 ? 10 :
6616 i == Xboom_2 && j == 3 ? 10 :
6617 i == Xboom_2 && j == 4 ? 10 :
6618 i == Xboom_2 && j == 5 ? 12 :
6619 i == Xboom_2 && j == 6 ? 12 :
6620 i == Xboom_2 && j == 7 ? 12 :
6622 special_animation && j == 4 ? 3 :
6623 effective_action != action ? 0 :
6629 int xxx_effective_action;
6630 int xxx_has_action_graphics;
6633 int element = object_mapping[i].element_rnd;
6634 int action = object_mapping[i].action;
6635 int direction = object_mapping[i].direction;
6636 boolean is_backside = object_mapping[i].is_backside;
6638 boolean action_removing = (action == ACTION_DIGGING ||
6639 action == ACTION_SNAPPING ||
6640 action == ACTION_COLLECTING);
6642 boolean action_exploding = ((action == ACTION_EXPLODING ||
6643 action == ACTION_SMASHED_BY_ROCK ||
6644 action == ACTION_SMASHED_BY_SPRING) &&
6645 element != EL_DIAMOND);
6646 boolean action_active = (action == ACTION_ACTIVE);
6647 boolean action_other = (action == ACTION_OTHER);
6651 int effective_element = get_effective_element_EM(i, j);
6653 int effective_element = (j > 5 && i == Yacid_splash_eB ? EL_EMPTY :
6654 j > 5 && i == Yacid_splash_wB ? EL_EMPTY :
6656 i == Xdrip_stretch ? element :
6657 i == Xdrip_stretchB ? element :
6658 i == Ydrip_s1 ? element :
6659 i == Ydrip_s1B ? element :
6660 i == Xball_1B ? element :
6661 i == Xball_2 ? element :
6662 i == Xball_2B ? element :
6663 i == Yball_eat ? element :
6664 i == Ykey_1_eat ? element :
6665 i == Ykey_2_eat ? element :
6666 i == Ykey_3_eat ? element :
6667 i == Ykey_4_eat ? element :
6668 i == Ykey_5_eat ? element :
6669 i == Ykey_6_eat ? element :
6670 i == Ykey_7_eat ? element :
6671 i == Ykey_8_eat ? element :
6672 i == Ylenses_eat ? element :
6673 i == Ymagnify_eat ? element :
6674 i == Ygrass_eat ? element :
6675 i == Ydirt_eat ? element :
6676 i == Yemerald_stone ? EL_EMERALD :
6677 i == Ydiamond_stone ? EL_ROCK :
6678 i == Xsand_stonein_1 ? element :
6679 i == Xsand_stonein_2 ? element :
6680 i == Xsand_stonein_3 ? element :
6681 i == Xsand_stonein_4 ? element :
6682 is_backside ? EL_EMPTY :
6683 action_removing ? EL_EMPTY :
6686 int effective_action = (j < 7 ? action :
6687 i == Xdrip_stretch ? action :
6688 i == Xdrip_stretchB ? action :
6689 i == Ydrip_s1 ? action :
6690 i == Ydrip_s1B ? action :
6691 i == Xball_1B ? action :
6692 i == Xball_2 ? action :
6693 i == Xball_2B ? action :
6694 i == Yball_eat ? action :
6695 i == Ykey_1_eat ? action :
6696 i == Ykey_2_eat ? action :
6697 i == Ykey_3_eat ? action :
6698 i == Ykey_4_eat ? action :
6699 i == Ykey_5_eat ? action :
6700 i == Ykey_6_eat ? action :
6701 i == Ykey_7_eat ? action :
6702 i == Ykey_8_eat ? action :
6703 i == Ylenses_eat ? action :
6704 i == Ymagnify_eat ? action :
6705 i == Ygrass_eat ? action :
6706 i == Ydirt_eat ? action :
6707 i == Xsand_stonein_1 ? action :
6708 i == Xsand_stonein_2 ? action :
6709 i == Xsand_stonein_3 ? action :
6710 i == Xsand_stonein_4 ? action :
6711 i == Xsand_stoneout_1 ? action :
6712 i == Xsand_stoneout_2 ? action :
6713 i == Xboom_android ? ACTION_EXPLODING :
6714 action_exploding ? ACTION_EXPLODING :
6715 action_active ? action :
6716 action_other ? action :
6718 int graphic = (el_act_dir2img(effective_element, effective_action,
6720 int crumbled = (el_act_dir2crm(effective_element, effective_action,
6722 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
6723 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
6724 boolean has_action_graphics = (graphic != base_graphic);
6725 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
6726 struct GraphicInfo *g = &graphic_info[graphic];
6728 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
6730 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
6733 /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
6734 boolean special_animation = (action != ACTION_DEFAULT &&
6735 g->anim_frames == 3 &&
6736 g->anim_delay == 2 &&
6737 g->anim_mode & ANIM_LINEAR);
6738 xxx_sync_frame = (i == Xdrip_stretch ? 7 :
6739 i == Xdrip_stretchB ? 7 :
6740 i == Ydrip_s2 ? j + 8 :
6741 i == Ydrip_s2B ? j + 8 :
6750 i == Xfake_acid_1 ? 0 :
6751 i == Xfake_acid_2 ? 10 :
6752 i == Xfake_acid_3 ? 20 :
6753 i == Xfake_acid_4 ? 30 :
6754 i == Xfake_acid_5 ? 40 :
6755 i == Xfake_acid_6 ? 50 :
6756 i == Xfake_acid_7 ? 60 :
6757 i == Xfake_acid_8 ? 70 :
6759 i == Xball_2B ? j + 8 :
6760 i == Yball_eat ? j + 1 :
6761 i == Ykey_1_eat ? j + 1 :
6762 i == Ykey_2_eat ? j + 1 :
6763 i == Ykey_3_eat ? j + 1 :
6764 i == Ykey_4_eat ? j + 1 :
6765 i == Ykey_5_eat ? j + 1 :
6766 i == Ykey_6_eat ? j + 1 :
6767 i == Ykey_7_eat ? j + 1 :
6768 i == Ykey_8_eat ? j + 1 :
6769 i == Ylenses_eat ? j + 1 :
6770 i == Ymagnify_eat ? j + 1 :
6771 i == Ygrass_eat ? j + 1 :
6772 i == Ydirt_eat ? j + 1 :
6773 i == Xamoeba_1 ? 0 :
6774 i == Xamoeba_2 ? 1 :
6775 i == Xamoeba_3 ? 2 :
6776 i == Xamoeba_4 ? 3 :
6777 i == Xamoeba_5 ? 0 :
6778 i == Xamoeba_6 ? 1 :
6779 i == Xamoeba_7 ? 2 :
6780 i == Xamoeba_8 ? 3 :
6781 i == Xexit_2 ? j + 8 :
6782 i == Xexit_3 ? j + 16 :
6783 i == Xdynamite_1 ? 0 :
6784 i == Xdynamite_2 ? 8 :
6785 i == Xdynamite_3 ? 16 :
6786 i == Xdynamite_4 ? 24 :
6787 i == Xsand_stonein_1 ? j + 1 :
6788 i == Xsand_stonein_2 ? j + 9 :
6789 i == Xsand_stonein_3 ? j + 17 :
6790 i == Xsand_stonein_4 ? j + 25 :
6791 i == Xsand_stoneout_1 && j == 0 ? 0 :
6792 i == Xsand_stoneout_1 && j == 1 ? 0 :
6793 i == Xsand_stoneout_1 && j == 2 ? 1 :
6794 i == Xsand_stoneout_1 && j == 3 ? 2 :
6795 i == Xsand_stoneout_1 && j == 4 ? 2 :
6796 i == Xsand_stoneout_1 && j == 5 ? 3 :
6797 i == Xsand_stoneout_1 && j == 6 ? 4 :
6798 i == Xsand_stoneout_1 && j == 7 ? 4 :
6799 i == Xsand_stoneout_2 && j == 0 ? 5 :
6800 i == Xsand_stoneout_2 && j == 1 ? 6 :
6801 i == Xsand_stoneout_2 && j == 2 ? 7 :
6802 i == Xsand_stoneout_2 && j == 3 ? 8 :
6803 i == Xsand_stoneout_2 && j == 4 ? 9 :
6804 i == Xsand_stoneout_2 && j == 5 ? 11 :
6805 i == Xsand_stoneout_2 && j == 6 ? 13 :
6806 i == Xsand_stoneout_2 && j == 7 ? 15 :
6807 i == Xboom_bug && j == 1 ? 2 :
6808 i == Xboom_bug && j == 2 ? 2 :
6809 i == Xboom_bug && j == 3 ? 4 :
6810 i == Xboom_bug && j == 4 ? 4 :
6811 i == Xboom_bug && j == 5 ? 2 :
6812 i == Xboom_bug && j == 6 ? 2 :
6813 i == Xboom_bug && j == 7 ? 0 :
6814 i == Xboom_bomb && j == 1 ? 2 :
6815 i == Xboom_bomb && j == 2 ? 2 :
6816 i == Xboom_bomb && j == 3 ? 4 :
6817 i == Xboom_bomb && j == 4 ? 4 :
6818 i == Xboom_bomb && j == 5 ? 2 :
6819 i == Xboom_bomb && j == 6 ? 2 :
6820 i == Xboom_bomb && j == 7 ? 0 :
6821 i == Xboom_android && j == 7 ? 6 :
6822 i == Xboom_1 && j == 1 ? 2 :
6823 i == Xboom_1 && j == 2 ? 2 :
6824 i == Xboom_1 && j == 3 ? 4 :
6825 i == Xboom_1 && j == 4 ? 4 :
6826 i == Xboom_1 && j == 5 ? 6 :
6827 i == Xboom_1 && j == 6 ? 6 :
6828 i == Xboom_1 && j == 7 ? 8 :
6829 i == Xboom_2 && j == 0 ? 8 :
6830 i == Xboom_2 && j == 1 ? 8 :
6831 i == Xboom_2 && j == 2 ? 10 :
6832 i == Xboom_2 && j == 3 ? 10 :
6833 i == Xboom_2 && j == 4 ? 10 :
6834 i == Xboom_2 && j == 5 ? 12 :
6835 i == Xboom_2 && j == 6 ? 12 :
6836 i == Xboom_2 && j == 7 ? 12 :
6837 special_animation && j == 4 ? 3 :
6838 effective_action != action ? 0 :
6841 xxx_effective_action = effective_action;
6842 xxx_has_action_graphics = has_action_graphics;
6847 int frame = getAnimationFrame(g->anim_frames,
6850 g->anim_start_frame,
6864 int old_src_x = g_em->src_x;
6865 int old_src_y = g_em->src_y;
6869 getGraphicSourceExt(graphic, frame, &g_em->bitmap, &g_em->src_x, &g_em->src_y,
6870 g->double_movement && is_backside);
6872 getGraphicSourceExt(graphic, frame, &g_em->bitmap,
6873 &g_em->src_x, &g_em->src_y, FALSE);
6884 if (graphic == IMG_BUG_MOVING_RIGHT)
6885 printf("::: %d, %d, %d: %d, %d [%d, %d -> %d, %d]\n", graphic, x, y,
6886 g->double_movement, is_backside,
6887 old_src_x, old_src_y, g_em->src_x, g_em->src_y);
6895 g_em->src_offset_x = 0;
6896 g_em->src_offset_y = 0;
6897 g_em->dst_offset_x = 0;
6898 g_em->dst_offset_y = 0;
6899 g_em->width = TILEX;
6900 g_em->height = TILEY;
6902 g_em->preserve_background = FALSE;
6905 /* (updating the "crumbled" graphic definitions is probably not really needed,
6906 as animations for crumbled graphics can't be longer than one EMC cycle) */
6908 set_crumbled_graphics_EM(g_em, has_crumbled_graphics, crumbled,
6913 g_em->crumbled_bitmap = NULL;
6914 g_em->crumbled_src_x = 0;
6915 g_em->crumbled_src_y = 0;
6917 g_em->has_crumbled_graphics = FALSE;
6919 if (has_crumbled_graphics && crumbled != IMG_EMPTY_SPACE)
6921 int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
6922 g_crumbled->anim_delay,
6923 g_crumbled->anim_mode,
6924 g_crumbled->anim_start_frame,
6927 getGraphicSource(crumbled, frame_crumbled, &g_em->crumbled_bitmap,
6928 &g_em->crumbled_src_x, &g_em->crumbled_src_y);
6930 g_em->has_crumbled_graphics = TRUE;
6936 int effective_action = xxx_effective_action;
6937 int has_action_graphics = xxx_has_action_graphics;
6939 if ((!g->double_movement && (effective_action == ACTION_FALLING ||
6940 effective_action == ACTION_MOVING ||
6941 effective_action == ACTION_PUSHING ||
6942 effective_action == ACTION_EATING)) ||
6943 (!has_action_graphics && (effective_action == ACTION_FILLING ||
6944 effective_action == ACTION_EMPTYING)))
6947 (effective_action == ACTION_FALLING ||
6948 effective_action == ACTION_FILLING ||
6949 effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
6950 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
6951 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? 1 : 0);
6952 int num_steps = (i == Ydrip_s1 ? 16 :
6953 i == Ydrip_s1B ? 16 :
6954 i == Ydrip_s2 ? 16 :
6955 i == Ydrip_s2B ? 16 :
6956 i == Xsand_stonein_1 ? 32 :
6957 i == Xsand_stonein_2 ? 32 :
6958 i == Xsand_stonein_3 ? 32 :
6959 i == Xsand_stonein_4 ? 32 :
6960 i == Xsand_stoneout_1 ? 16 :
6961 i == Xsand_stoneout_2 ? 16 : 8);
6962 int cx = ABS(dx) * (TILEX / num_steps);
6963 int cy = ABS(dy) * (TILEY / num_steps);
6964 int step_frame = (i == Ydrip_s2 ? j + 8 :
6965 i == Ydrip_s2B ? j + 8 :
6966 i == Xsand_stonein_2 ? j + 8 :
6967 i == Xsand_stonein_3 ? j + 16 :
6968 i == Xsand_stonein_4 ? j + 24 :
6969 i == Xsand_stoneout_2 ? j + 8 : j) + 1;
6970 int step = (is_backside ? step_frame : num_steps - step_frame);
6972 if (is_backside) /* tile where movement starts */
6974 if (dx < 0 || dy < 0)
6976 g_em->src_offset_x = cx * step;
6977 g_em->src_offset_y = cy * step;
6981 g_em->dst_offset_x = cx * step;
6982 g_em->dst_offset_y = cy * step;
6985 else /* tile where movement ends */
6987 if (dx < 0 || dy < 0)
6989 g_em->dst_offset_x = cx * step;
6990 g_em->dst_offset_y = cy * step;
6994 g_em->src_offset_x = cx * step;
6995 g_em->src_offset_y = cy * step;
6999 g_em->width = TILEX - cx * step;
7000 g_em->height = TILEY - cy * step;
7003 /* create unique graphic identifier to decide if tile must be redrawn */
7004 /* bit 31 - 16 (16 bit): EM style graphic
7005 bit 15 - 12 ( 4 bit): EM style frame
7006 bit 11 - 6 ( 6 bit): graphic width
7007 bit 5 - 0 ( 6 bit): graphic height */
7008 g_em->unique_identifier =
7009 (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
7015 void getGraphicSourcePlayerExt_EM(struct GraphicInfo_EM *g_em,
7016 int player_nr, int anim, int frame_em)
7018 int element = player_mapping[player_nr][anim].element_rnd;
7019 int action = player_mapping[player_nr][anim].action;
7020 int direction = player_mapping[player_nr][anim].direction;
7021 int graphic = (direction == MV_NONE ?
7022 el_act2img(element, action) :
7023 el_act_dir2img(element, action, direction));
7024 struct GraphicInfo *g = &graphic_info[graphic];
7027 InitPlayerGfxAnimation(&stored_player[player_nr], action, direction);
7029 stored_player[player_nr].StepFrame = frame_em;
7031 sync_frame = stored_player[player_nr].Frame;
7033 int frame = getAnimationFrame(g->anim_frames,
7036 g->anim_start_frame,
7039 getGraphicSourceExt(graphic, frame, &g_em->bitmap,
7040 &g_em->src_x, &g_em->src_y, FALSE);
7043 printf("::: %d: %d, %d [%d]\n",
7045 stored_player[player_nr].Frame,
7046 stored_player[player_nr].StepFrame,
7051 void InitGraphicInfo_EM(void)
7054 struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
7055 struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
7060 int num_em_gfx_errors = 0;
7062 if (graphic_info_em_object[0][0].bitmap == NULL)
7064 /* EM graphics not yet initialized in em_open_all() */
7069 printf("::: [4 errors can be ignored (1 x 'bomb', 3 x 'em_dynamite']\n");
7072 /* always start with reliable default values */
7073 for (i = 0; i < TILE_MAX; i++)
7075 object_mapping[i].element_rnd = EL_UNKNOWN;
7076 object_mapping[i].is_backside = FALSE;
7077 object_mapping[i].action = ACTION_DEFAULT;
7078 object_mapping[i].direction = MV_NONE;
7081 /* always start with reliable default values */
7082 for (p = 0; p < MAX_PLAYERS; p++)
7084 for (i = 0; i < SPR_MAX; i++)
7086 player_mapping[p][i].element_rnd = EL_UNKNOWN;
7087 player_mapping[p][i].action = ACTION_DEFAULT;
7088 player_mapping[p][i].direction = MV_NONE;
7092 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
7094 int e = em_object_mapping_list[i].element_em;
7096 object_mapping[e].element_rnd = em_object_mapping_list[i].element_rnd;
7097 object_mapping[e].is_backside = em_object_mapping_list[i].is_backside;
7099 if (em_object_mapping_list[i].action != -1)
7100 object_mapping[e].action = em_object_mapping_list[i].action;
7102 if (em_object_mapping_list[i].direction != -1)
7103 object_mapping[e].direction =
7104 MV_DIR_FROM_BIT(em_object_mapping_list[i].direction);
7107 for (i = 0; em_player_mapping_list[i].action_em != -1; i++)
7109 int a = em_player_mapping_list[i].action_em;
7110 int p = em_player_mapping_list[i].player_nr;
7112 player_mapping[p][a].element_rnd = em_player_mapping_list[i].element_rnd;
7114 if (em_player_mapping_list[i].action != -1)
7115 player_mapping[p][a].action = em_player_mapping_list[i].action;
7117 if (em_player_mapping_list[i].direction != -1)
7118 player_mapping[p][a].direction =
7119 MV_DIR_FROM_BIT(em_player_mapping_list[i].direction);
7122 for (i = 0; i < TILE_MAX; i++)
7124 int element = object_mapping[i].element_rnd;
7125 int action = object_mapping[i].action;
7126 int direction = object_mapping[i].direction;
7127 boolean is_backside = object_mapping[i].is_backside;
7129 boolean action_removing = (action == ACTION_DIGGING ||
7130 action == ACTION_SNAPPING ||
7131 action == ACTION_COLLECTING);
7133 boolean action_exploding = ((action == ACTION_EXPLODING ||
7134 action == ACTION_SMASHED_BY_ROCK ||
7135 action == ACTION_SMASHED_BY_SPRING) &&
7136 element != EL_DIAMOND);
7137 boolean action_active = (action == ACTION_ACTIVE);
7138 boolean action_other = (action == ACTION_OTHER);
7140 for (j = 0; j < 8; j++)
7143 int effective_element = get_effective_element_EM(i, j);
7145 int effective_element = (j > 5 && i == Yacid_splash_eB ? EL_EMPTY :
7146 j > 5 && i == Yacid_splash_wB ? EL_EMPTY :
7148 i == Xdrip_stretch ? element :
7149 i == Xdrip_stretchB ? element :
7150 i == Ydrip_s1 ? element :
7151 i == Ydrip_s1B ? element :
7152 i == Xball_1B ? element :
7153 i == Xball_2 ? element :
7154 i == Xball_2B ? element :
7155 i == Yball_eat ? element :
7156 i == Ykey_1_eat ? element :
7157 i == Ykey_2_eat ? element :
7158 i == Ykey_3_eat ? element :
7159 i == Ykey_4_eat ? element :
7160 i == Ykey_5_eat ? element :
7161 i == Ykey_6_eat ? element :
7162 i == Ykey_7_eat ? element :
7163 i == Ykey_8_eat ? element :
7164 i == Ylenses_eat ? element :
7165 i == Ymagnify_eat ? element :
7166 i == Ygrass_eat ? element :
7167 i == Ydirt_eat ? element :
7168 i == Yemerald_stone ? EL_EMERALD :
7169 i == Ydiamond_stone ? EL_ROCK :
7170 i == Xsand_stonein_1 ? element :
7171 i == Xsand_stonein_2 ? element :
7172 i == Xsand_stonein_3 ? element :
7173 i == Xsand_stonein_4 ? element :
7174 is_backside ? EL_EMPTY :
7175 action_removing ? EL_EMPTY :
7178 int effective_action = (j < 7 ? action :
7179 i == Xdrip_stretch ? action :
7180 i == Xdrip_stretchB ? action :
7181 i == Ydrip_s1 ? action :
7182 i == Ydrip_s1B ? action :
7183 i == Xball_1B ? action :
7184 i == Xball_2 ? action :
7185 i == Xball_2B ? action :
7186 i == Yball_eat ? action :
7187 i == Ykey_1_eat ? action :
7188 i == Ykey_2_eat ? action :
7189 i == Ykey_3_eat ? action :
7190 i == Ykey_4_eat ? action :
7191 i == Ykey_5_eat ? action :
7192 i == Ykey_6_eat ? action :
7193 i == Ykey_7_eat ? action :
7194 i == Ykey_8_eat ? action :
7195 i == Ylenses_eat ? action :
7196 i == Ymagnify_eat ? action :
7197 i == Ygrass_eat ? action :
7198 i == Ydirt_eat ? action :
7199 i == Xsand_stonein_1 ? action :
7200 i == Xsand_stonein_2 ? action :
7201 i == Xsand_stonein_3 ? action :
7202 i == Xsand_stonein_4 ? action :
7203 i == Xsand_stoneout_1 ? action :
7204 i == Xsand_stoneout_2 ? action :
7205 i == Xboom_android ? ACTION_EXPLODING :
7206 action_exploding ? ACTION_EXPLODING :
7207 action_active ? action :
7208 action_other ? action :
7210 int graphic = (el_act_dir2img(effective_element, effective_action,
7212 int crumbled = (el_act_dir2crm(effective_element, effective_action,
7214 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
7215 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
7216 boolean has_action_graphics = (graphic != base_graphic);
7217 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
7218 struct GraphicInfo *g = &graphic_info[graphic];
7220 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
7222 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
7225 /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
7226 boolean special_animation = (action != ACTION_DEFAULT &&
7227 g->anim_frames == 3 &&
7228 g->anim_delay == 2 &&
7229 g->anim_mode & ANIM_LINEAR);
7230 int sync_frame = (i == Xdrip_stretch ? 7 :
7231 i == Xdrip_stretchB ? 7 :
7232 i == Ydrip_s2 ? j + 8 :
7233 i == Ydrip_s2B ? j + 8 :
7242 i == Xfake_acid_1 ? 0 :
7243 i == Xfake_acid_2 ? 10 :
7244 i == Xfake_acid_3 ? 20 :
7245 i == Xfake_acid_4 ? 30 :
7246 i == Xfake_acid_5 ? 40 :
7247 i == Xfake_acid_6 ? 50 :
7248 i == Xfake_acid_7 ? 60 :
7249 i == Xfake_acid_8 ? 70 :
7251 i == Xball_2B ? j + 8 :
7252 i == Yball_eat ? j + 1 :
7253 i == Ykey_1_eat ? j + 1 :
7254 i == Ykey_2_eat ? j + 1 :
7255 i == Ykey_3_eat ? j + 1 :
7256 i == Ykey_4_eat ? j + 1 :
7257 i == Ykey_5_eat ? j + 1 :
7258 i == Ykey_6_eat ? j + 1 :
7259 i == Ykey_7_eat ? j + 1 :
7260 i == Ykey_8_eat ? j + 1 :
7261 i == Ylenses_eat ? j + 1 :
7262 i == Ymagnify_eat ? j + 1 :
7263 i == Ygrass_eat ? j + 1 :
7264 i == Ydirt_eat ? j + 1 :
7265 i == Xamoeba_1 ? 0 :
7266 i == Xamoeba_2 ? 1 :
7267 i == Xamoeba_3 ? 2 :
7268 i == Xamoeba_4 ? 3 :
7269 i == Xamoeba_5 ? 0 :
7270 i == Xamoeba_6 ? 1 :
7271 i == Xamoeba_7 ? 2 :
7272 i == Xamoeba_8 ? 3 :
7273 i == Xexit_2 ? j + 8 :
7274 i == Xexit_3 ? j + 16 :
7275 i == Xdynamite_1 ? 0 :
7276 i == Xdynamite_2 ? 8 :
7277 i == Xdynamite_3 ? 16 :
7278 i == Xdynamite_4 ? 24 :
7279 i == Xsand_stonein_1 ? j + 1 :
7280 i == Xsand_stonein_2 ? j + 9 :
7281 i == Xsand_stonein_3 ? j + 17 :
7282 i == Xsand_stonein_4 ? j + 25 :
7283 i == Xsand_stoneout_1 && j == 0 ? 0 :
7284 i == Xsand_stoneout_1 && j == 1 ? 0 :
7285 i == Xsand_stoneout_1 && j == 2 ? 1 :
7286 i == Xsand_stoneout_1 && j == 3 ? 2 :
7287 i == Xsand_stoneout_1 && j == 4 ? 2 :
7288 i == Xsand_stoneout_1 && j == 5 ? 3 :
7289 i == Xsand_stoneout_1 && j == 6 ? 4 :
7290 i == Xsand_stoneout_1 && j == 7 ? 4 :
7291 i == Xsand_stoneout_2 && j == 0 ? 5 :
7292 i == Xsand_stoneout_2 && j == 1 ? 6 :
7293 i == Xsand_stoneout_2 && j == 2 ? 7 :
7294 i == Xsand_stoneout_2 && j == 3 ? 8 :
7295 i == Xsand_stoneout_2 && j == 4 ? 9 :
7296 i == Xsand_stoneout_2 && j == 5 ? 11 :
7297 i == Xsand_stoneout_2 && j == 6 ? 13 :
7298 i == Xsand_stoneout_2 && j == 7 ? 15 :
7299 i == Xboom_bug && j == 1 ? 2 :
7300 i == Xboom_bug && j == 2 ? 2 :
7301 i == Xboom_bug && j == 3 ? 4 :
7302 i == Xboom_bug && j == 4 ? 4 :
7303 i == Xboom_bug && j == 5 ? 2 :
7304 i == Xboom_bug && j == 6 ? 2 :
7305 i == Xboom_bug && j == 7 ? 0 :
7306 i == Xboom_bomb && j == 1 ? 2 :
7307 i == Xboom_bomb && j == 2 ? 2 :
7308 i == Xboom_bomb && j == 3 ? 4 :
7309 i == Xboom_bomb && j == 4 ? 4 :
7310 i == Xboom_bomb && j == 5 ? 2 :
7311 i == Xboom_bomb && j == 6 ? 2 :
7312 i == Xboom_bomb && j == 7 ? 0 :
7313 i == Xboom_android && j == 7 ? 6 :
7314 i == Xboom_1 && j == 1 ? 2 :
7315 i == Xboom_1 && j == 2 ? 2 :
7316 i == Xboom_1 && j == 3 ? 4 :
7317 i == Xboom_1 && j == 4 ? 4 :
7318 i == Xboom_1 && j == 5 ? 6 :
7319 i == Xboom_1 && j == 6 ? 6 :
7320 i == Xboom_1 && j == 7 ? 8 :
7321 i == Xboom_2 && j == 0 ? 8 :
7322 i == Xboom_2 && j == 1 ? 8 :
7323 i == Xboom_2 && j == 2 ? 10 :
7324 i == Xboom_2 && j == 3 ? 10 :
7325 i == Xboom_2 && j == 4 ? 10 :
7326 i == Xboom_2 && j == 5 ? 12 :
7327 i == Xboom_2 && j == 6 ? 12 :
7328 i == Xboom_2 && j == 7 ? 12 :
7329 special_animation && j == 4 ? 3 :
7330 effective_action != action ? 0 :
7334 Bitmap *debug_bitmap = g_em->bitmap;
7335 int debug_src_x = g_em->src_x;
7336 int debug_src_y = g_em->src_y;
7339 int frame = getAnimationFrame(g->anim_frames,
7342 g->anim_start_frame,
7345 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y,
7346 g->double_movement && is_backside);
7348 g_em->bitmap = src_bitmap;
7349 g_em->src_x = src_x;
7350 g_em->src_y = src_y;
7351 g_em->src_offset_x = 0;
7352 g_em->src_offset_y = 0;
7353 g_em->dst_offset_x = 0;
7354 g_em->dst_offset_y = 0;
7355 g_em->width = TILEX;
7356 g_em->height = TILEY;
7358 g_em->preserve_background = FALSE;
7361 set_crumbled_graphics_EM(g_em, has_crumbled_graphics, crumbled,
7366 g_em->crumbled_bitmap = NULL;
7367 g_em->crumbled_src_x = 0;
7368 g_em->crumbled_src_y = 0;
7369 g_em->crumbled_border_size = 0;
7371 g_em->has_crumbled_graphics = FALSE;
7374 if (has_crumbled_graphics && crumbled == IMG_EMPTY_SPACE)
7375 printf("::: empty crumbled: %d [%s], %d, %d\n",
7376 effective_element, element_info[effective_element].token_name,
7377 effective_action, direction);
7380 /* if element can be crumbled, but certain action graphics are just empty
7381 space (like instantly snapping sand to empty space in 1 frame), do not
7382 treat these empty space graphics as crumbled graphics in EMC engine */
7383 if (has_crumbled_graphics && crumbled != IMG_EMPTY_SPACE)
7385 int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
7386 g_crumbled->anim_delay,
7387 g_crumbled->anim_mode,
7388 g_crumbled->anim_start_frame,
7391 getGraphicSource(crumbled, frame_crumbled, &src_bitmap, &src_x, &src_y);
7393 g_em->has_crumbled_graphics = TRUE;
7394 g_em->crumbled_bitmap = src_bitmap;
7395 g_em->crumbled_src_x = src_x;
7396 g_em->crumbled_src_y = src_y;
7397 g_em->crumbled_border_size = graphic_info[crumbled].border_size;
7401 if (g_em == &graphic_info_em_object[207][0])
7402 printf("... %d, %d [%d, %d, %d, %d] [%d, %d, %d, %d, %d, %d => %d]\n",
7403 graphic_info_em_object[207][0].crumbled_src_x,
7404 graphic_info_em_object[207][0].crumbled_src_y,
7406 crumbled, frame, src_x, src_y,
7411 g->anim_start_frame,
7413 gfx.anim_random_frame,
7418 printf("::: EMC tile %d is crumbled\n", i);
7424 if (element == EL_ROCK &&
7425 effective_action == ACTION_FILLING)
7426 printf("::: has_action_graphics == %d\n", has_action_graphics);
7429 if ((!g->double_movement && (effective_action == ACTION_FALLING ||
7430 effective_action == ACTION_MOVING ||
7431 effective_action == ACTION_PUSHING ||
7432 effective_action == ACTION_EATING)) ||
7433 (!has_action_graphics && (effective_action == ACTION_FILLING ||
7434 effective_action == ACTION_EMPTYING)))
7437 (effective_action == ACTION_FALLING ||
7438 effective_action == ACTION_FILLING ||
7439 effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
7440 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
7441 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? 1 : 0);
7442 int num_steps = (i == Ydrip_s1 ? 16 :
7443 i == Ydrip_s1B ? 16 :
7444 i == Ydrip_s2 ? 16 :
7445 i == Ydrip_s2B ? 16 :
7446 i == Xsand_stonein_1 ? 32 :
7447 i == Xsand_stonein_2 ? 32 :
7448 i == Xsand_stonein_3 ? 32 :
7449 i == Xsand_stonein_4 ? 32 :
7450 i == Xsand_stoneout_1 ? 16 :
7451 i == Xsand_stoneout_2 ? 16 : 8);
7452 int cx = ABS(dx) * (TILEX / num_steps);
7453 int cy = ABS(dy) * (TILEY / num_steps);
7454 int step_frame = (i == Ydrip_s2 ? j + 8 :
7455 i == Ydrip_s2B ? j + 8 :
7456 i == Xsand_stonein_2 ? j + 8 :
7457 i == Xsand_stonein_3 ? j + 16 :
7458 i == Xsand_stonein_4 ? j + 24 :
7459 i == Xsand_stoneout_2 ? j + 8 : j) + 1;
7460 int step = (is_backside ? step_frame : num_steps - step_frame);
7462 if (is_backside) /* tile where movement starts */
7464 if (dx < 0 || dy < 0)
7466 g_em->src_offset_x = cx * step;
7467 g_em->src_offset_y = cy * step;
7471 g_em->dst_offset_x = cx * step;
7472 g_em->dst_offset_y = cy * step;
7475 else /* tile where movement ends */
7477 if (dx < 0 || dy < 0)
7479 g_em->dst_offset_x = cx * step;
7480 g_em->dst_offset_y = cy * step;
7484 g_em->src_offset_x = cx * step;
7485 g_em->src_offset_y = cy * step;
7489 g_em->width = TILEX - cx * step;
7490 g_em->height = TILEY - cy * step;
7493 /* create unique graphic identifier to decide if tile must be redrawn */
7494 /* bit 31 - 16 (16 bit): EM style graphic
7495 bit 15 - 12 ( 4 bit): EM style frame
7496 bit 11 - 6 ( 6 bit): graphic width
7497 bit 5 - 0 ( 6 bit): graphic height */
7498 g_em->unique_identifier =
7499 (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
7503 /* skip check for EMC elements not contained in original EMC artwork */
7504 if (element == EL_EMC_FAKE_ACID)
7507 if (g_em->bitmap != debug_bitmap ||
7508 g_em->src_x != debug_src_x ||
7509 g_em->src_y != debug_src_y ||
7510 g_em->src_offset_x != 0 ||
7511 g_em->src_offset_y != 0 ||
7512 g_em->dst_offset_x != 0 ||
7513 g_em->dst_offset_y != 0 ||
7514 g_em->width != TILEX ||
7515 g_em->height != TILEY)
7517 static int last_i = -1;
7525 printf("::: EMC GFX ERROR for element %d -> %d ('%s', '%s', %d)",
7526 i, element, element_info[element].token_name,
7527 element_action_info[effective_action].suffix, direction);
7529 if (element != effective_element)
7530 printf(" [%d ('%s')]",
7532 element_info[effective_element].token_name);
7536 if (g_em->bitmap != debug_bitmap)
7537 printf(" %d (%d): different bitmap! (0x%08x != 0x%08x)\n",
7538 j, is_backside, (int)(g_em->bitmap), (int)(debug_bitmap));
7540 if (g_em->src_x != debug_src_x ||
7541 g_em->src_y != debug_src_y)
7542 printf(" frame %d (%c): %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
7543 j, (is_backside ? 'B' : 'F'),
7544 g_em->src_x, g_em->src_y,
7545 g_em->src_x / 32, g_em->src_y / 32,
7546 debug_src_x, debug_src_y,
7547 debug_src_x / 32, debug_src_y / 32);
7549 if (g_em->src_offset_x != 0 ||
7550 g_em->src_offset_y != 0 ||
7551 g_em->dst_offset_x != 0 ||
7552 g_em->dst_offset_y != 0)
7553 printf(" %d (%d): offsets %d,%d and %d,%d should be all 0\n",
7555 g_em->src_offset_x, g_em->src_offset_y,
7556 g_em->dst_offset_x, g_em->dst_offset_y);
7558 if (g_em->width != TILEX ||
7559 g_em->height != TILEY)
7560 printf(" %d (%d): size %d,%d should be %d,%d\n",
7562 g_em->width, g_em->height, TILEX, TILEY);
7564 num_em_gfx_errors++;
7571 for (i = 0; i < TILE_MAX; i++)
7573 for (j = 0; j < 8; j++)
7575 int element = object_mapping[i].element_rnd;
7576 int action = object_mapping[i].action;
7577 int direction = object_mapping[i].direction;
7578 boolean is_backside = object_mapping[i].is_backside;
7579 int graphic_action = el_act_dir2img(element, action, direction);
7580 int graphic_default = el_act_dir2img(element, ACTION_DEFAULT, direction);
7582 if ((action == ACTION_SMASHED_BY_ROCK ||
7583 action == ACTION_SMASHED_BY_SPRING ||
7584 action == ACTION_EATING) &&
7585 graphic_action == graphic_default)
7587 int e = (action == ACTION_SMASHED_BY_ROCK ? Ystone_s :
7588 action == ACTION_SMASHED_BY_SPRING ? Yspring_s :
7589 direction == MV_LEFT ? (is_backside? Yspring_wB: Yspring_w) :
7590 direction == MV_RIGHT ? (is_backside? Yspring_eB: Yspring_e) :
7593 /* no separate animation for "smashed by rock" -- use rock instead */
7594 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
7595 struct GraphicInfo_EM *g_xx = &graphic_info_em_object[e][7 - j];
7597 g_em->bitmap = g_xx->bitmap;
7598 g_em->src_x = g_xx->src_x;
7599 g_em->src_y = g_xx->src_y;
7600 g_em->src_offset_x = g_xx->src_offset_x;
7601 g_em->src_offset_y = g_xx->src_offset_y;
7602 g_em->dst_offset_x = g_xx->dst_offset_x;
7603 g_em->dst_offset_y = g_xx->dst_offset_y;
7604 g_em->width = g_xx->width;
7605 g_em->height = g_xx->height;
7606 g_em->unique_identifier = g_xx->unique_identifier;
7609 g_em->preserve_background = TRUE;
7614 for (p = 0; p < MAX_PLAYERS; p++)
7616 for (i = 0; i < SPR_MAX; i++)
7618 int element = player_mapping[p][i].element_rnd;
7619 int action = player_mapping[p][i].action;
7620 int direction = player_mapping[p][i].direction;
7622 for (j = 0; j < 8; j++)
7624 int effective_element = element;
7625 int effective_action = action;
7626 int graphic = (direction == MV_NONE ?
7627 el_act2img(effective_element, effective_action) :
7628 el_act_dir2img(effective_element, effective_action,
7630 struct GraphicInfo *g = &graphic_info[graphic];
7631 struct GraphicInfo_EM *g_em = &graphic_info_em_player[p][i][7 - j];
7637 Bitmap *debug_bitmap = g_em->bitmap;
7638 int debug_src_x = g_em->src_x;
7639 int debug_src_y = g_em->src_y;
7642 int frame = getAnimationFrame(g->anim_frames,
7645 g->anim_start_frame,
7648 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
7650 g_em->bitmap = src_bitmap;
7651 g_em->src_x = src_x;
7652 g_em->src_y = src_y;
7653 g_em->src_offset_x = 0;
7654 g_em->src_offset_y = 0;
7655 g_em->dst_offset_x = 0;
7656 g_em->dst_offset_y = 0;
7657 g_em->width = TILEX;
7658 g_em->height = TILEY;
7662 /* skip check for EMC elements not contained in original EMC artwork */
7663 if (element == EL_PLAYER_3 ||
7664 element == EL_PLAYER_4)
7667 if (g_em->bitmap != debug_bitmap ||
7668 g_em->src_x != debug_src_x ||
7669 g_em->src_y != debug_src_y)
7671 static int last_i = -1;
7679 printf("::: EMC GFX ERROR for p/a %d/%d -> %d ('%s', '%s', %d)",
7680 p, i, element, element_info[element].token_name,
7681 element_action_info[effective_action].suffix, direction);
7683 if (element != effective_element)
7684 printf(" [%d ('%s')]",
7686 element_info[effective_element].token_name);
7690 if (g_em->bitmap != debug_bitmap)
7691 printf(" %d: different bitmap! (0x%08x != 0x%08x)\n",
7692 j, (int)(g_em->bitmap), (int)(debug_bitmap));
7694 if (g_em->src_x != debug_src_x ||
7695 g_em->src_y != debug_src_y)
7696 printf(" frame %d: %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
7698 g_em->src_x, g_em->src_y,
7699 g_em->src_x / 32, g_em->src_y / 32,
7700 debug_src_x, debug_src_y,
7701 debug_src_x / 32, debug_src_y / 32);
7703 num_em_gfx_errors++;
7713 printf("::: [%d errors found]\n", num_em_gfx_errors);
7719 void PlayMenuSoundExt(int sound)
7721 if (sound == SND_UNDEFINED)
7724 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
7725 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
7728 if (IS_LOOP_SOUND(sound))
7729 PlaySoundLoop(sound);
7734 void PlayMenuSound()
7736 PlayMenuSoundExt(menu.sound[game_status]);
7739 void PlayMenuSoundStereo(int sound, int stereo_position)
7741 if (sound == SND_UNDEFINED)
7744 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
7745 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
7748 if (IS_LOOP_SOUND(sound))
7749 PlaySoundExt(sound, SOUND_MAX_VOLUME, stereo_position, SND_CTRL_PLAY_LOOP);
7751 PlaySoundStereo(sound, stereo_position);
7754 void PlayMenuSoundIfLoopExt(int sound)
7756 if (sound == SND_UNDEFINED)
7759 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
7760 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
7763 if (IS_LOOP_SOUND(sound))
7764 PlaySoundLoop(sound);
7767 void PlayMenuSoundIfLoop()
7769 PlayMenuSoundIfLoopExt(menu.sound[game_status]);
7772 void PlayMenuMusicExt(int music)
7774 if (music == MUS_UNDEFINED)
7777 if (!setup.sound_music)
7783 void PlayMenuMusic()
7785 PlayMenuMusicExt(menu.music[game_status]);
7788 void PlaySoundActivating()
7791 PlaySound(SND_MENU_ITEM_ACTIVATING);
7795 void PlaySoundSelecting()
7798 PlaySound(SND_MENU_ITEM_SELECTING);
7802 void ToggleFullscreenIfNeeded()
7804 boolean change_fullscreen = (setup.fullscreen !=
7805 video.fullscreen_enabled);
7806 boolean change_fullscreen_mode = (video.fullscreen_enabled &&
7807 !strEqual(setup.fullscreen_mode,
7808 video.fullscreen_mode_current));
7810 if (!video.fullscreen_available)
7814 if (change_fullscreen || change_fullscreen_mode)
7816 if (setup.fullscreen != video.fullscreen_enabled ||
7817 setup.fullscreen_mode != video.fullscreen_mode_current)
7820 Bitmap *tmp_backbuffer = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
7822 /* save backbuffer content which gets lost when toggling fullscreen mode */
7823 BlitBitmap(backbuffer, tmp_backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
7826 if (change_fullscreen_mode)
7828 if (setup.fullscreen && video.fullscreen_enabled)
7831 /* keep fullscreen, but change fullscreen mode (screen resolution) */
7833 /* (this is now set in sdl.c) */
7835 video.fullscreen_mode_current = setup.fullscreen_mode;
7837 video.fullscreen_enabled = FALSE; /* force new fullscreen mode */
7840 /* toggle fullscreen */
7841 ChangeVideoModeIfNeeded(setup.fullscreen);
7843 setup.fullscreen = video.fullscreen_enabled;
7845 /* restore backbuffer content from temporary backbuffer backup bitmap */
7846 BlitBitmap(tmp_backbuffer, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
7848 FreeBitmap(tmp_backbuffer);
7851 /* update visible window/screen */
7852 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
7854 redraw_mask = REDRAW_ALL;