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) */
2723 /* this allows transparent pushing animation over non-black background */
2724 if (IS_MOVING(jx, jy))
2727 DrawLevelElement(jx, jy, Back[jx][jy]);
2729 DrawLevelElement(jx, jy, EL_EMPTY);
2731 if (Back[next_jx][next_jy])
2732 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
2734 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
2737 if (Back[next_jx][next_jy])
2738 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
2742 printf("::: %d, %d, %d, %d [%d] [%d, %d, %d] [%d] [%d, %d] [%d, %d]\n",
2743 jx, px, player->GfxPos, player->StepFrame,
2748 GfxFrame[jx][jy], GfxFrame[next_jx][next_jy]);
2752 /* do not draw (EM style) pushing animation when pushing is finished */
2753 /* (two-tile animations usually do not contain start and end frame) */
2754 if (graphic_info[graphic].double_movement && !IS_MOVING(jx, jy))
2755 DrawLevelElement(next_jx, next_jy, Feld[next_jx][next_jy]);
2757 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
2759 /* masked drawing is needed for EMC style (double) movement graphics */
2760 /* !!! (ONLY WHEN DRAWING PUSHED ELEMENT OVER THE PLAYER) !!! */
2761 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
2766 #if DRAW_PLAYER_OVER_PUSHED_ELEMENT
2767 /* ----------------------------------------------------------------------- */
2768 /* draw player himself */
2769 /* ----------------------------------------------------------------------- */
2771 graphic = getPlayerGraphic(player, move_dir);
2773 /* in the case of changed player action or direction, prevent the current
2774 animation frame from being restarted for identical animations */
2775 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
2776 player->Frame = last_player_frame;
2778 frame = getGraphicAnimationFrame(graphic, player->Frame);
2782 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
2783 sxx = player->GfxPos;
2785 syy = player->GfxPos;
2788 if (!setup.soft_scrolling && ScreenMovPos)
2791 if (player_is_opaque)
2792 DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
2794 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
2796 if (SHIELD_ON(player))
2798 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
2799 IMG_SHIELD_NORMAL_ACTIVE);
2800 int frame = getGraphicAnimationFrame(graphic, -1);
2802 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
2806 /* ----------------------------------------------------------------------- */
2807 /* draw things in front of player (active dynamite or dynabombs) */
2808 /* ----------------------------------------------------------------------- */
2810 if (IS_ACTIVE_BOMB(element))
2812 graphic = el2img(element);
2813 frame = getGraphicAnimationFrame(graphic, GfxFrame[jx][jy]);
2815 if (game.emulation == EMU_SUPAPLEX)
2816 DrawGraphic(sx, sy, IMG_SP_DISK_RED, frame);
2818 DrawGraphicThruMask(sx, sy, graphic, frame);
2821 if (player_is_moving && last_element == EL_EXPLOSION)
2823 int element = (GfxElement[last_jx][last_jy] != EL_UNDEFINED ?
2824 GfxElement[last_jx][last_jy] : EL_EMPTY);
2825 int graphic = el_act2img(element, ACTION_EXPLODING);
2826 int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
2827 int phase = ExplodePhase[last_jx][last_jy] - 1;
2828 int frame = getGraphicAnimationFrame(graphic, phase - delay);
2831 DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy), graphic, frame);
2834 /* ----------------------------------------------------------------------- */
2835 /* draw elements the player is just walking/passing through/under */
2836 /* ----------------------------------------------------------------------- */
2838 if (player_is_moving)
2840 /* handle the field the player is leaving ... */
2841 if (IS_ACCESSIBLE_INSIDE(last_element))
2842 DrawLevelField(last_jx, last_jy);
2843 else if (IS_ACCESSIBLE_UNDER(last_element))
2844 DrawLevelFieldThruMask(last_jx, last_jy);
2847 /* do not redraw accessible elements if the player is just pushing them */
2848 if (!player_is_moving || !player->is_pushing)
2850 /* ... and the field the player is entering */
2851 if (IS_ACCESSIBLE_INSIDE(element))
2852 DrawLevelField(jx, jy);
2853 else if (IS_ACCESSIBLE_UNDER(element))
2854 DrawLevelFieldThruMask(jx, jy);
2857 MarkTileDirty(sx, sy);
2860 /* ------------------------------------------------------------------------- */
2862 void WaitForEventToContinue()
2864 boolean still_wait = TRUE;
2866 /* simulate releasing mouse button over last gadget, if still pressed */
2868 HandleGadgets(-1, -1, 0);
2870 button_status = MB_RELEASED;
2886 case EVENT_BUTTONPRESS:
2887 case EVENT_KEYPRESS:
2891 case EVENT_KEYRELEASE:
2892 ClearPlayerAction();
2896 HandleOtherEvents(&event);
2900 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
2907 /* don't eat all CPU time */
2912 #define MAX_REQUEST_LINES 13
2913 #define MAX_REQUEST_LINE_FONT1_LEN 7
2914 #define MAX_REQUEST_LINE_FONT2_LEN 10
2916 boolean Request(char *text, unsigned int req_state)
2918 int mx, my, ty, result = -1;
2919 unsigned int old_door_state;
2920 int last_game_status = game_status; /* save current game status */
2921 int max_request_line_len = MAX_REQUEST_LINE_FONT1_LEN;
2922 int font_nr = FONT_TEXT_2;
2923 int max_word_len = 0;
2926 for (text_ptr = text; *text_ptr; text_ptr++)
2928 max_word_len = (*text_ptr != ' ' ? max_word_len + 1 : 0);
2930 if (max_word_len > MAX_REQUEST_LINE_FONT1_LEN)
2932 max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
2934 font_nr = FONT_TEXT_1;
2936 font_nr = FONT_LEVEL_NUMBER;
2943 if (game_status == GAME_MODE_PLAYING)
2945 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
2946 BlitScreenToBitmap_EM(backbuffer);
2947 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
2948 BlitScreenToBitmap_SP(backbuffer);
2951 /* disable deactivated drawing when quick-loading level tape recording */
2952 if (tape.playing && tape.deactivate_display)
2953 TapeDeactivateDisplayOff(TRUE);
2955 SetMouseCursor(CURSOR_DEFAULT);
2957 #if defined(NETWORK_AVALIABLE)
2958 /* pause network game while waiting for request to answer */
2959 if (options.network &&
2960 game_status == GAME_MODE_PLAYING &&
2961 req_state & REQUEST_WAIT_FOR_INPUT)
2962 SendToServer_PausePlaying();
2965 old_door_state = GetDoorState();
2967 /* simulate releasing mouse button over last gadget, if still pressed */
2969 HandleGadgets(-1, -1, 0);
2973 if (old_door_state & DOOR_OPEN_1)
2975 CloseDoor(DOOR_CLOSE_1);
2977 /* save old door content */
2978 BlitBitmap(bitmap_db_door, bitmap_db_door,
2979 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
2980 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
2984 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
2987 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
2989 /* clear door drawing field */
2990 DrawBackground(DX, DY, DXSIZE, DYSIZE);
2992 /* force DOOR font inside door area */
2993 game_status = GAME_MODE_PSEUDO_DOOR;
2995 /* write text for request */
2996 for (ty = 0; ty < MAX_REQUEST_LINES; ty++)
2998 char text_line[max_request_line_len + 1];
3004 for (tl = 0, tx = 0; tx < max_request_line_len; tl++, tx++)
3007 if (!tc || tc == ' ')
3018 strncpy(text_line, text, tl);
3021 DrawText(DX + (DXSIZE - tl * getFontWidth(font_nr)) / 2,
3022 DY + 8 + ty * (getFontHeight(font_nr) + 2),
3023 text_line, font_nr);
3025 text += tl + (tc == ' ' ? 1 : 0);
3028 game_status = last_game_status; /* restore current game status */
3030 if (req_state & REQ_ASK)
3032 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
3033 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
3035 else if (req_state & REQ_CONFIRM)
3037 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
3039 else if (req_state & REQ_PLAYER)
3041 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
3042 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
3043 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
3044 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
3047 /* copy request gadgets to door backbuffer */
3048 BlitBitmap(drawto, bitmap_db_door,
3049 DX, DY, DXSIZE, DYSIZE,
3050 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
3052 OpenDoor(DOOR_OPEN_1);
3054 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
3056 if (game_status == GAME_MODE_PLAYING)
3058 SetPanelBackground();
3059 SetDrawBackgroundMask(REDRAW_DOOR_1);
3063 SetDrawBackgroundMask(REDRAW_FIELD);
3069 if (game_status != GAME_MODE_MAIN)
3072 button_status = MB_RELEASED;
3074 request_gadget_id = -1;
3076 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
3088 case EVENT_BUTTONPRESS:
3089 case EVENT_BUTTONRELEASE:
3090 case EVENT_MOTIONNOTIFY:
3092 if (event.type == EVENT_MOTIONNOTIFY)
3094 if (!PointerInWindow(window))
3095 continue; /* window and pointer are on different screens */
3100 motion_status = TRUE;
3101 mx = ((MotionEvent *) &event)->x;
3102 my = ((MotionEvent *) &event)->y;
3106 motion_status = FALSE;
3107 mx = ((ButtonEvent *) &event)->x;
3108 my = ((ButtonEvent *) &event)->y;
3109 if (event.type == EVENT_BUTTONPRESS)
3110 button_status = ((ButtonEvent *) &event)->button;
3112 button_status = MB_RELEASED;
3115 /* this sets 'request_gadget_id' */
3116 HandleGadgets(mx, my, button_status);
3118 switch (request_gadget_id)
3120 case TOOL_CTRL_ID_YES:
3123 case TOOL_CTRL_ID_NO:
3126 case TOOL_CTRL_ID_CONFIRM:
3127 result = TRUE | FALSE;
3130 case TOOL_CTRL_ID_PLAYER_1:
3133 case TOOL_CTRL_ID_PLAYER_2:
3136 case TOOL_CTRL_ID_PLAYER_3:
3139 case TOOL_CTRL_ID_PLAYER_4:
3150 case EVENT_KEYPRESS:
3151 switch (GetEventKey((KeyEvent *)&event, TRUE))
3154 if (req_state & REQ_CONFIRM)
3170 if (req_state & REQ_PLAYER)
3174 case EVENT_KEYRELEASE:
3175 ClearPlayerAction();
3179 HandleOtherEvents(&event);
3183 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
3185 int joy = AnyJoystick();
3187 if (joy & JOY_BUTTON_1)
3189 else if (joy & JOY_BUTTON_2)
3195 if (game_status == GAME_MODE_PLAYING && local_player->LevelSolved_GameEnd)
3197 HandleGameActions();
3203 if (!PendingEvent()) /* delay only if no pending events */
3214 if (!PendingEvent()) /* delay only if no pending events */
3217 /* don't eat all CPU time */
3224 if (game_status != GAME_MODE_MAIN)
3229 if (!(req_state & REQ_STAY_OPEN))
3231 CloseDoor(DOOR_CLOSE_1);
3233 if (((old_door_state & DOOR_OPEN_1) && !(req_state & REQ_STAY_CLOSED)) ||
3234 (req_state & REQ_REOPEN))
3235 OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
3240 if (game_status == GAME_MODE_PLAYING)
3242 SetPanelBackground();
3243 SetDrawBackgroundMask(REDRAW_DOOR_1);
3247 SetDrawBackgroundMask(REDRAW_FIELD);
3250 #if defined(NETWORK_AVALIABLE)
3251 /* continue network game after request */
3252 if (options.network &&
3253 game_status == GAME_MODE_PLAYING &&
3254 req_state & REQUEST_WAIT_FOR_INPUT)
3255 SendToServer_ContinuePlaying();
3258 /* restore deactivated drawing when quick-loading level tape recording */
3259 if (tape.playing && tape.deactivate_display)
3260 TapeDeactivateDisplayOn();
3265 unsigned int OpenDoor(unsigned int door_state)
3267 if (door_state & DOOR_COPY_BACK)
3269 if (door_state & DOOR_OPEN_1)
3270 BlitBitmap(bitmap_db_door, bitmap_db_door,
3271 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
3272 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
3274 if (door_state & DOOR_OPEN_2)
3275 BlitBitmap(bitmap_db_door, bitmap_db_door,
3276 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY2, VXSIZE, VYSIZE,
3277 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
3279 door_state &= ~DOOR_COPY_BACK;
3282 return MoveDoor(door_state);
3285 unsigned int CloseDoor(unsigned int door_state)
3287 unsigned int old_door_state = GetDoorState();
3289 if (!(door_state & DOOR_NO_COPY_BACK))
3291 if (old_door_state & DOOR_OPEN_1)
3292 BlitBitmap(backbuffer, bitmap_db_door,
3293 DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
3295 if (old_door_state & DOOR_OPEN_2)
3296 BlitBitmap(backbuffer, bitmap_db_door,
3297 VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
3299 door_state &= ~DOOR_NO_COPY_BACK;
3302 return MoveDoor(door_state);
3305 unsigned int GetDoorState()
3307 return MoveDoor(DOOR_GET_STATE);
3310 unsigned int SetDoorState(unsigned int door_state)
3312 return MoveDoor(door_state | DOOR_SET_STATE);
3315 unsigned int MoveDoor(unsigned int door_state)
3317 static int door1 = DOOR_OPEN_1;
3318 static int door2 = DOOR_CLOSE_2;
3319 unsigned long door_delay = 0;
3320 unsigned long door_delay_value;
3323 if (door_1.width < 0 || door_1.width > DXSIZE)
3324 door_1.width = DXSIZE;
3325 if (door_1.height < 0 || door_1.height > DYSIZE)
3326 door_1.height = DYSIZE;
3327 if (door_2.width < 0 || door_2.width > VXSIZE)
3328 door_2.width = VXSIZE;
3329 if (door_2.height < 0 || door_2.height > VYSIZE)
3330 door_2.height = VYSIZE;
3332 if (door_state == DOOR_GET_STATE)
3333 return (door1 | door2);
3335 if (door_state & DOOR_SET_STATE)
3337 if (door_state & DOOR_ACTION_1)
3338 door1 = door_state & DOOR_ACTION_1;
3339 if (door_state & DOOR_ACTION_2)
3340 door2 = door_state & DOOR_ACTION_2;
3342 return (door1 | door2);
3345 if (!(door_state & DOOR_FORCE_REDRAW))
3347 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
3348 door_state &= ~DOOR_OPEN_1;
3349 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
3350 door_state &= ~DOOR_CLOSE_1;
3351 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
3352 door_state &= ~DOOR_OPEN_2;
3353 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
3354 door_state &= ~DOOR_CLOSE_2;
3357 door_delay_value = (door_state & DOOR_ACTION_1 ? door_1.step_delay :
3360 if (setup.quick_doors)
3362 stepsize = 20; /* must be chosen to always draw last frame */
3363 door_delay_value = 0;
3366 if (global.autoplay_leveldir)
3368 door_state |= DOOR_NO_DELAY;
3369 door_state &= ~DOOR_CLOSE_ALL;
3373 if (game_status == GAME_MODE_EDITOR)
3374 door_state |= DOOR_NO_DELAY;
3377 if (door_state & DOOR_ACTION)
3379 boolean handle_door_1 = (door_state & DOOR_ACTION_1);
3380 boolean handle_door_2 = (door_state & DOOR_ACTION_2);
3381 boolean door_1_done = (!handle_door_1);
3382 boolean door_2_done = (!handle_door_2);
3383 boolean door_1_vertical = (door_1.anim_mode & ANIM_VERTICAL);
3384 boolean door_2_vertical = (door_2.anim_mode & ANIM_VERTICAL);
3385 int door_size_1 = (door_1_vertical ? door_1.height : door_1.width);
3386 int door_size_2 = (door_2_vertical ? door_2.height : door_2.width);
3387 int max_door_size_1 = (door_1_vertical ? DYSIZE : DXSIZE);
3388 int max_door_size_2 = (door_2_vertical ? VYSIZE : VXSIZE);
3389 int door_size = (handle_door_1 ? door_size_1 : door_size_2);
3390 int max_door_size = (handle_door_1 ? max_door_size_1 : max_door_size_2);
3391 int door_skip = max_door_size - door_size;
3392 int end = door_size;
3393 int start = ((door_state & DOOR_NO_DELAY) ? end : 0);
3396 if (!(door_state & DOOR_NO_DELAY) && !setup.quick_doors)
3398 /* opening door sound has priority over simultaneously closing door */
3399 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
3400 PlayMenuSoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
3401 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
3402 PlayMenuSoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
3405 for (k = start; k <= end && !(door_1_done && door_2_done); k += stepsize)
3408 Bitmap *bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
3409 GC gc = bitmap->stored_clip_gc;
3411 if (door_state & DOOR_ACTION_1)
3413 int a = MIN(x * door_1.step_offset, end);
3414 int p = (door_state & DOOR_OPEN_1 ? end - a : a);
3415 int i = p + door_skip;
3417 if (door_1.anim_mode & ANIM_STATIC_PANEL)
3419 BlitBitmap(bitmap_db_door, drawto,
3420 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1,
3421 DXSIZE, DYSIZE, DX, DY);
3425 BlitBitmap(bitmap_db_door, drawto,
3426 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + p / 2,
3427 DXSIZE, DYSIZE - p / 2, DX, DY);
3429 ClearRectangle(drawto, DX, DY + DYSIZE - p / 2, DXSIZE, p / 2);
3432 if (door_1.anim_mode & ANIM_HORIZONTAL && x <= DXSIZE)
3434 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
3435 int dst1_x = DX + DXSIZE - i, dst1_y = DY;
3436 int src2_x = DXSIZE - i, src2_y = DOOR_GFX_PAGEY1;
3437 int dst2_x = DX, dst2_y = DY;
3438 int width = i, height = DYSIZE;
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 (door_1.anim_mode & ANIM_VERTICAL && x <= DYSIZE)
3450 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
3451 int dst1_x = DX, dst1_y = DY + DYSIZE - i;
3452 int src2_x = 0, src2_y = DOOR_GFX_PAGEY1 + DYSIZE - i;
3453 int dst2_x = DX, dst2_y = DY;
3454 int width = DXSIZE, height = i;
3456 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
3457 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
3460 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
3461 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
3464 else if (x <= DXSIZE) /* ANIM_DEFAULT */
3466 int j = (door_1.anim_mode == ANIM_DEFAULT ? (DXSIZE - i) / 3 : 0);
3468 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
3469 BlitBitmapMasked(bitmap, drawto,
3470 DXSIZE, DOOR_GFX_PAGEY1, i, 77,
3471 DX + DXSIZE - i, DY + j);
3472 BlitBitmapMasked(bitmap, drawto,
3473 DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63,
3474 DX + DXSIZE - i, DY + 140 + j);
3475 SetClipOrigin(bitmap, gc, DX - DXSIZE + i,
3476 DY - (DOOR_GFX_PAGEY1 + j));
3477 BlitBitmapMasked(bitmap, drawto,
3478 DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j,
3480 BlitBitmapMasked(bitmap, drawto,
3481 DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63,
3484 BlitBitmapMasked(bitmap, drawto,
3485 DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
3487 BlitBitmapMasked(bitmap, drawto,
3488 DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
3490 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
3491 BlitBitmapMasked(bitmap, drawto,
3492 DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
3493 DX + DXSIZE - i, DY + 77 + j);
3494 BlitBitmapMasked(bitmap, drawto,
3495 DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
3496 DX + DXSIZE - i, DY + 203 + j);
3499 redraw_mask |= REDRAW_DOOR_1;
3500 door_1_done = (a == end);
3503 if (door_state & DOOR_ACTION_2)
3505 int a = MIN(x * door_2.step_offset, door_size);
3506 int p = (door_state & DOOR_OPEN_2 ? door_size - a : a);
3507 int i = p + door_skip;
3509 if (door_2.anim_mode & ANIM_STATIC_PANEL)
3511 BlitBitmap(bitmap_db_door, drawto,
3512 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2,
3513 VXSIZE, VYSIZE, VX, VY);
3515 else if (x <= VYSIZE)
3517 BlitBitmap(bitmap_db_door, drawto,
3518 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + p / 2,
3519 VXSIZE, VYSIZE - p / 2, VX, VY);
3521 ClearRectangle(drawto, VX, VY + VYSIZE - p / 2, VXSIZE, p / 2);
3524 if (door_2.anim_mode & ANIM_HORIZONTAL && x <= VXSIZE)
3526 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
3527 int dst1_x = VX + VXSIZE - i, dst1_y = VY;
3528 int src2_x = VXSIZE - i, src2_y = DOOR_GFX_PAGEY2;
3529 int dst2_x = VX, dst2_y = VY;
3530 int width = i, height = VYSIZE;
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 (door_2.anim_mode & ANIM_VERTICAL && x <= VYSIZE)
3542 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
3543 int dst1_x = VX, dst1_y = VY + VYSIZE - i;
3544 int src2_x = 0, src2_y = DOOR_GFX_PAGEY2 + VYSIZE - i;
3545 int dst2_x = VX, dst2_y = VY;
3546 int width = VXSIZE, height = i;
3548 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
3549 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
3552 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
3553 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
3556 else if (x <= VXSIZE) /* ANIM_DEFAULT */
3558 int j = (door_2.anim_mode == ANIM_DEFAULT ? (VXSIZE - i) / 3 : 0);
3560 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
3561 BlitBitmapMasked(bitmap, drawto,
3562 VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2,
3563 VX + VXSIZE - i, VY + j);
3564 SetClipOrigin(bitmap, gc,
3565 VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
3566 BlitBitmapMasked(bitmap, drawto,
3567 VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j,
3570 BlitBitmapMasked(bitmap, drawto,
3571 VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2,
3572 i, VYSIZE / 2, VX, VY + VYSIZE / 2 - j);
3573 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
3574 BlitBitmapMasked(bitmap, drawto,
3575 VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2,
3577 VX + VXSIZE - i, VY + VYSIZE / 2 + j);
3580 redraw_mask |= REDRAW_DOOR_2;
3581 door_2_done = (a == VXSIZE);
3584 if (!(door_state & DOOR_NO_DELAY))
3588 if (game_status == GAME_MODE_MAIN)
3591 WaitUntilDelayReached(&door_delay, door_delay_value);
3596 if (door_state & DOOR_ACTION_1)
3597 door1 = door_state & DOOR_ACTION_1;
3598 if (door_state & DOOR_ACTION_2)
3599 door2 = door_state & DOOR_ACTION_2;
3601 return (door1 | door2);
3604 void DrawSpecialEditorDoor()
3606 /* draw bigger toolbox window */
3607 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
3608 DOOR_GFX_PAGEX7, 0, EXSIZE + 8, 8,
3610 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
3611 EX - 6, VY - 4, EXSIZE + 12, EYSIZE - VYSIZE + 4,
3614 redraw_mask |= REDRAW_ALL;
3617 void UndrawSpecialEditorDoor()
3619 /* draw normal tape recorder window */
3620 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
3621 EX - 6, EY - 12, EXSIZE + 12, EYSIZE - VYSIZE + 12,
3624 redraw_mask |= REDRAW_ALL;
3628 /* ---------- new tool button stuff ---------------------------------------- */
3630 /* graphic position values for tool buttons */
3631 #define TOOL_BUTTON_YES_XPOS 2
3632 #define TOOL_BUTTON_YES_YPOS 250
3633 #define TOOL_BUTTON_YES_GFX_YPOS 0
3634 #define TOOL_BUTTON_YES_XSIZE 46
3635 #define TOOL_BUTTON_YES_YSIZE 28
3636 #define TOOL_BUTTON_NO_XPOS 52
3637 #define TOOL_BUTTON_NO_YPOS TOOL_BUTTON_YES_YPOS
3638 #define TOOL_BUTTON_NO_GFX_YPOS TOOL_BUTTON_YES_GFX_YPOS
3639 #define TOOL_BUTTON_NO_XSIZE TOOL_BUTTON_YES_XSIZE
3640 #define TOOL_BUTTON_NO_YSIZE TOOL_BUTTON_YES_YSIZE
3641 #define TOOL_BUTTON_CONFIRM_XPOS TOOL_BUTTON_YES_XPOS
3642 #define TOOL_BUTTON_CONFIRM_YPOS TOOL_BUTTON_YES_YPOS
3643 #define TOOL_BUTTON_CONFIRM_GFX_YPOS 30
3644 #define TOOL_BUTTON_CONFIRM_XSIZE 96
3645 #define TOOL_BUTTON_CONFIRM_YSIZE TOOL_BUTTON_YES_YSIZE
3646 #define TOOL_BUTTON_PLAYER_XSIZE 30
3647 #define TOOL_BUTTON_PLAYER_YSIZE 30
3648 #define TOOL_BUTTON_PLAYER_GFX_XPOS 5
3649 #define TOOL_BUTTON_PLAYER_GFX_YPOS 185
3650 #define TOOL_BUTTON_PLAYER_XPOS (5 + TOOL_BUTTON_PLAYER_XSIZE / 2)
3651 #define TOOL_BUTTON_PLAYER_YPOS (215 - TOOL_BUTTON_PLAYER_YSIZE / 2)
3652 #define TOOL_BUTTON_PLAYER1_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3653 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
3654 #define TOOL_BUTTON_PLAYER2_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3655 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
3656 #define TOOL_BUTTON_PLAYER3_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3657 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
3658 #define TOOL_BUTTON_PLAYER4_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3659 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
3660 #define TOOL_BUTTON_PLAYER1_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3661 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
3662 #define TOOL_BUTTON_PLAYER2_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3663 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
3664 #define TOOL_BUTTON_PLAYER3_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3665 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
3666 #define TOOL_BUTTON_PLAYER4_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3667 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
3676 } toolbutton_info[NUM_TOOL_BUTTONS] =
3679 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_GFX_YPOS,
3680 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_YPOS,
3681 TOOL_BUTTON_YES_XSIZE, TOOL_BUTTON_YES_YSIZE,
3686 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_GFX_YPOS,
3687 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_YPOS,
3688 TOOL_BUTTON_NO_XSIZE, TOOL_BUTTON_NO_YSIZE,
3693 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_GFX_YPOS,
3694 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_YPOS,
3695 TOOL_BUTTON_CONFIRM_XSIZE, TOOL_BUTTON_CONFIRM_YSIZE,
3696 TOOL_CTRL_ID_CONFIRM,
3700 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3701 TOOL_BUTTON_PLAYER1_XPOS, TOOL_BUTTON_PLAYER1_YPOS,
3702 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3703 TOOL_CTRL_ID_PLAYER_1,
3707 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3708 TOOL_BUTTON_PLAYER2_XPOS, TOOL_BUTTON_PLAYER2_YPOS,
3709 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3710 TOOL_CTRL_ID_PLAYER_2,
3714 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3715 TOOL_BUTTON_PLAYER3_XPOS, TOOL_BUTTON_PLAYER3_YPOS,
3716 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3717 TOOL_CTRL_ID_PLAYER_3,
3721 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3722 TOOL_BUTTON_PLAYER4_XPOS, TOOL_BUTTON_PLAYER4_YPOS,
3723 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3724 TOOL_CTRL_ID_PLAYER_4,
3729 void CreateToolButtons()
3733 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3735 Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
3736 Bitmap *deco_bitmap = None;
3737 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
3738 struct GadgetInfo *gi;
3739 unsigned long event_mask;
3740 int gd_xoffset, gd_yoffset;
3741 int gd_x1, gd_x2, gd_y;
3744 event_mask = GD_EVENT_RELEASED;
3746 gd_xoffset = toolbutton_info[i].xpos;
3747 gd_yoffset = toolbutton_info[i].ypos;
3748 gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
3749 gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
3750 gd_y = DOOR_GFX_PAGEY1 + gd_yoffset;
3752 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
3754 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
3756 getMiniGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr),
3757 &deco_bitmap, &deco_x, &deco_y);
3758 deco_xpos = (toolbutton_info[i].width - MINI_TILEX) / 2;
3759 deco_ypos = (toolbutton_info[i].height - MINI_TILEY) / 2;
3762 gi = CreateGadget(GDI_CUSTOM_ID, id,
3763 GDI_INFO_TEXT, toolbutton_info[i].infotext,
3764 GDI_X, DX + toolbutton_info[i].x,
3765 GDI_Y, DY + toolbutton_info[i].y,
3766 GDI_WIDTH, toolbutton_info[i].width,
3767 GDI_HEIGHT, toolbutton_info[i].height,
3768 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
3769 GDI_STATE, GD_BUTTON_UNPRESSED,
3770 GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
3771 GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
3772 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
3773 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
3774 GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
3775 GDI_DECORATION_SHIFTING, 1, 1,
3776 GDI_DIRECT_DRAW, FALSE,
3777 GDI_EVENT_MASK, event_mask,
3778 GDI_CALLBACK_ACTION, HandleToolButtons,
3782 Error(ERR_EXIT, "cannot create gadget");
3784 tool_gadget[id] = gi;
3788 void FreeToolButtons()
3792 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3793 FreeGadget(tool_gadget[i]);
3796 static void UnmapToolButtons()
3800 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3801 UnmapGadget(tool_gadget[i]);
3804 static void HandleToolButtons(struct GadgetInfo *gi)
3806 request_gadget_id = gi->custom_id;
3809 static struct Mapping_EM_to_RND_object
3812 boolean is_rnd_to_em_mapping; /* unique mapping EM <-> RND */
3813 boolean is_backside; /* backside of moving element */
3819 em_object_mapping_list[] =
3822 Xblank, TRUE, FALSE,
3826 Yacid_splash_eB, FALSE, FALSE,
3827 EL_ACID_SPLASH_RIGHT, -1, -1
3830 Yacid_splash_wB, FALSE, FALSE,
3831 EL_ACID_SPLASH_LEFT, -1, -1
3834 #ifdef EM_ENGINE_BAD_ROLL
3836 Xstone_force_e, FALSE, FALSE,
3837 EL_ROCK, -1, MV_BIT_RIGHT
3840 Xstone_force_w, FALSE, FALSE,
3841 EL_ROCK, -1, MV_BIT_LEFT
3844 Xnut_force_e, FALSE, FALSE,
3845 EL_NUT, -1, MV_BIT_RIGHT
3848 Xnut_force_w, FALSE, FALSE,
3849 EL_NUT, -1, MV_BIT_LEFT
3852 Xspring_force_e, FALSE, FALSE,
3853 EL_SPRING, -1, MV_BIT_RIGHT
3856 Xspring_force_w, FALSE, FALSE,
3857 EL_SPRING, -1, MV_BIT_LEFT
3860 Xemerald_force_e, FALSE, FALSE,
3861 EL_EMERALD, -1, MV_BIT_RIGHT
3864 Xemerald_force_w, FALSE, FALSE,
3865 EL_EMERALD, -1, MV_BIT_LEFT
3868 Xdiamond_force_e, FALSE, FALSE,
3869 EL_DIAMOND, -1, MV_BIT_RIGHT
3872 Xdiamond_force_w, FALSE, FALSE,
3873 EL_DIAMOND, -1, MV_BIT_LEFT
3876 Xbomb_force_e, FALSE, FALSE,
3877 EL_BOMB, -1, MV_BIT_RIGHT
3880 Xbomb_force_w, FALSE, FALSE,
3881 EL_BOMB, -1, MV_BIT_LEFT
3883 #endif /* EM_ENGINE_BAD_ROLL */
3886 Xstone, TRUE, FALSE,
3890 Xstone_pause, FALSE, FALSE,
3894 Xstone_fall, FALSE, FALSE,
3898 Ystone_s, FALSE, FALSE,
3899 EL_ROCK, ACTION_FALLING, -1
3902 Ystone_sB, FALSE, TRUE,
3903 EL_ROCK, ACTION_FALLING, -1
3906 Ystone_e, FALSE, FALSE,
3907 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
3910 Ystone_eB, FALSE, TRUE,
3911 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
3914 Ystone_w, FALSE, FALSE,
3915 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
3918 Ystone_wB, FALSE, TRUE,
3919 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
3926 Xnut_pause, FALSE, FALSE,
3930 Xnut_fall, FALSE, FALSE,
3934 Ynut_s, FALSE, FALSE,
3935 EL_NUT, ACTION_FALLING, -1
3938 Ynut_sB, FALSE, TRUE,
3939 EL_NUT, ACTION_FALLING, -1
3942 Ynut_e, FALSE, FALSE,
3943 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
3946 Ynut_eB, FALSE, TRUE,
3947 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
3950 Ynut_w, FALSE, FALSE,
3951 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
3954 Ynut_wB, FALSE, TRUE,
3955 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
3958 Xbug_n, TRUE, FALSE,
3962 Xbug_e, TRUE, FALSE,
3963 EL_BUG_RIGHT, -1, -1
3966 Xbug_s, TRUE, FALSE,
3970 Xbug_w, TRUE, FALSE,
3974 Xbug_gon, FALSE, FALSE,
3978 Xbug_goe, FALSE, FALSE,
3979 EL_BUG_RIGHT, -1, -1
3982 Xbug_gos, FALSE, FALSE,
3986 Xbug_gow, FALSE, FALSE,
3990 Ybug_n, FALSE, FALSE,
3991 EL_BUG, ACTION_MOVING, MV_BIT_UP
3994 Ybug_nB, FALSE, TRUE,
3995 EL_BUG, ACTION_MOVING, MV_BIT_UP
3998 Ybug_e, FALSE, FALSE,
3999 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
4002 Ybug_eB, FALSE, TRUE,
4003 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
4006 Ybug_s, FALSE, FALSE,
4007 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
4010 Ybug_sB, FALSE, TRUE,
4011 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
4014 Ybug_w, FALSE, FALSE,
4015 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
4018 Ybug_wB, FALSE, TRUE,
4019 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
4022 Ybug_w_n, FALSE, FALSE,
4023 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
4026 Ybug_n_e, FALSE, FALSE,
4027 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
4030 Ybug_e_s, FALSE, FALSE,
4031 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
4034 Ybug_s_w, FALSE, FALSE,
4035 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
4038 Ybug_e_n, FALSE, FALSE,
4039 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
4042 Ybug_s_e, FALSE, FALSE,
4043 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
4046 Ybug_w_s, FALSE, FALSE,
4047 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
4050 Ybug_n_w, FALSE, FALSE,
4051 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
4054 Ybug_stone, FALSE, FALSE,
4055 EL_BUG, ACTION_SMASHED_BY_ROCK, -1
4058 Ybug_spring, FALSE, FALSE,
4059 EL_BUG, ACTION_SMASHED_BY_SPRING, -1
4062 Xtank_n, TRUE, FALSE,
4063 EL_SPACESHIP_UP, -1, -1
4066 Xtank_e, TRUE, FALSE,
4067 EL_SPACESHIP_RIGHT, -1, -1
4070 Xtank_s, TRUE, FALSE,
4071 EL_SPACESHIP_DOWN, -1, -1
4074 Xtank_w, TRUE, FALSE,
4075 EL_SPACESHIP_LEFT, -1, -1
4078 Xtank_gon, FALSE, FALSE,
4079 EL_SPACESHIP_UP, -1, -1
4082 Xtank_goe, FALSE, FALSE,
4083 EL_SPACESHIP_RIGHT, -1, -1
4086 Xtank_gos, FALSE, FALSE,
4087 EL_SPACESHIP_DOWN, -1, -1
4090 Xtank_gow, FALSE, FALSE,
4091 EL_SPACESHIP_LEFT, -1, -1
4094 Ytank_n, FALSE, FALSE,
4095 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
4098 Ytank_nB, FALSE, TRUE,
4099 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
4102 Ytank_e, FALSE, FALSE,
4103 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
4106 Ytank_eB, FALSE, TRUE,
4107 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
4110 Ytank_s, FALSE, FALSE,
4111 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
4114 Ytank_sB, FALSE, TRUE,
4115 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
4118 Ytank_w, FALSE, FALSE,
4119 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
4122 Ytank_wB, FALSE, TRUE,
4123 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
4126 Ytank_w_n, FALSE, FALSE,
4127 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
4130 Ytank_n_e, FALSE, FALSE,
4131 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
4134 Ytank_e_s, FALSE, FALSE,
4135 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
4138 Ytank_s_w, FALSE, FALSE,
4139 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
4142 Ytank_e_n, FALSE, FALSE,
4143 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
4146 Ytank_s_e, FALSE, FALSE,
4147 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
4150 Ytank_w_s, FALSE, FALSE,
4151 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
4154 Ytank_n_w, FALSE, FALSE,
4155 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
4158 Ytank_stone, FALSE, FALSE,
4159 EL_SPACESHIP, ACTION_SMASHED_BY_ROCK, -1
4162 Ytank_spring, FALSE, FALSE,
4163 EL_SPACESHIP, ACTION_SMASHED_BY_SPRING, -1
4166 Xandroid, TRUE, FALSE,
4167 EL_EMC_ANDROID, ACTION_ACTIVE, -1
4170 Xandroid_1_n, FALSE, FALSE,
4171 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
4174 Xandroid_2_n, FALSE, FALSE,
4175 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
4178 Xandroid_1_e, FALSE, FALSE,
4179 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
4182 Xandroid_2_e, FALSE, FALSE,
4183 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
4186 Xandroid_1_w, FALSE, FALSE,
4187 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
4190 Xandroid_2_w, FALSE, FALSE,
4191 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
4194 Xandroid_1_s, FALSE, FALSE,
4195 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
4198 Xandroid_2_s, FALSE, FALSE,
4199 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
4202 Yandroid_n, FALSE, FALSE,
4203 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
4206 Yandroid_nB, FALSE, TRUE,
4207 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
4210 Yandroid_ne, FALSE, FALSE,
4211 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPRIGHT
4214 Yandroid_neB, FALSE, TRUE,
4215 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPRIGHT
4218 Yandroid_e, FALSE, FALSE,
4219 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
4222 Yandroid_eB, FALSE, TRUE,
4223 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
4226 Yandroid_se, FALSE, FALSE,
4227 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNRIGHT
4230 Yandroid_seB, FALSE, TRUE,
4231 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNRIGHT
4234 Yandroid_s, FALSE, FALSE,
4235 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
4238 Yandroid_sB, FALSE, TRUE,
4239 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
4242 Yandroid_sw, FALSE, FALSE,
4243 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNLEFT
4246 Yandroid_swB, FALSE, TRUE,
4247 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNLEFT
4250 Yandroid_w, FALSE, FALSE,
4251 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
4254 Yandroid_wB, FALSE, TRUE,
4255 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
4258 Yandroid_nw, FALSE, FALSE,
4259 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPLEFT
4262 Yandroid_nwB, FALSE, TRUE,
4263 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPLEFT
4266 Xspring, TRUE, FALSE,
4270 Xspring_pause, FALSE, FALSE,
4274 Xspring_e, FALSE, FALSE,
4278 Xspring_w, FALSE, FALSE,
4282 Xspring_fall, FALSE, FALSE,
4286 Yspring_s, FALSE, FALSE,
4287 EL_SPRING, ACTION_FALLING, -1
4290 Yspring_sB, FALSE, TRUE,
4291 EL_SPRING, ACTION_FALLING, -1
4294 Yspring_e, FALSE, FALSE,
4295 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
4298 Yspring_eB, FALSE, TRUE,
4299 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
4302 Yspring_w, FALSE, FALSE,
4303 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
4306 Yspring_wB, FALSE, TRUE,
4307 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
4310 Yspring_kill_e, FALSE, FALSE,
4311 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
4314 Yspring_kill_eB, FALSE, TRUE,
4315 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
4318 Yspring_kill_w, FALSE, FALSE,
4319 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
4322 Yspring_kill_wB, FALSE, TRUE,
4323 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
4326 Xeater_n, TRUE, FALSE,
4327 EL_YAMYAM_UP, -1, -1
4330 Xeater_e, TRUE, FALSE,
4331 EL_YAMYAM_RIGHT, -1, -1
4334 Xeater_w, TRUE, FALSE,
4335 EL_YAMYAM_LEFT, -1, -1
4338 Xeater_s, TRUE, FALSE,
4339 EL_YAMYAM_DOWN, -1, -1
4342 Yeater_n, FALSE, FALSE,
4343 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
4346 Yeater_nB, FALSE, TRUE,
4347 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
4350 Yeater_e, FALSE, FALSE,
4351 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
4354 Yeater_eB, FALSE, TRUE,
4355 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
4358 Yeater_s, FALSE, FALSE,
4359 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
4362 Yeater_sB, FALSE, TRUE,
4363 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
4366 Yeater_w, FALSE, FALSE,
4367 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
4370 Yeater_wB, FALSE, TRUE,
4371 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
4374 Yeater_stone, FALSE, FALSE,
4375 EL_YAMYAM, ACTION_SMASHED_BY_ROCK, -1
4378 Yeater_spring, FALSE, FALSE,
4379 EL_YAMYAM, ACTION_SMASHED_BY_SPRING, -1
4382 Xalien, TRUE, FALSE,
4386 Xalien_pause, FALSE, FALSE,
4390 Yalien_n, FALSE, FALSE,
4391 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
4394 Yalien_nB, FALSE, TRUE,
4395 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
4398 Yalien_e, FALSE, FALSE,
4399 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
4402 Yalien_eB, FALSE, TRUE,
4403 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
4406 Yalien_s, FALSE, FALSE,
4407 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
4410 Yalien_sB, FALSE, TRUE,
4411 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
4414 Yalien_w, FALSE, FALSE,
4415 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
4418 Yalien_wB, FALSE, TRUE,
4419 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
4422 Yalien_stone, FALSE, FALSE,
4423 EL_ROBOT, ACTION_SMASHED_BY_ROCK, -1
4426 Yalien_spring, FALSE, FALSE,
4427 EL_ROBOT, ACTION_SMASHED_BY_SPRING, -1
4430 Xemerald, TRUE, FALSE,
4434 Xemerald_pause, FALSE, FALSE,
4438 Xemerald_fall, FALSE, FALSE,
4442 Xemerald_shine, FALSE, FALSE,
4443 EL_EMERALD, ACTION_TWINKLING, -1
4446 Yemerald_s, FALSE, FALSE,
4447 EL_EMERALD, ACTION_FALLING, -1
4450 Yemerald_sB, FALSE, TRUE,
4451 EL_EMERALD, ACTION_FALLING, -1
4454 Yemerald_e, FALSE, FALSE,
4455 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
4458 Yemerald_eB, FALSE, TRUE,
4459 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
4462 Yemerald_w, FALSE, FALSE,
4463 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
4466 Yemerald_wB, FALSE, TRUE,
4467 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
4470 Yemerald_eat, FALSE, FALSE,
4471 EL_EMERALD, ACTION_COLLECTING, -1
4474 Yemerald_stone, FALSE, FALSE,
4475 EL_NUT, ACTION_BREAKING, -1
4478 Xdiamond, TRUE, FALSE,
4482 Xdiamond_pause, FALSE, FALSE,
4486 Xdiamond_fall, FALSE, FALSE,
4490 Xdiamond_shine, FALSE, FALSE,
4491 EL_DIAMOND, ACTION_TWINKLING, -1
4494 Ydiamond_s, FALSE, FALSE,
4495 EL_DIAMOND, ACTION_FALLING, -1
4498 Ydiamond_sB, FALSE, TRUE,
4499 EL_DIAMOND, ACTION_FALLING, -1
4502 Ydiamond_e, FALSE, FALSE,
4503 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
4506 Ydiamond_eB, FALSE, TRUE,
4507 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
4510 Ydiamond_w, FALSE, FALSE,
4511 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
4514 Ydiamond_wB, FALSE, TRUE,
4515 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
4518 Ydiamond_eat, FALSE, FALSE,
4519 EL_DIAMOND, ACTION_COLLECTING, -1
4522 Ydiamond_stone, FALSE, FALSE,
4523 EL_DIAMOND, ACTION_SMASHED_BY_ROCK, -1
4526 Xdrip_fall, TRUE, FALSE,
4527 EL_AMOEBA_DROP, -1, -1
4530 Xdrip_stretch, FALSE, FALSE,
4531 EL_AMOEBA_DROP, ACTION_FALLING, -1
4534 Xdrip_stretchB, FALSE, TRUE,
4535 EL_AMOEBA_DROP, ACTION_FALLING, -1
4538 Xdrip_eat, FALSE, FALSE,
4539 EL_AMOEBA_DROP, ACTION_GROWING, -1
4542 Ydrip_s1, FALSE, FALSE,
4543 EL_AMOEBA_DROP, ACTION_FALLING, -1
4546 Ydrip_s1B, FALSE, TRUE,
4547 EL_AMOEBA_DROP, ACTION_FALLING, -1
4550 Ydrip_s2, FALSE, FALSE,
4551 EL_AMOEBA_DROP, ACTION_FALLING, -1
4554 Ydrip_s2B, FALSE, TRUE,
4555 EL_AMOEBA_DROP, ACTION_FALLING, -1
4562 Xbomb_pause, FALSE, FALSE,
4566 Xbomb_fall, FALSE, FALSE,
4570 Ybomb_s, FALSE, FALSE,
4571 EL_BOMB, ACTION_FALLING, -1
4574 Ybomb_sB, FALSE, TRUE,
4575 EL_BOMB, ACTION_FALLING, -1
4578 Ybomb_e, FALSE, FALSE,
4579 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
4582 Ybomb_eB, FALSE, TRUE,
4583 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
4586 Ybomb_w, FALSE, FALSE,
4587 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
4590 Ybomb_wB, FALSE, TRUE,
4591 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
4594 Ybomb_eat, FALSE, FALSE,
4595 EL_BOMB, ACTION_ACTIVATING, -1
4598 Xballoon, TRUE, FALSE,
4602 Yballoon_n, FALSE, FALSE,
4603 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
4606 Yballoon_nB, FALSE, TRUE,
4607 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
4610 Yballoon_e, FALSE, FALSE,
4611 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
4614 Yballoon_eB, FALSE, TRUE,
4615 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
4618 Yballoon_s, FALSE, FALSE,
4619 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
4622 Yballoon_sB, FALSE, TRUE,
4623 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
4626 Yballoon_w, FALSE, FALSE,
4627 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
4630 Yballoon_wB, FALSE, TRUE,
4631 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
4634 Xgrass, TRUE, FALSE,
4635 EL_EMC_GRASS, -1, -1
4638 Ygrass_nB, FALSE, FALSE,
4639 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_UP
4642 Ygrass_eB, FALSE, FALSE,
4643 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_RIGHT
4646 Ygrass_sB, FALSE, FALSE,
4647 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_DOWN
4650 Ygrass_wB, FALSE, FALSE,
4651 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_LEFT
4658 Ydirt_nB, FALSE, FALSE,
4659 EL_SAND, ACTION_DIGGING, MV_BIT_UP
4662 Ydirt_eB, FALSE, FALSE,
4663 EL_SAND, ACTION_DIGGING, MV_BIT_RIGHT
4666 Ydirt_sB, FALSE, FALSE,
4667 EL_SAND, ACTION_DIGGING, MV_BIT_DOWN
4670 Ydirt_wB, FALSE, FALSE,
4671 EL_SAND, ACTION_DIGGING, MV_BIT_LEFT
4674 Xacid_ne, TRUE, FALSE,
4675 EL_ACID_POOL_TOPRIGHT, -1, -1
4678 Xacid_se, TRUE, FALSE,
4679 EL_ACID_POOL_BOTTOMRIGHT, -1, -1
4682 Xacid_s, TRUE, FALSE,
4683 EL_ACID_POOL_BOTTOM, -1, -1
4686 Xacid_sw, TRUE, FALSE,
4687 EL_ACID_POOL_BOTTOMLEFT, -1, -1
4690 Xacid_nw, TRUE, FALSE,
4691 EL_ACID_POOL_TOPLEFT, -1, -1
4694 Xacid_1, TRUE, FALSE,
4698 Xacid_2, FALSE, FALSE,
4702 Xacid_3, FALSE, FALSE,
4706 Xacid_4, FALSE, FALSE,
4710 Xacid_5, FALSE, FALSE,
4714 Xacid_6, FALSE, FALSE,
4718 Xacid_7, FALSE, FALSE,
4722 Xacid_8, FALSE, FALSE,
4726 Xball_1, TRUE, FALSE,
4727 EL_EMC_MAGIC_BALL, -1, -1
4730 Xball_1B, FALSE, FALSE,
4731 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
4734 Xball_2, FALSE, FALSE,
4735 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
4738 Xball_2B, FALSE, FALSE,
4739 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
4742 Yball_eat, FALSE, FALSE,
4743 EL_EMC_MAGIC_BALL, ACTION_DROPPING, -1
4746 Ykey_1_eat, FALSE, FALSE,
4747 EL_EM_KEY_1, ACTION_COLLECTING, -1
4750 Ykey_2_eat, FALSE, FALSE,
4751 EL_EM_KEY_2, ACTION_COLLECTING, -1
4754 Ykey_3_eat, FALSE, FALSE,
4755 EL_EM_KEY_3, ACTION_COLLECTING, -1
4758 Ykey_4_eat, FALSE, FALSE,
4759 EL_EM_KEY_4, ACTION_COLLECTING, -1
4762 Ykey_5_eat, FALSE, FALSE,
4763 EL_EMC_KEY_5, ACTION_COLLECTING, -1
4766 Ykey_6_eat, FALSE, FALSE,
4767 EL_EMC_KEY_6, ACTION_COLLECTING, -1
4770 Ykey_7_eat, FALSE, FALSE,
4771 EL_EMC_KEY_7, ACTION_COLLECTING, -1
4774 Ykey_8_eat, FALSE, FALSE,
4775 EL_EMC_KEY_8, ACTION_COLLECTING, -1
4778 Ylenses_eat, FALSE, FALSE,
4779 EL_EMC_LENSES, ACTION_COLLECTING, -1
4782 Ymagnify_eat, FALSE, FALSE,
4783 EL_EMC_MAGNIFIER, ACTION_COLLECTING, -1
4786 Ygrass_eat, FALSE, FALSE,
4787 EL_EMC_GRASS, ACTION_SNAPPING, -1
4790 Ydirt_eat, FALSE, FALSE,
4791 EL_SAND, ACTION_SNAPPING, -1
4794 Xgrow_ns, TRUE, FALSE,
4795 EL_EXPANDABLE_WALL_VERTICAL, -1, -1
4798 Ygrow_ns_eat, FALSE, FALSE,
4799 EL_EXPANDABLE_WALL_VERTICAL, ACTION_GROWING, -1
4802 Xgrow_ew, TRUE, FALSE,
4803 EL_EXPANDABLE_WALL_HORIZONTAL, -1, -1
4806 Ygrow_ew_eat, FALSE, FALSE,
4807 EL_EXPANDABLE_WALL_HORIZONTAL, ACTION_GROWING, -1
4810 Xwonderwall, TRUE, FALSE,
4811 EL_MAGIC_WALL, -1, -1
4814 XwonderwallB, FALSE, FALSE,
4815 EL_MAGIC_WALL, ACTION_ACTIVE, -1
4818 Xamoeba_1, TRUE, FALSE,
4819 EL_AMOEBA_DRY, ACTION_OTHER, -1
4822 Xamoeba_2, FALSE, FALSE,
4823 EL_AMOEBA_DRY, ACTION_OTHER, -1
4826 Xamoeba_3, FALSE, FALSE,
4827 EL_AMOEBA_DRY, ACTION_OTHER, -1
4830 Xamoeba_4, FALSE, FALSE,
4831 EL_AMOEBA_DRY, ACTION_OTHER, -1
4834 Xamoeba_5, TRUE, FALSE,
4835 EL_AMOEBA_WET, ACTION_OTHER, -1
4838 Xamoeba_6, FALSE, FALSE,
4839 EL_AMOEBA_WET, ACTION_OTHER, -1
4842 Xamoeba_7, FALSE, FALSE,
4843 EL_AMOEBA_WET, ACTION_OTHER, -1
4846 Xamoeba_8, FALSE, FALSE,
4847 EL_AMOEBA_WET, ACTION_OTHER, -1
4850 Xdoor_1, TRUE, FALSE,
4851 EL_EM_GATE_1, -1, -1
4854 Xdoor_2, TRUE, FALSE,
4855 EL_EM_GATE_2, -1, -1
4858 Xdoor_3, TRUE, FALSE,
4859 EL_EM_GATE_3, -1, -1
4862 Xdoor_4, TRUE, FALSE,
4863 EL_EM_GATE_4, -1, -1
4866 Xdoor_5, TRUE, FALSE,
4867 EL_EMC_GATE_5, -1, -1
4870 Xdoor_6, TRUE, FALSE,
4871 EL_EMC_GATE_6, -1, -1
4874 Xdoor_7, TRUE, FALSE,
4875 EL_EMC_GATE_7, -1, -1
4878 Xdoor_8, TRUE, FALSE,
4879 EL_EMC_GATE_8, -1, -1
4882 Xkey_1, TRUE, FALSE,
4886 Xkey_2, TRUE, FALSE,
4890 Xkey_3, TRUE, FALSE,
4894 Xkey_4, TRUE, FALSE,
4898 Xkey_5, TRUE, FALSE,
4899 EL_EMC_KEY_5, -1, -1
4902 Xkey_6, TRUE, FALSE,
4903 EL_EMC_KEY_6, -1, -1
4906 Xkey_7, TRUE, FALSE,
4907 EL_EMC_KEY_7, -1, -1
4910 Xkey_8, TRUE, FALSE,
4911 EL_EMC_KEY_8, -1, -1
4914 Xwind_n, TRUE, FALSE,
4915 EL_BALLOON_SWITCH_UP, -1, -1
4918 Xwind_e, TRUE, FALSE,
4919 EL_BALLOON_SWITCH_RIGHT, -1, -1
4922 Xwind_s, TRUE, FALSE,
4923 EL_BALLOON_SWITCH_DOWN, -1, -1
4926 Xwind_w, TRUE, FALSE,
4927 EL_BALLOON_SWITCH_LEFT, -1, -1
4930 Xwind_nesw, TRUE, FALSE,
4931 EL_BALLOON_SWITCH_ANY, -1, -1
4934 Xwind_stop, TRUE, FALSE,
4935 EL_BALLOON_SWITCH_NONE, -1, -1
4939 EL_EM_EXIT_CLOSED, -1, -1
4942 Xexit_1, TRUE, FALSE,
4943 EL_EM_EXIT_OPEN, -1, -1
4946 Xexit_2, FALSE, FALSE,
4947 EL_EM_EXIT_OPEN, -1, -1
4950 Xexit_3, FALSE, FALSE,
4951 EL_EM_EXIT_OPEN, -1, -1
4954 Xdynamite, TRUE, FALSE,
4955 EL_EM_DYNAMITE, -1, -1
4958 Ydynamite_eat, FALSE, FALSE,
4959 EL_EM_DYNAMITE, ACTION_COLLECTING, -1
4962 Xdynamite_1, TRUE, FALSE,
4963 EL_EM_DYNAMITE_ACTIVE, -1, -1
4966 Xdynamite_2, FALSE, FALSE,
4967 EL_EM_DYNAMITE_ACTIVE, -1, -1
4970 Xdynamite_3, FALSE, FALSE,
4971 EL_EM_DYNAMITE_ACTIVE, -1, -1
4974 Xdynamite_4, FALSE, FALSE,
4975 EL_EM_DYNAMITE_ACTIVE, -1, -1
4978 Xbumper, TRUE, FALSE,
4979 EL_EMC_SPRING_BUMPER, -1, -1
4982 XbumperB, FALSE, FALSE,
4983 EL_EMC_SPRING_BUMPER, ACTION_ACTIVE, -1
4986 Xwheel, TRUE, FALSE,
4987 EL_ROBOT_WHEEL, -1, -1
4990 XwheelB, FALSE, FALSE,
4991 EL_ROBOT_WHEEL, ACTION_ACTIVE, -1
4994 Xswitch, TRUE, FALSE,
4995 EL_EMC_MAGIC_BALL_SWITCH, -1, -1
4998 XswitchB, FALSE, FALSE,
4999 EL_EMC_MAGIC_BALL_SWITCH, ACTION_ACTIVE, -1
5003 EL_QUICKSAND_EMPTY, -1, -1
5006 Xsand_stone, TRUE, FALSE,
5007 EL_QUICKSAND_FULL, -1, -1
5010 Xsand_stonein_1, FALSE, TRUE,
5011 EL_ROCK, ACTION_FILLING, -1
5014 Xsand_stonein_2, FALSE, TRUE,
5015 EL_ROCK, ACTION_FILLING, -1
5018 Xsand_stonein_3, FALSE, TRUE,
5019 EL_ROCK, ACTION_FILLING, -1
5022 Xsand_stonein_4, FALSE, TRUE,
5023 EL_ROCK, ACTION_FILLING, -1
5027 Xsand_stonesand_1, FALSE, FALSE,
5028 EL_QUICKSAND_EMPTYING, -1, -1
5031 Xsand_stonesand_2, FALSE, FALSE,
5032 EL_QUICKSAND_EMPTYING, -1, -1
5035 Xsand_stonesand_3, FALSE, FALSE,
5036 EL_QUICKSAND_EMPTYING, -1, -1
5039 Xsand_stonesand_4, FALSE, FALSE,
5040 EL_QUICKSAND_EMPTYING, -1, -1
5043 Xsand_stonesand_quickout_1, FALSE, FALSE,
5044 EL_QUICKSAND_EMPTYING, -1, -1
5047 Xsand_stonesand_quickout_2, FALSE, FALSE,
5048 EL_QUICKSAND_EMPTYING, -1, -1
5052 Xsand_stonesand_1, FALSE, FALSE,
5053 EL_QUICKSAND_FULL, -1, -1
5056 Xsand_stonesand_2, FALSE, FALSE,
5057 EL_QUICKSAND_FULL, -1, -1
5060 Xsand_stonesand_3, FALSE, FALSE,
5061 EL_QUICKSAND_FULL, -1, -1
5064 Xsand_stonesand_4, FALSE, FALSE,
5065 EL_QUICKSAND_FULL, -1, -1
5069 Xsand_stoneout_1, FALSE, FALSE,
5070 EL_ROCK, ACTION_EMPTYING, -1
5073 Xsand_stoneout_2, FALSE, FALSE,
5074 EL_ROCK, ACTION_EMPTYING, -1
5078 Xsand_sandstone_1, FALSE, FALSE,
5079 EL_QUICKSAND_FILLING, -1, -1
5082 Xsand_sandstone_2, FALSE, FALSE,
5083 EL_QUICKSAND_FILLING, -1, -1
5086 Xsand_sandstone_3, FALSE, FALSE,
5087 EL_QUICKSAND_FILLING, -1, -1
5090 Xsand_sandstone_4, FALSE, FALSE,
5091 EL_QUICKSAND_FILLING, -1, -1
5095 Xsand_sandstone_1, FALSE, FALSE,
5096 EL_QUICKSAND_FULL, -1, -1
5099 Xsand_sandstone_2, FALSE, FALSE,
5100 EL_QUICKSAND_FULL, -1, -1
5103 Xsand_sandstone_3, FALSE, FALSE,
5104 EL_QUICKSAND_FULL, -1, -1
5107 Xsand_sandstone_4, FALSE, FALSE,
5108 EL_QUICKSAND_FULL, -1, -1
5112 Xplant, TRUE, FALSE,
5113 EL_EMC_PLANT, -1, -1
5116 Yplant, FALSE, FALSE,
5117 EL_EMC_PLANT, -1, -1
5120 Xlenses, TRUE, FALSE,
5121 EL_EMC_LENSES, -1, -1
5124 Xmagnify, TRUE, FALSE,
5125 EL_EMC_MAGNIFIER, -1, -1
5128 Xdripper, TRUE, FALSE,
5129 EL_EMC_DRIPPER, -1, -1
5132 XdripperB, FALSE, FALSE,
5133 EL_EMC_DRIPPER, ACTION_ACTIVE, -1
5136 Xfake_blank, TRUE, FALSE,
5137 EL_INVISIBLE_WALL, -1, -1
5140 Xfake_blankB, FALSE, FALSE,
5141 EL_INVISIBLE_WALL, ACTION_ACTIVE, -1
5144 Xfake_grass, TRUE, FALSE,
5145 EL_EMC_FAKE_GRASS, -1, -1
5148 Xfake_grassB, FALSE, FALSE,
5149 EL_EMC_FAKE_GRASS, ACTION_ACTIVE, -1
5152 Xfake_door_1, TRUE, FALSE,
5153 EL_EM_GATE_1_GRAY, -1, -1
5156 Xfake_door_2, TRUE, FALSE,
5157 EL_EM_GATE_2_GRAY, -1, -1
5160 Xfake_door_3, TRUE, FALSE,
5161 EL_EM_GATE_3_GRAY, -1, -1
5164 Xfake_door_4, TRUE, FALSE,
5165 EL_EM_GATE_4_GRAY, -1, -1
5168 Xfake_door_5, TRUE, FALSE,
5169 EL_EMC_GATE_5_GRAY, -1, -1
5172 Xfake_door_6, TRUE, FALSE,
5173 EL_EMC_GATE_6_GRAY, -1, -1
5176 Xfake_door_7, TRUE, FALSE,
5177 EL_EMC_GATE_7_GRAY, -1, -1
5180 Xfake_door_8, TRUE, FALSE,
5181 EL_EMC_GATE_8_GRAY, -1, -1
5184 Xfake_acid_1, TRUE, FALSE,
5185 EL_EMC_FAKE_ACID, -1, -1
5188 Xfake_acid_2, FALSE, FALSE,
5189 EL_EMC_FAKE_ACID, -1, -1
5192 Xfake_acid_3, FALSE, FALSE,
5193 EL_EMC_FAKE_ACID, -1, -1
5196 Xfake_acid_4, FALSE, FALSE,
5197 EL_EMC_FAKE_ACID, -1, -1
5200 Xfake_acid_5, FALSE, FALSE,
5201 EL_EMC_FAKE_ACID, -1, -1
5204 Xfake_acid_6, FALSE, FALSE,
5205 EL_EMC_FAKE_ACID, -1, -1
5208 Xfake_acid_7, FALSE, FALSE,
5209 EL_EMC_FAKE_ACID, -1, -1
5212 Xfake_acid_8, FALSE, FALSE,
5213 EL_EMC_FAKE_ACID, -1, -1
5216 Xsteel_1, TRUE, FALSE,
5217 EL_STEELWALL, -1, -1
5220 Xsteel_2, TRUE, FALSE,
5221 EL_EMC_STEELWALL_2, -1, -1
5224 Xsteel_3, TRUE, FALSE,
5225 EL_EMC_STEELWALL_3, -1, -1
5228 Xsteel_4, TRUE, FALSE,
5229 EL_EMC_STEELWALL_4, -1, -1
5232 Xwall_1, TRUE, FALSE,
5236 Xwall_2, TRUE, FALSE,
5237 EL_EMC_WALL_14, -1, -1
5240 Xwall_3, TRUE, FALSE,
5241 EL_EMC_WALL_15, -1, -1
5244 Xwall_4, TRUE, FALSE,
5245 EL_EMC_WALL_16, -1, -1
5248 Xround_wall_1, TRUE, FALSE,
5249 EL_WALL_SLIPPERY, -1, -1
5252 Xround_wall_2, TRUE, FALSE,
5253 EL_EMC_WALL_SLIPPERY_2, -1, -1
5256 Xround_wall_3, TRUE, FALSE,
5257 EL_EMC_WALL_SLIPPERY_3, -1, -1
5260 Xround_wall_4, TRUE, FALSE,
5261 EL_EMC_WALL_SLIPPERY_4, -1, -1
5264 Xdecor_1, TRUE, FALSE,
5265 EL_EMC_WALL_8, -1, -1
5268 Xdecor_2, TRUE, FALSE,
5269 EL_EMC_WALL_6, -1, -1
5272 Xdecor_3, TRUE, FALSE,
5273 EL_EMC_WALL_4, -1, -1
5276 Xdecor_4, TRUE, FALSE,
5277 EL_EMC_WALL_7, -1, -1
5280 Xdecor_5, TRUE, FALSE,
5281 EL_EMC_WALL_5, -1, -1
5284 Xdecor_6, TRUE, FALSE,
5285 EL_EMC_WALL_9, -1, -1
5288 Xdecor_7, TRUE, FALSE,
5289 EL_EMC_WALL_10, -1, -1
5292 Xdecor_8, TRUE, FALSE,
5293 EL_EMC_WALL_1, -1, -1
5296 Xdecor_9, TRUE, FALSE,
5297 EL_EMC_WALL_2, -1, -1
5300 Xdecor_10, TRUE, FALSE,
5301 EL_EMC_WALL_3, -1, -1
5304 Xdecor_11, TRUE, FALSE,
5305 EL_EMC_WALL_11, -1, -1
5308 Xdecor_12, TRUE, FALSE,
5309 EL_EMC_WALL_12, -1, -1
5312 Xalpha_0, TRUE, FALSE,
5313 EL_CHAR('0'), -1, -1
5316 Xalpha_1, TRUE, FALSE,
5317 EL_CHAR('1'), -1, -1
5320 Xalpha_2, TRUE, FALSE,
5321 EL_CHAR('2'), -1, -1
5324 Xalpha_3, TRUE, FALSE,
5325 EL_CHAR('3'), -1, -1
5328 Xalpha_4, TRUE, FALSE,
5329 EL_CHAR('4'), -1, -1
5332 Xalpha_5, TRUE, FALSE,
5333 EL_CHAR('5'), -1, -1
5336 Xalpha_6, TRUE, FALSE,
5337 EL_CHAR('6'), -1, -1
5340 Xalpha_7, TRUE, FALSE,
5341 EL_CHAR('7'), -1, -1
5344 Xalpha_8, TRUE, FALSE,
5345 EL_CHAR('8'), -1, -1
5348 Xalpha_9, TRUE, FALSE,
5349 EL_CHAR('9'), -1, -1
5352 Xalpha_excla, TRUE, FALSE,
5353 EL_CHAR('!'), -1, -1
5356 Xalpha_quote, TRUE, FALSE,
5357 EL_CHAR('"'), -1, -1
5360 Xalpha_comma, TRUE, FALSE,
5361 EL_CHAR(','), -1, -1
5364 Xalpha_minus, TRUE, FALSE,
5365 EL_CHAR('-'), -1, -1
5368 Xalpha_perio, TRUE, FALSE,
5369 EL_CHAR('.'), -1, -1
5372 Xalpha_colon, TRUE, FALSE,
5373 EL_CHAR(':'), -1, -1
5376 Xalpha_quest, TRUE, FALSE,
5377 EL_CHAR('?'), -1, -1
5380 Xalpha_a, TRUE, FALSE,
5381 EL_CHAR('A'), -1, -1
5384 Xalpha_b, TRUE, FALSE,
5385 EL_CHAR('B'), -1, -1
5388 Xalpha_c, TRUE, FALSE,
5389 EL_CHAR('C'), -1, -1
5392 Xalpha_d, TRUE, FALSE,
5393 EL_CHAR('D'), -1, -1
5396 Xalpha_e, TRUE, FALSE,
5397 EL_CHAR('E'), -1, -1
5400 Xalpha_f, TRUE, FALSE,
5401 EL_CHAR('F'), -1, -1
5404 Xalpha_g, TRUE, FALSE,
5405 EL_CHAR('G'), -1, -1
5408 Xalpha_h, TRUE, FALSE,
5409 EL_CHAR('H'), -1, -1
5412 Xalpha_i, TRUE, FALSE,
5413 EL_CHAR('I'), -1, -1
5416 Xalpha_j, TRUE, FALSE,
5417 EL_CHAR('J'), -1, -1
5420 Xalpha_k, TRUE, FALSE,
5421 EL_CHAR('K'), -1, -1
5424 Xalpha_l, TRUE, FALSE,
5425 EL_CHAR('L'), -1, -1
5428 Xalpha_m, TRUE, FALSE,
5429 EL_CHAR('M'), -1, -1
5432 Xalpha_n, TRUE, FALSE,
5433 EL_CHAR('N'), -1, -1
5436 Xalpha_o, TRUE, FALSE,
5437 EL_CHAR('O'), -1, -1
5440 Xalpha_p, TRUE, FALSE,
5441 EL_CHAR('P'), -1, -1
5444 Xalpha_q, TRUE, FALSE,
5445 EL_CHAR('Q'), -1, -1
5448 Xalpha_r, TRUE, FALSE,
5449 EL_CHAR('R'), -1, -1
5452 Xalpha_s, TRUE, FALSE,
5453 EL_CHAR('S'), -1, -1
5456 Xalpha_t, TRUE, FALSE,
5457 EL_CHAR('T'), -1, -1
5460 Xalpha_u, TRUE, FALSE,
5461 EL_CHAR('U'), -1, -1
5464 Xalpha_v, TRUE, FALSE,
5465 EL_CHAR('V'), -1, -1
5468 Xalpha_w, TRUE, FALSE,
5469 EL_CHAR('W'), -1, -1
5472 Xalpha_x, TRUE, FALSE,
5473 EL_CHAR('X'), -1, -1
5476 Xalpha_y, TRUE, FALSE,
5477 EL_CHAR('Y'), -1, -1
5480 Xalpha_z, TRUE, FALSE,
5481 EL_CHAR('Z'), -1, -1
5484 Xalpha_arrow_e, TRUE, FALSE,
5485 EL_CHAR('>'), -1, -1
5488 Xalpha_arrow_w, TRUE, FALSE,
5489 EL_CHAR('<'), -1, -1
5492 Xalpha_copyr, TRUE, FALSE,
5493 EL_CHAR('©'), -1, -1
5497 Xboom_bug, FALSE, FALSE,
5498 EL_BUG, ACTION_EXPLODING, -1
5501 Xboom_bomb, FALSE, FALSE,
5502 EL_BOMB, ACTION_EXPLODING, -1
5505 Xboom_android, FALSE, FALSE,
5506 EL_EMC_ANDROID, ACTION_OTHER, -1
5509 Xboom_1, FALSE, FALSE,
5510 EL_DEFAULT, ACTION_EXPLODING, -1
5513 Xboom_2, FALSE, FALSE,
5514 EL_DEFAULT, ACTION_EXPLODING, -1
5517 Znormal, FALSE, FALSE,
5521 Zdynamite, FALSE, FALSE,
5525 Zplayer, FALSE, FALSE,
5529 ZBORDER, FALSE, FALSE,
5539 static struct Mapping_EM_to_RND_player
5548 em_player_mapping_list[] =
5552 EL_PLAYER_1, ACTION_MOVING, MV_BIT_UP,
5556 EL_PLAYER_1, ACTION_MOVING, MV_BIT_RIGHT,
5560 EL_PLAYER_1, ACTION_MOVING, MV_BIT_DOWN,
5564 EL_PLAYER_1, ACTION_MOVING, MV_BIT_LEFT,
5568 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_UP,
5572 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_RIGHT,
5576 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_DOWN,
5580 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_LEFT,
5584 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_UP,
5588 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_RIGHT,
5592 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_DOWN,
5596 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_LEFT,
5600 EL_PLAYER_2, ACTION_MOVING, MV_BIT_UP,
5604 EL_PLAYER_2, ACTION_MOVING, MV_BIT_RIGHT,
5608 EL_PLAYER_2, ACTION_MOVING, MV_BIT_DOWN,
5612 EL_PLAYER_2, ACTION_MOVING, MV_BIT_LEFT,
5616 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_UP,
5620 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_RIGHT,
5624 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_DOWN,
5628 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_LEFT,
5632 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_UP,
5636 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_RIGHT,
5640 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_DOWN,
5644 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_LEFT,
5648 EL_PLAYER_1, ACTION_DEFAULT, -1,
5652 EL_PLAYER_2, ACTION_DEFAULT, -1,
5656 EL_PLAYER_3, ACTION_MOVING, MV_BIT_UP,
5660 EL_PLAYER_3, ACTION_MOVING, MV_BIT_RIGHT,
5664 EL_PLAYER_3, ACTION_MOVING, MV_BIT_DOWN,
5668 EL_PLAYER_3, ACTION_MOVING, MV_BIT_LEFT,
5672 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_UP,
5676 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_RIGHT,
5680 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_DOWN,
5684 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_LEFT,
5688 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_UP,
5692 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_RIGHT,
5696 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_DOWN,
5700 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_LEFT,
5704 EL_PLAYER_4, ACTION_MOVING, MV_BIT_UP,
5708 EL_PLAYER_4, ACTION_MOVING, MV_BIT_RIGHT,
5712 EL_PLAYER_4, ACTION_MOVING, MV_BIT_DOWN,
5716 EL_PLAYER_4, ACTION_MOVING, MV_BIT_LEFT,
5720 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_UP,
5724 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_RIGHT,
5728 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_DOWN,
5732 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_LEFT,
5736 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_UP,
5740 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_RIGHT,
5744 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_DOWN,
5748 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_LEFT,
5752 EL_PLAYER_3, ACTION_DEFAULT, -1,
5756 EL_PLAYER_4, ACTION_DEFAULT, -1,
5765 int map_element_RND_to_EM(int element_rnd)
5767 static unsigned short mapping_RND_to_EM[NUM_FILE_ELEMENTS];
5768 static boolean mapping_initialized = FALSE;
5770 if (!mapping_initialized)
5774 /* return "Xalpha_quest" for all undefined elements in mapping array */
5775 for (i = 0; i < NUM_FILE_ELEMENTS; i++)
5776 mapping_RND_to_EM[i] = Xalpha_quest;
5778 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5779 if (em_object_mapping_list[i].is_rnd_to_em_mapping)
5780 mapping_RND_to_EM[em_object_mapping_list[i].element_rnd] =
5781 em_object_mapping_list[i].element_em;
5783 mapping_initialized = TRUE;
5786 if (element_rnd >= 0 && element_rnd < NUM_FILE_ELEMENTS)
5787 return mapping_RND_to_EM[element_rnd];
5789 Error(ERR_WARN, "invalid RND level element %d", element_rnd);
5794 int map_element_EM_to_RND(int element_em)
5796 static unsigned short mapping_EM_to_RND[TILE_MAX];
5797 static boolean mapping_initialized = FALSE;
5799 if (!mapping_initialized)
5803 /* return "EL_UNKNOWN" for all undefined elements in mapping array */
5804 for (i = 0; i < TILE_MAX; i++)
5805 mapping_EM_to_RND[i] = EL_UNKNOWN;
5807 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5808 mapping_EM_to_RND[em_object_mapping_list[i].element_em] =
5809 em_object_mapping_list[i].element_rnd;
5811 mapping_initialized = TRUE;
5814 if (element_em >= 0 && element_em < TILE_MAX)
5815 return mapping_EM_to_RND[element_em];
5817 Error(ERR_WARN, "invalid EM level element %d", element_em);
5822 void map_android_clone_elements_RND_to_EM(struct LevelInfo *level)
5824 struct LevelInfo_EM *level_em = level->native_em_level;
5825 struct LEVEL *lev = level_em->lev;
5828 for (i = 0; i < TILE_MAX; i++)
5829 lev->android_array[i] = Xblank;
5831 for (i = 0; i < level->num_android_clone_elements; i++)
5833 int element_rnd = level->android_clone_element[i];
5834 int element_em = map_element_RND_to_EM(element_rnd);
5836 for (j = 0; em_object_mapping_list[j].element_em != -1; j++)
5837 if (em_object_mapping_list[j].element_rnd == element_rnd)
5838 lev->android_array[em_object_mapping_list[j].element_em] = element_em;
5842 void map_android_clone_elements_EM_to_RND(struct LevelInfo *level)
5844 struct LevelInfo_EM *level_em = level->native_em_level;
5845 struct LEVEL *lev = level_em->lev;
5848 level->num_android_clone_elements = 0;
5850 for (i = 0; i < TILE_MAX; i++)
5852 int element_em = lev->android_array[i];
5854 boolean element_found = FALSE;
5856 if (element_em == Xblank)
5859 element_rnd = map_element_EM_to_RND(element_em);
5861 for (j = 0; j < level->num_android_clone_elements; j++)
5862 if (level->android_clone_element[j] == element_rnd)
5863 element_found = TRUE;
5867 level->android_clone_element[level->num_android_clone_elements++] =
5870 if (level->num_android_clone_elements == MAX_ANDROID_ELEMENTS)
5875 if (level->num_android_clone_elements == 0)
5877 level->num_android_clone_elements = 1;
5878 level->android_clone_element[0] = EL_EMPTY;
5882 int map_direction_RND_to_EM(int direction)
5884 return (direction == MV_UP ? 0 :
5885 direction == MV_RIGHT ? 1 :
5886 direction == MV_DOWN ? 2 :
5887 direction == MV_LEFT ? 3 :
5891 int map_direction_EM_to_RND(int direction)
5893 return (direction == 0 ? MV_UP :
5894 direction == 1 ? MV_RIGHT :
5895 direction == 2 ? MV_DOWN :
5896 direction == 3 ? MV_LEFT :
5900 int get_next_element(int element)
5904 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
5905 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
5906 case EL_QUICKSAND_FAST_FILLING: return EL_QUICKSAND_FAST_FULL;
5907 case EL_QUICKSAND_FAST_EMPTYING: return EL_QUICKSAND_FAST_EMPTY;
5908 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
5909 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
5910 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
5911 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
5912 case EL_DC_MAGIC_WALL_FILLING: return EL_DC_MAGIC_WALL_FULL;
5913 case EL_DC_MAGIC_WALL_EMPTYING: return EL_DC_MAGIC_WALL_ACTIVE;
5914 case EL_AMOEBA_DROPPING: return EL_AMOEBA_WET;
5916 default: return element;
5921 int el_act_dir2img(int element, int action, int direction)
5923 element = GFX_ELEMENT(element);
5925 if (direction == MV_NONE)
5926 return element_info[element].graphic[action];
5928 direction = MV_DIR_TO_BIT(direction);
5930 return element_info[element].direction_graphic[action][direction];
5933 int el_act_dir2img(int element, int action, int direction)
5935 element = GFX_ELEMENT(element);
5936 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
5938 /* direction_graphic[][] == graphic[] for undefined direction graphics */
5939 return element_info[element].direction_graphic[action][direction];
5944 static int el_act_dir2crm(int element, int action, int direction)
5946 element = GFX_ELEMENT(element);
5948 if (direction == MV_NONE)
5949 return element_info[element].crumbled[action];
5951 direction = MV_DIR_TO_BIT(direction);
5953 return element_info[element].direction_crumbled[action][direction];
5956 static int el_act_dir2crm(int element, int action, int direction)
5958 element = GFX_ELEMENT(element);
5959 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
5961 /* direction_graphic[][] == graphic[] for undefined direction graphics */
5962 return element_info[element].direction_crumbled[action][direction];
5966 int el_act2img(int element, int action)
5968 element = GFX_ELEMENT(element);
5970 return element_info[element].graphic[action];
5973 int el_act2crm(int element, int action)
5975 element = GFX_ELEMENT(element);
5977 return element_info[element].crumbled[action];
5980 int el_dir2img(int element, int direction)
5982 element = GFX_ELEMENT(element);
5984 return el_act_dir2img(element, ACTION_DEFAULT, direction);
5987 int el2baseimg(int element)
5989 return element_info[element].graphic[ACTION_DEFAULT];
5992 int el2img(int element)
5994 element = GFX_ELEMENT(element);
5996 return element_info[element].graphic[ACTION_DEFAULT];
5999 int el2edimg(int element)
6001 element = GFX_ELEMENT(element);
6003 return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
6006 int el2preimg(int element)
6008 element = GFX_ELEMENT(element);
6010 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];
6013 int el2panelimg(int element)
6015 element = GFX_ELEMENT(element);
6017 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PANEL];
6020 int font2baseimg(int font_nr)
6022 return font_info[font_nr].special_graphic[GFX_SPECIAL_ARG_DEFAULT];
6025 int getBeltNrFromBeltElement(int element)
6027 return (element < EL_CONVEYOR_BELT_2_LEFT ? 0 :
6028 element < EL_CONVEYOR_BELT_3_LEFT ? 1 :
6029 element < EL_CONVEYOR_BELT_4_LEFT ? 2 : 3);
6032 int getBeltNrFromBeltActiveElement(int element)
6034 return (element < EL_CONVEYOR_BELT_2_LEFT_ACTIVE ? 0 :
6035 element < EL_CONVEYOR_BELT_3_LEFT_ACTIVE ? 1 :
6036 element < EL_CONVEYOR_BELT_4_LEFT_ACTIVE ? 2 : 3);
6039 int getBeltNrFromBeltSwitchElement(int element)
6041 return (element < EL_CONVEYOR_BELT_2_SWITCH_LEFT ? 0 :
6042 element < EL_CONVEYOR_BELT_3_SWITCH_LEFT ? 1 :
6043 element < EL_CONVEYOR_BELT_4_SWITCH_LEFT ? 2 : 3);
6046 int getBeltDirNrFromBeltElement(int element)
6048 static int belt_base_element[4] =
6050 EL_CONVEYOR_BELT_1_LEFT,
6051 EL_CONVEYOR_BELT_2_LEFT,
6052 EL_CONVEYOR_BELT_3_LEFT,
6053 EL_CONVEYOR_BELT_4_LEFT
6056 int belt_nr = getBeltNrFromBeltElement(element);
6057 int belt_dir_nr = element - belt_base_element[belt_nr];
6059 return (belt_dir_nr % 3);
6062 int getBeltDirNrFromBeltSwitchElement(int element)
6064 static int belt_base_element[4] =
6066 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
6067 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
6068 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
6069 EL_CONVEYOR_BELT_4_SWITCH_LEFT
6072 int belt_nr = getBeltNrFromBeltSwitchElement(element);
6073 int belt_dir_nr = element - belt_base_element[belt_nr];
6075 return (belt_dir_nr % 3);
6078 int getBeltDirFromBeltElement(int element)
6080 static int belt_move_dir[3] =
6087 int belt_dir_nr = getBeltDirNrFromBeltElement(element);
6089 return belt_move_dir[belt_dir_nr];
6092 int getBeltDirFromBeltSwitchElement(int element)
6094 static int belt_move_dir[3] =
6101 int belt_dir_nr = getBeltDirNrFromBeltSwitchElement(element);
6103 return belt_move_dir[belt_dir_nr];
6106 int getBeltElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
6108 static int belt_base_element[4] =
6110 EL_CONVEYOR_BELT_1_LEFT,
6111 EL_CONVEYOR_BELT_2_LEFT,
6112 EL_CONVEYOR_BELT_3_LEFT,
6113 EL_CONVEYOR_BELT_4_LEFT
6116 return belt_base_element[belt_nr] + belt_dir_nr;
6119 int getBeltElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
6121 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
6123 return getBeltElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
6126 int getBeltSwitchElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
6128 static int belt_base_element[4] =
6130 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
6131 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
6132 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
6133 EL_CONVEYOR_BELT_4_SWITCH_LEFT
6136 return belt_base_element[belt_nr] + belt_dir_nr;
6139 int getBeltSwitchElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
6141 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
6143 return getBeltSwitchElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
6146 int getNumActivePlayers_EM()
6148 int num_players = 0;
6154 for (i = 0; i < MAX_PLAYERS; i++)
6155 if (tape.player_participates[i])
6161 int getGameFrameDelay_EM(int native_em_game_frame_delay)
6163 int game_frame_delay_value;
6165 game_frame_delay_value =
6166 (tape.playing && tape.fast_forward ? FfwdFrameDelay :
6167 GameFrameDelay == GAME_FRAME_DELAY ? native_em_game_frame_delay :
6170 if (tape.playing && tape.warp_forward && !tape.pausing)
6171 game_frame_delay_value = 0;
6173 return game_frame_delay_value;
6176 unsigned int InitRND(long seed)
6178 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
6179 return InitEngineRandom_EM(seed);
6180 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
6181 return InitEngineRandom_SP(seed);
6183 return InitEngineRandom_RND(seed);
6187 static struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
6188 static struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
6191 inline static int get_effective_element_EM(int tile, int frame_em)
6193 int element = object_mapping[tile].element_rnd;
6194 int action = object_mapping[tile].action;
6195 boolean is_backside = object_mapping[tile].is_backside;
6196 boolean action_removing = (action == ACTION_DIGGING ||
6197 action == ACTION_SNAPPING ||
6198 action == ACTION_COLLECTING);
6204 case Yacid_splash_eB:
6205 case Yacid_splash_wB:
6206 return (frame_em > 5 ? EL_EMPTY : element);
6212 else /* frame_em == 7 */
6216 case Yacid_splash_eB:
6217 case Yacid_splash_wB:
6220 case Yemerald_stone:
6223 case Ydiamond_stone:
6227 case Xdrip_stretchB:
6246 case Xsand_stonein_1:
6247 case Xsand_stonein_2:
6248 case Xsand_stonein_3:
6249 case Xsand_stonein_4:
6253 return (is_backside || action_removing ? EL_EMPTY : element);
6258 inline static boolean check_linear_animation_EM(int tile)
6262 case Xsand_stonesand_1:
6263 case Xsand_stonesand_quickout_1:
6264 case Xsand_sandstone_1:
6265 case Xsand_stonein_1:
6266 case Xsand_stoneout_1:
6291 inline static void set_crumbled_graphics_EM(struct GraphicInfo_EM *g_em,
6292 boolean has_crumbled_graphics,
6293 int crumbled, int sync_frame)
6295 /* if element can be crumbled, but certain action graphics are just empty
6296 space (like instantly snapping sand to empty space in 1 frame), do not
6297 treat these empty space graphics as crumbled graphics in EMC engine */
6298 if (crumbled == IMG_EMPTY_SPACE)
6299 has_crumbled_graphics = FALSE;
6301 if (has_crumbled_graphics)
6303 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
6304 int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
6305 g_crumbled->anim_delay,
6306 g_crumbled->anim_mode,
6307 g_crumbled->anim_start_frame,
6310 getGraphicSource(crumbled, frame_crumbled, &g_em->crumbled_bitmap,
6311 &g_em->crumbled_src_x, &g_em->crumbled_src_y);
6313 g_em->crumbled_border_size = graphic_info[crumbled].border_size;
6315 g_em->has_crumbled_graphics = TRUE;
6319 g_em->crumbled_bitmap = NULL;
6320 g_em->crumbled_src_x = 0;
6321 g_em->crumbled_src_y = 0;
6322 g_em->crumbled_border_size = 0;
6324 g_em->has_crumbled_graphics = FALSE;
6328 void ResetGfxAnimation_EM(int x, int y, int tile)
6333 void SetGfxAnimation_EM(struct GraphicInfo_EM *g_em,
6334 int tile, int frame_em, int x, int y)
6336 int action = object_mapping[tile].action;
6338 int direction = object_mapping[tile].direction;
6339 int effective_element = get_effective_element_EM(tile, frame_em);
6340 int graphic = (direction == MV_NONE ?
6341 el_act2img(effective_element, action) :
6342 el_act_dir2img(effective_element, action, direction));
6343 struct GraphicInfo *g = &graphic_info[graphic];
6346 boolean action_removing = (action == ACTION_DIGGING ||
6347 action == ACTION_SNAPPING ||
6348 action == ACTION_COLLECTING);
6349 boolean action_moving = (action == ACTION_FALLING ||
6350 action == ACTION_MOVING ||
6351 action == ACTION_PUSHING ||
6352 action == ACTION_EATING ||
6353 action == ACTION_FILLING ||
6354 action == ACTION_EMPTYING);
6355 boolean action_falling = (action == ACTION_FALLING ||
6356 action == ACTION_FILLING ||
6357 action == ACTION_EMPTYING);
6359 /* special case: graphic uses "2nd movement tile" and has defined
6360 7 frames for movement animation (or less) => use default graphic
6361 for last (8th) frame which ends the movement animation */
6362 if (g->double_movement && g->anim_frames < 8 && frame_em == 7)
6364 action = ACTION_DEFAULT; /* (keep action_* unchanged for now) */
6365 graphic = (direction == MV_NONE ?
6366 el_act2img(effective_element, action) :
6367 el_act_dir2img(effective_element, action, direction));
6369 g = &graphic_info[graphic];
6373 if (tile == Xsand_stonesand_1 ||
6374 tile == Xsand_stonesand_2 ||
6375 tile == Xsand_stonesand_3 ||
6376 tile == Xsand_stonesand_4)
6377 printf("::: 1: quicksand frame %d [%d]\n", GfxFrame[x][y], tile);
6381 if ((action_removing || check_linear_animation_EM(tile)) && frame_em == 0)
6385 // printf("::: resetting... [%d]\n", tile);
6388 if (action_removing || check_linear_animation_EM(tile))
6390 GfxFrame[x][y] = frame_em;
6392 // printf("::: resetting... [%d]\n", tile);
6395 else if (action_moving)
6397 boolean is_backside = object_mapping[tile].is_backside;
6401 int direction = object_mapping[tile].direction;
6402 int move_dir = (action_falling ? MV_DOWN : direction);
6407 /* !!! TEST !!! NEW !!! DOES NOT WORK RIGHT YET !!! */
6408 if (g->double_movement && frame_em == 0)
6412 // printf("::: resetting... [%d]\n", tile);
6416 if (move_dir == MV_LEFT)
6417 GfxFrame[x - 1][y] = GfxFrame[x][y];
6418 else if (move_dir == MV_RIGHT)
6419 GfxFrame[x + 1][y] = GfxFrame[x][y];
6420 else if (move_dir == MV_UP)
6421 GfxFrame[x][y - 1] = GfxFrame[x][y];
6422 else if (move_dir == MV_DOWN)
6423 GfxFrame[x][y + 1] = GfxFrame[x][y];
6430 /* special case: animation for Xsand_stonesand_quickout_1/2 twice as fast */
6431 if (tile == Xsand_stonesand_quickout_1 ||
6432 tile == Xsand_stonesand_quickout_2)
6437 if (tile == Xsand_stonesand_1 ||
6438 tile == Xsand_stonesand_2 ||
6439 tile == Xsand_stonesand_3 ||
6440 tile == Xsand_stonesand_4)
6441 printf("::: 2: quicksand frame %d [%d]\n", GfxFrame[x][y], tile);
6445 if (graphic_info[graphic].anim_global_sync)
6446 sync_frame = FrameCounter;
6447 else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY))
6448 sync_frame = GfxFrame[x][y];
6450 sync_frame = 0; /* playfield border (pseudo steel) */
6452 SetRandomAnimationValue(x, y);
6454 int frame = getAnimationFrame(g->anim_frames,
6457 g->anim_start_frame,
6460 g_em->unique_identifier =
6461 (graphic << 16) | ((frame % 8) << 12) | (g_em->width << 6) | g_em->height;
6465 void getGraphicSourceObjectExt_EM(struct GraphicInfo_EM *g_em,
6466 int tile, int frame_em, int x, int y)
6468 int action = object_mapping[tile].action;
6469 int direction = object_mapping[tile].direction;
6470 boolean is_backside = object_mapping[tile].is_backside;
6471 int effective_element = get_effective_element_EM(tile, frame_em);
6473 int effective_action = action;
6475 int effective_action = (frame_em < 7 ? action : ACTION_DEFAULT);
6477 int graphic = (direction == MV_NONE ?
6478 el_act2img(effective_element, effective_action) :
6479 el_act_dir2img(effective_element, effective_action,
6481 int crumbled = (direction == MV_NONE ?
6482 el_act2crm(effective_element, effective_action) :
6483 el_act_dir2crm(effective_element, effective_action,
6485 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
6486 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
6487 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
6488 struct GraphicInfo *g = &graphic_info[graphic];
6490 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
6494 /* special case: graphic uses "2nd movement tile" and has defined
6495 7 frames for movement animation (or less) => use default graphic
6496 for last (8th) frame which ends the movement animation */
6497 if (g->double_movement && g->anim_frames < 8 && frame_em == 7)
6499 effective_action = ACTION_DEFAULT;
6500 graphic = (direction == MV_NONE ?
6501 el_act2img(effective_element, effective_action) :
6502 el_act_dir2img(effective_element, effective_action,
6504 crumbled = (direction == MV_NONE ?
6505 el_act2crm(effective_element, effective_action) :
6506 el_act_dir2crm(effective_element, effective_action,
6509 g = &graphic_info[graphic];
6519 if (frame_em == 0) /* reset animation frame for certain elements */
6521 if (check_linear_animation_EM(tile))
6526 if (graphic_info[graphic].anim_global_sync)
6527 sync_frame = FrameCounter;
6528 else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY))
6529 sync_frame = GfxFrame[x][y];
6531 sync_frame = 0; /* playfield border (pseudo steel) */
6533 SetRandomAnimationValue(x, y);
6538 int xxx_sync_frame = (i == Xdrip_stretch ? 7 :
6539 i == Xdrip_stretchB ? 7 :
6540 i == Ydrip_s2 ? j + 8 :
6541 i == Ydrip_s2B ? j + 8 :
6550 i == Xfake_acid_1 ? 0 :
6551 i == Xfake_acid_2 ? 10 :
6552 i == Xfake_acid_3 ? 20 :
6553 i == Xfake_acid_4 ? 30 :
6554 i == Xfake_acid_5 ? 40 :
6555 i == Xfake_acid_6 ? 50 :
6556 i == Xfake_acid_7 ? 60 :
6557 i == Xfake_acid_8 ? 70 :
6559 i == Xball_2B ? j + 8 :
6560 i == Yball_eat ? j + 1 :
6561 i == Ykey_1_eat ? j + 1 :
6562 i == Ykey_2_eat ? j + 1 :
6563 i == Ykey_3_eat ? j + 1 :
6564 i == Ykey_4_eat ? j + 1 :
6565 i == Ykey_5_eat ? j + 1 :
6566 i == Ykey_6_eat ? j + 1 :
6567 i == Ykey_7_eat ? j + 1 :
6568 i == Ykey_8_eat ? j + 1 :
6569 i == Ylenses_eat ? j + 1 :
6570 i == Ymagnify_eat ? j + 1 :
6571 i == Ygrass_eat ? j + 1 :
6572 i == Ydirt_eat ? j + 1 :
6573 i == Xamoeba_1 ? 0 :
6574 i == Xamoeba_2 ? 1 :
6575 i == Xamoeba_3 ? 2 :
6576 i == Xamoeba_4 ? 3 :
6577 i == Xamoeba_5 ? 0 :
6578 i == Xamoeba_6 ? 1 :
6579 i == Xamoeba_7 ? 2 :
6580 i == Xamoeba_8 ? 3 :
6581 i == Xexit_2 ? j + 8 :
6582 i == Xexit_3 ? j + 16 :
6583 i == Xdynamite_1 ? 0 :
6584 i == Xdynamite_2 ? 8 :
6585 i == Xdynamite_3 ? 16 :
6586 i == Xdynamite_4 ? 24 :
6587 i == Xsand_stonein_1 ? j + 1 :
6588 i == Xsand_stonein_2 ? j + 9 :
6589 i == Xsand_stonein_3 ? j + 17 :
6590 i == Xsand_stonein_4 ? j + 25 :
6591 i == Xsand_stoneout_1 && j == 0 ? 0 :
6592 i == Xsand_stoneout_1 && j == 1 ? 0 :
6593 i == Xsand_stoneout_1 && j == 2 ? 1 :
6594 i == Xsand_stoneout_1 && j == 3 ? 2 :
6595 i == Xsand_stoneout_1 && j == 4 ? 2 :
6596 i == Xsand_stoneout_1 && j == 5 ? 3 :
6597 i == Xsand_stoneout_1 && j == 6 ? 4 :
6598 i == Xsand_stoneout_1 && j == 7 ? 4 :
6599 i == Xsand_stoneout_2 && j == 0 ? 5 :
6600 i == Xsand_stoneout_2 && j == 1 ? 6 :
6601 i == Xsand_stoneout_2 && j == 2 ? 7 :
6602 i == Xsand_stoneout_2 && j == 3 ? 8 :
6603 i == Xsand_stoneout_2 && j == 4 ? 9 :
6604 i == Xsand_stoneout_2 && j == 5 ? 11 :
6605 i == Xsand_stoneout_2 && j == 6 ? 13 :
6606 i == Xsand_stoneout_2 && j == 7 ? 15 :
6607 i == Xboom_bug && j == 1 ? 2 :
6608 i == Xboom_bug && j == 2 ? 2 :
6609 i == Xboom_bug && j == 3 ? 4 :
6610 i == Xboom_bug && j == 4 ? 4 :
6611 i == Xboom_bug && j == 5 ? 2 :
6612 i == Xboom_bug && j == 6 ? 2 :
6613 i == Xboom_bug && j == 7 ? 0 :
6614 i == Xboom_bomb && j == 1 ? 2 :
6615 i == Xboom_bomb && j == 2 ? 2 :
6616 i == Xboom_bomb && j == 3 ? 4 :
6617 i == Xboom_bomb && j == 4 ? 4 :
6618 i == Xboom_bomb && j == 5 ? 2 :
6619 i == Xboom_bomb && j == 6 ? 2 :
6620 i == Xboom_bomb && j == 7 ? 0 :
6621 i == Xboom_android && j == 7 ? 6 :
6622 i == Xboom_1 && j == 1 ? 2 :
6623 i == Xboom_1 && j == 2 ? 2 :
6624 i == Xboom_1 && j == 3 ? 4 :
6625 i == Xboom_1 && j == 4 ? 4 :
6626 i == Xboom_1 && j == 5 ? 6 :
6627 i == Xboom_1 && j == 6 ? 6 :
6628 i == Xboom_1 && j == 7 ? 8 :
6629 i == Xboom_2 && j == 0 ? 8 :
6630 i == Xboom_2 && j == 1 ? 8 :
6631 i == Xboom_2 && j == 2 ? 10 :
6632 i == Xboom_2 && j == 3 ? 10 :
6633 i == Xboom_2 && j == 4 ? 10 :
6634 i == Xboom_2 && j == 5 ? 12 :
6635 i == Xboom_2 && j == 6 ? 12 :
6636 i == Xboom_2 && j == 7 ? 12 :
6638 special_animation && j == 4 ? 3 :
6639 effective_action != action ? 0 :
6645 int xxx_effective_action;
6646 int xxx_has_action_graphics;
6649 int element = object_mapping[i].element_rnd;
6650 int action = object_mapping[i].action;
6651 int direction = object_mapping[i].direction;
6652 boolean is_backside = object_mapping[i].is_backside;
6654 boolean action_removing = (action == ACTION_DIGGING ||
6655 action == ACTION_SNAPPING ||
6656 action == ACTION_COLLECTING);
6658 boolean action_exploding = ((action == ACTION_EXPLODING ||
6659 action == ACTION_SMASHED_BY_ROCK ||
6660 action == ACTION_SMASHED_BY_SPRING) &&
6661 element != EL_DIAMOND);
6662 boolean action_active = (action == ACTION_ACTIVE);
6663 boolean action_other = (action == ACTION_OTHER);
6667 int effective_element = get_effective_element_EM(i, j);
6669 int effective_element = (j > 5 && i == Yacid_splash_eB ? EL_EMPTY :
6670 j > 5 && i == Yacid_splash_wB ? EL_EMPTY :
6672 i == Xdrip_stretch ? element :
6673 i == Xdrip_stretchB ? element :
6674 i == Ydrip_s1 ? element :
6675 i == Ydrip_s1B ? element :
6676 i == Xball_1B ? element :
6677 i == Xball_2 ? element :
6678 i == Xball_2B ? element :
6679 i == Yball_eat ? element :
6680 i == Ykey_1_eat ? element :
6681 i == Ykey_2_eat ? element :
6682 i == Ykey_3_eat ? element :
6683 i == Ykey_4_eat ? element :
6684 i == Ykey_5_eat ? element :
6685 i == Ykey_6_eat ? element :
6686 i == Ykey_7_eat ? element :
6687 i == Ykey_8_eat ? element :
6688 i == Ylenses_eat ? element :
6689 i == Ymagnify_eat ? element :
6690 i == Ygrass_eat ? element :
6691 i == Ydirt_eat ? element :
6692 i == Yemerald_stone ? EL_EMERALD :
6693 i == Ydiamond_stone ? EL_ROCK :
6694 i == Xsand_stonein_1 ? element :
6695 i == Xsand_stonein_2 ? element :
6696 i == Xsand_stonein_3 ? element :
6697 i == Xsand_stonein_4 ? element :
6698 is_backside ? EL_EMPTY :
6699 action_removing ? EL_EMPTY :
6702 int effective_action = (j < 7 ? action :
6703 i == Xdrip_stretch ? action :
6704 i == Xdrip_stretchB ? action :
6705 i == Ydrip_s1 ? action :
6706 i == Ydrip_s1B ? action :
6707 i == Xball_1B ? action :
6708 i == Xball_2 ? action :
6709 i == Xball_2B ? action :
6710 i == Yball_eat ? action :
6711 i == Ykey_1_eat ? action :
6712 i == Ykey_2_eat ? action :
6713 i == Ykey_3_eat ? action :
6714 i == Ykey_4_eat ? action :
6715 i == Ykey_5_eat ? action :
6716 i == Ykey_6_eat ? action :
6717 i == Ykey_7_eat ? action :
6718 i == Ykey_8_eat ? action :
6719 i == Ylenses_eat ? action :
6720 i == Ymagnify_eat ? action :
6721 i == Ygrass_eat ? action :
6722 i == Ydirt_eat ? action :
6723 i == Xsand_stonein_1 ? action :
6724 i == Xsand_stonein_2 ? action :
6725 i == Xsand_stonein_3 ? action :
6726 i == Xsand_stonein_4 ? action :
6727 i == Xsand_stoneout_1 ? action :
6728 i == Xsand_stoneout_2 ? action :
6729 i == Xboom_android ? ACTION_EXPLODING :
6730 action_exploding ? ACTION_EXPLODING :
6731 action_active ? action :
6732 action_other ? action :
6734 int graphic = (el_act_dir2img(effective_element, effective_action,
6736 int crumbled = (el_act_dir2crm(effective_element, effective_action,
6738 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
6739 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
6740 boolean has_action_graphics = (graphic != base_graphic);
6741 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
6742 struct GraphicInfo *g = &graphic_info[graphic];
6744 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
6746 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
6749 /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
6750 boolean special_animation = (action != ACTION_DEFAULT &&
6751 g->anim_frames == 3 &&
6752 g->anim_delay == 2 &&
6753 g->anim_mode & ANIM_LINEAR);
6754 xxx_sync_frame = (i == Xdrip_stretch ? 7 :
6755 i == Xdrip_stretchB ? 7 :
6756 i == Ydrip_s2 ? j + 8 :
6757 i == Ydrip_s2B ? j + 8 :
6766 i == Xfake_acid_1 ? 0 :
6767 i == Xfake_acid_2 ? 10 :
6768 i == Xfake_acid_3 ? 20 :
6769 i == Xfake_acid_4 ? 30 :
6770 i == Xfake_acid_5 ? 40 :
6771 i == Xfake_acid_6 ? 50 :
6772 i == Xfake_acid_7 ? 60 :
6773 i == Xfake_acid_8 ? 70 :
6775 i == Xball_2B ? j + 8 :
6776 i == Yball_eat ? j + 1 :
6777 i == Ykey_1_eat ? j + 1 :
6778 i == Ykey_2_eat ? j + 1 :
6779 i == Ykey_3_eat ? j + 1 :
6780 i == Ykey_4_eat ? j + 1 :
6781 i == Ykey_5_eat ? j + 1 :
6782 i == Ykey_6_eat ? j + 1 :
6783 i == Ykey_7_eat ? j + 1 :
6784 i == Ykey_8_eat ? j + 1 :
6785 i == Ylenses_eat ? j + 1 :
6786 i == Ymagnify_eat ? j + 1 :
6787 i == Ygrass_eat ? j + 1 :
6788 i == Ydirt_eat ? j + 1 :
6789 i == Xamoeba_1 ? 0 :
6790 i == Xamoeba_2 ? 1 :
6791 i == Xamoeba_3 ? 2 :
6792 i == Xamoeba_4 ? 3 :
6793 i == Xamoeba_5 ? 0 :
6794 i == Xamoeba_6 ? 1 :
6795 i == Xamoeba_7 ? 2 :
6796 i == Xamoeba_8 ? 3 :
6797 i == Xexit_2 ? j + 8 :
6798 i == Xexit_3 ? j + 16 :
6799 i == Xdynamite_1 ? 0 :
6800 i == Xdynamite_2 ? 8 :
6801 i == Xdynamite_3 ? 16 :
6802 i == Xdynamite_4 ? 24 :
6803 i == Xsand_stonein_1 ? j + 1 :
6804 i == Xsand_stonein_2 ? j + 9 :
6805 i == Xsand_stonein_3 ? j + 17 :
6806 i == Xsand_stonein_4 ? j + 25 :
6807 i == Xsand_stoneout_1 && j == 0 ? 0 :
6808 i == Xsand_stoneout_1 && j == 1 ? 0 :
6809 i == Xsand_stoneout_1 && j == 2 ? 1 :
6810 i == Xsand_stoneout_1 && j == 3 ? 2 :
6811 i == Xsand_stoneout_1 && j == 4 ? 2 :
6812 i == Xsand_stoneout_1 && j == 5 ? 3 :
6813 i == Xsand_stoneout_1 && j == 6 ? 4 :
6814 i == Xsand_stoneout_1 && j == 7 ? 4 :
6815 i == Xsand_stoneout_2 && j == 0 ? 5 :
6816 i == Xsand_stoneout_2 && j == 1 ? 6 :
6817 i == Xsand_stoneout_2 && j == 2 ? 7 :
6818 i == Xsand_stoneout_2 && j == 3 ? 8 :
6819 i == Xsand_stoneout_2 && j == 4 ? 9 :
6820 i == Xsand_stoneout_2 && j == 5 ? 11 :
6821 i == Xsand_stoneout_2 && j == 6 ? 13 :
6822 i == Xsand_stoneout_2 && j == 7 ? 15 :
6823 i == Xboom_bug && j == 1 ? 2 :
6824 i == Xboom_bug && j == 2 ? 2 :
6825 i == Xboom_bug && j == 3 ? 4 :
6826 i == Xboom_bug && j == 4 ? 4 :
6827 i == Xboom_bug && j == 5 ? 2 :
6828 i == Xboom_bug && j == 6 ? 2 :
6829 i == Xboom_bug && j == 7 ? 0 :
6830 i == Xboom_bomb && j == 1 ? 2 :
6831 i == Xboom_bomb && j == 2 ? 2 :
6832 i == Xboom_bomb && j == 3 ? 4 :
6833 i == Xboom_bomb && j == 4 ? 4 :
6834 i == Xboom_bomb && j == 5 ? 2 :
6835 i == Xboom_bomb && j == 6 ? 2 :
6836 i == Xboom_bomb && j == 7 ? 0 :
6837 i == Xboom_android && j == 7 ? 6 :
6838 i == Xboom_1 && j == 1 ? 2 :
6839 i == Xboom_1 && j == 2 ? 2 :
6840 i == Xboom_1 && j == 3 ? 4 :
6841 i == Xboom_1 && j == 4 ? 4 :
6842 i == Xboom_1 && j == 5 ? 6 :
6843 i == Xboom_1 && j == 6 ? 6 :
6844 i == Xboom_1 && j == 7 ? 8 :
6845 i == Xboom_2 && j == 0 ? 8 :
6846 i == Xboom_2 && j == 1 ? 8 :
6847 i == Xboom_2 && j == 2 ? 10 :
6848 i == Xboom_2 && j == 3 ? 10 :
6849 i == Xboom_2 && j == 4 ? 10 :
6850 i == Xboom_2 && j == 5 ? 12 :
6851 i == Xboom_2 && j == 6 ? 12 :
6852 i == Xboom_2 && j == 7 ? 12 :
6853 special_animation && j == 4 ? 3 :
6854 effective_action != action ? 0 :
6857 xxx_effective_action = effective_action;
6858 xxx_has_action_graphics = has_action_graphics;
6863 int frame = getAnimationFrame(g->anim_frames,
6866 g->anim_start_frame,
6880 int old_src_x = g_em->src_x;
6881 int old_src_y = g_em->src_y;
6885 getGraphicSourceExt(graphic, frame, &g_em->bitmap, &g_em->src_x, &g_em->src_y,
6886 g->double_movement && is_backside);
6888 getGraphicSourceExt(graphic, frame, &g_em->bitmap,
6889 &g_em->src_x, &g_em->src_y, FALSE);
6900 if (graphic == IMG_BUG_MOVING_RIGHT)
6901 printf("::: %d, %d, %d: %d, %d [%d, %d -> %d, %d]\n", graphic, x, y,
6902 g->double_movement, is_backside,
6903 old_src_x, old_src_y, g_em->src_x, g_em->src_y);
6911 g_em->src_offset_x = 0;
6912 g_em->src_offset_y = 0;
6913 g_em->dst_offset_x = 0;
6914 g_em->dst_offset_y = 0;
6915 g_em->width = TILEX;
6916 g_em->height = TILEY;
6918 g_em->preserve_background = FALSE;
6921 /* (updating the "crumbled" graphic definitions is probably not really needed,
6922 as animations for crumbled graphics can't be longer than one EMC cycle) */
6924 set_crumbled_graphics_EM(g_em, has_crumbled_graphics, crumbled,
6929 g_em->crumbled_bitmap = NULL;
6930 g_em->crumbled_src_x = 0;
6931 g_em->crumbled_src_y = 0;
6933 g_em->has_crumbled_graphics = FALSE;
6935 if (has_crumbled_graphics && crumbled != IMG_EMPTY_SPACE)
6937 int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
6938 g_crumbled->anim_delay,
6939 g_crumbled->anim_mode,
6940 g_crumbled->anim_start_frame,
6943 getGraphicSource(crumbled, frame_crumbled, &g_em->crumbled_bitmap,
6944 &g_em->crumbled_src_x, &g_em->crumbled_src_y);
6946 g_em->has_crumbled_graphics = TRUE;
6952 int effective_action = xxx_effective_action;
6953 int has_action_graphics = xxx_has_action_graphics;
6955 if ((!g->double_movement && (effective_action == ACTION_FALLING ||
6956 effective_action == ACTION_MOVING ||
6957 effective_action == ACTION_PUSHING ||
6958 effective_action == ACTION_EATING)) ||
6959 (!has_action_graphics && (effective_action == ACTION_FILLING ||
6960 effective_action == ACTION_EMPTYING)))
6963 (effective_action == ACTION_FALLING ||
6964 effective_action == ACTION_FILLING ||
6965 effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
6966 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
6967 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? 1 : 0);
6968 int num_steps = (i == Ydrip_s1 ? 16 :
6969 i == Ydrip_s1B ? 16 :
6970 i == Ydrip_s2 ? 16 :
6971 i == Ydrip_s2B ? 16 :
6972 i == Xsand_stonein_1 ? 32 :
6973 i == Xsand_stonein_2 ? 32 :
6974 i == Xsand_stonein_3 ? 32 :
6975 i == Xsand_stonein_4 ? 32 :
6976 i == Xsand_stoneout_1 ? 16 :
6977 i == Xsand_stoneout_2 ? 16 : 8);
6978 int cx = ABS(dx) * (TILEX / num_steps);
6979 int cy = ABS(dy) * (TILEY / num_steps);
6980 int step_frame = (i == Ydrip_s2 ? j + 8 :
6981 i == Ydrip_s2B ? j + 8 :
6982 i == Xsand_stonein_2 ? j + 8 :
6983 i == Xsand_stonein_3 ? j + 16 :
6984 i == Xsand_stonein_4 ? j + 24 :
6985 i == Xsand_stoneout_2 ? j + 8 : j) + 1;
6986 int step = (is_backside ? step_frame : num_steps - step_frame);
6988 if (is_backside) /* tile where movement starts */
6990 if (dx < 0 || dy < 0)
6992 g_em->src_offset_x = cx * step;
6993 g_em->src_offset_y = cy * step;
6997 g_em->dst_offset_x = cx * step;
6998 g_em->dst_offset_y = cy * step;
7001 else /* tile where movement ends */
7003 if (dx < 0 || dy < 0)
7005 g_em->dst_offset_x = cx * step;
7006 g_em->dst_offset_y = cy * step;
7010 g_em->src_offset_x = cx * step;
7011 g_em->src_offset_y = cy * step;
7015 g_em->width = TILEX - cx * step;
7016 g_em->height = TILEY - cy * step;
7019 /* create unique graphic identifier to decide if tile must be redrawn */
7020 /* bit 31 - 16 (16 bit): EM style graphic
7021 bit 15 - 12 ( 4 bit): EM style frame
7022 bit 11 - 6 ( 6 bit): graphic width
7023 bit 5 - 0 ( 6 bit): graphic height */
7024 g_em->unique_identifier =
7025 (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
7031 void getGraphicSourcePlayerExt_EM(struct GraphicInfo_EM *g_em,
7032 int player_nr, int anim, int frame_em)
7034 int element = player_mapping[player_nr][anim].element_rnd;
7035 int action = player_mapping[player_nr][anim].action;
7036 int direction = player_mapping[player_nr][anim].direction;
7037 int graphic = (direction == MV_NONE ?
7038 el_act2img(element, action) :
7039 el_act_dir2img(element, action, direction));
7040 struct GraphicInfo *g = &graphic_info[graphic];
7043 InitPlayerGfxAnimation(&stored_player[player_nr], action, direction);
7045 stored_player[player_nr].StepFrame = frame_em;
7047 sync_frame = stored_player[player_nr].Frame;
7049 int frame = getAnimationFrame(g->anim_frames,
7052 g->anim_start_frame,
7055 getGraphicSourceExt(graphic, frame, &g_em->bitmap,
7056 &g_em->src_x, &g_em->src_y, FALSE);
7059 printf("::: %d: %d, %d [%d]\n",
7061 stored_player[player_nr].Frame,
7062 stored_player[player_nr].StepFrame,
7067 void InitGraphicInfo_EM(void)
7070 struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
7071 struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
7076 int num_em_gfx_errors = 0;
7078 if (graphic_info_em_object[0][0].bitmap == NULL)
7080 /* EM graphics not yet initialized in em_open_all() */
7085 printf("::: [4 errors can be ignored (1 x 'bomb', 3 x 'em_dynamite']\n");
7088 /* always start with reliable default values */
7089 for (i = 0; i < TILE_MAX; i++)
7091 object_mapping[i].element_rnd = EL_UNKNOWN;
7092 object_mapping[i].is_backside = FALSE;
7093 object_mapping[i].action = ACTION_DEFAULT;
7094 object_mapping[i].direction = MV_NONE;
7097 /* always start with reliable default values */
7098 for (p = 0; p < MAX_PLAYERS; p++)
7100 for (i = 0; i < SPR_MAX; i++)
7102 player_mapping[p][i].element_rnd = EL_UNKNOWN;
7103 player_mapping[p][i].action = ACTION_DEFAULT;
7104 player_mapping[p][i].direction = MV_NONE;
7108 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
7110 int e = em_object_mapping_list[i].element_em;
7112 object_mapping[e].element_rnd = em_object_mapping_list[i].element_rnd;
7113 object_mapping[e].is_backside = em_object_mapping_list[i].is_backside;
7115 if (em_object_mapping_list[i].action != -1)
7116 object_mapping[e].action = em_object_mapping_list[i].action;
7118 if (em_object_mapping_list[i].direction != -1)
7119 object_mapping[e].direction =
7120 MV_DIR_FROM_BIT(em_object_mapping_list[i].direction);
7123 for (i = 0; em_player_mapping_list[i].action_em != -1; i++)
7125 int a = em_player_mapping_list[i].action_em;
7126 int p = em_player_mapping_list[i].player_nr;
7128 player_mapping[p][a].element_rnd = em_player_mapping_list[i].element_rnd;
7130 if (em_player_mapping_list[i].action != -1)
7131 player_mapping[p][a].action = em_player_mapping_list[i].action;
7133 if (em_player_mapping_list[i].direction != -1)
7134 player_mapping[p][a].direction =
7135 MV_DIR_FROM_BIT(em_player_mapping_list[i].direction);
7138 for (i = 0; i < TILE_MAX; i++)
7140 int element = object_mapping[i].element_rnd;
7141 int action = object_mapping[i].action;
7142 int direction = object_mapping[i].direction;
7143 boolean is_backside = object_mapping[i].is_backside;
7145 boolean action_removing = (action == ACTION_DIGGING ||
7146 action == ACTION_SNAPPING ||
7147 action == ACTION_COLLECTING);
7149 boolean action_exploding = ((action == ACTION_EXPLODING ||
7150 action == ACTION_SMASHED_BY_ROCK ||
7151 action == ACTION_SMASHED_BY_SPRING) &&
7152 element != EL_DIAMOND);
7153 boolean action_active = (action == ACTION_ACTIVE);
7154 boolean action_other = (action == ACTION_OTHER);
7156 for (j = 0; j < 8; j++)
7159 int effective_element = get_effective_element_EM(i, j);
7161 int effective_element = (j > 5 && i == Yacid_splash_eB ? EL_EMPTY :
7162 j > 5 && i == Yacid_splash_wB ? EL_EMPTY :
7164 i == Xdrip_stretch ? element :
7165 i == Xdrip_stretchB ? element :
7166 i == Ydrip_s1 ? element :
7167 i == Ydrip_s1B ? element :
7168 i == Xball_1B ? element :
7169 i == Xball_2 ? element :
7170 i == Xball_2B ? element :
7171 i == Yball_eat ? element :
7172 i == Ykey_1_eat ? element :
7173 i == Ykey_2_eat ? element :
7174 i == Ykey_3_eat ? element :
7175 i == Ykey_4_eat ? element :
7176 i == Ykey_5_eat ? element :
7177 i == Ykey_6_eat ? element :
7178 i == Ykey_7_eat ? element :
7179 i == Ykey_8_eat ? element :
7180 i == Ylenses_eat ? element :
7181 i == Ymagnify_eat ? element :
7182 i == Ygrass_eat ? element :
7183 i == Ydirt_eat ? element :
7184 i == Yemerald_stone ? EL_EMERALD :
7185 i == Ydiamond_stone ? EL_ROCK :
7186 i == Xsand_stonein_1 ? element :
7187 i == Xsand_stonein_2 ? element :
7188 i == Xsand_stonein_3 ? element :
7189 i == Xsand_stonein_4 ? element :
7190 is_backside ? EL_EMPTY :
7191 action_removing ? EL_EMPTY :
7194 int effective_action = (j < 7 ? action :
7195 i == Xdrip_stretch ? action :
7196 i == Xdrip_stretchB ? action :
7197 i == Ydrip_s1 ? action :
7198 i == Ydrip_s1B ? action :
7199 i == Xball_1B ? action :
7200 i == Xball_2 ? action :
7201 i == Xball_2B ? action :
7202 i == Yball_eat ? action :
7203 i == Ykey_1_eat ? action :
7204 i == Ykey_2_eat ? action :
7205 i == Ykey_3_eat ? action :
7206 i == Ykey_4_eat ? action :
7207 i == Ykey_5_eat ? action :
7208 i == Ykey_6_eat ? action :
7209 i == Ykey_7_eat ? action :
7210 i == Ykey_8_eat ? action :
7211 i == Ylenses_eat ? action :
7212 i == Ymagnify_eat ? action :
7213 i == Ygrass_eat ? action :
7214 i == Ydirt_eat ? action :
7215 i == Xsand_stonein_1 ? action :
7216 i == Xsand_stonein_2 ? action :
7217 i == Xsand_stonein_3 ? action :
7218 i == Xsand_stonein_4 ? action :
7219 i == Xsand_stoneout_1 ? action :
7220 i == Xsand_stoneout_2 ? action :
7221 i == Xboom_android ? ACTION_EXPLODING :
7222 action_exploding ? ACTION_EXPLODING :
7223 action_active ? action :
7224 action_other ? action :
7226 int graphic = (el_act_dir2img(effective_element, effective_action,
7228 int crumbled = (el_act_dir2crm(effective_element, effective_action,
7230 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
7231 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
7232 boolean has_action_graphics = (graphic != base_graphic);
7233 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
7234 struct GraphicInfo *g = &graphic_info[graphic];
7236 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
7238 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
7241 /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
7242 boolean special_animation = (action != ACTION_DEFAULT &&
7243 g->anim_frames == 3 &&
7244 g->anim_delay == 2 &&
7245 g->anim_mode & ANIM_LINEAR);
7246 int sync_frame = (i == Xdrip_stretch ? 7 :
7247 i == Xdrip_stretchB ? 7 :
7248 i == Ydrip_s2 ? j + 8 :
7249 i == Ydrip_s2B ? j + 8 :
7258 i == Xfake_acid_1 ? 0 :
7259 i == Xfake_acid_2 ? 10 :
7260 i == Xfake_acid_3 ? 20 :
7261 i == Xfake_acid_4 ? 30 :
7262 i == Xfake_acid_5 ? 40 :
7263 i == Xfake_acid_6 ? 50 :
7264 i == Xfake_acid_7 ? 60 :
7265 i == Xfake_acid_8 ? 70 :
7267 i == Xball_2B ? j + 8 :
7268 i == Yball_eat ? j + 1 :
7269 i == Ykey_1_eat ? j + 1 :
7270 i == Ykey_2_eat ? j + 1 :
7271 i == Ykey_3_eat ? j + 1 :
7272 i == Ykey_4_eat ? j + 1 :
7273 i == Ykey_5_eat ? j + 1 :
7274 i == Ykey_6_eat ? j + 1 :
7275 i == Ykey_7_eat ? j + 1 :
7276 i == Ykey_8_eat ? j + 1 :
7277 i == Ylenses_eat ? j + 1 :
7278 i == Ymagnify_eat ? j + 1 :
7279 i == Ygrass_eat ? j + 1 :
7280 i == Ydirt_eat ? j + 1 :
7281 i == Xamoeba_1 ? 0 :
7282 i == Xamoeba_2 ? 1 :
7283 i == Xamoeba_3 ? 2 :
7284 i == Xamoeba_4 ? 3 :
7285 i == Xamoeba_5 ? 0 :
7286 i == Xamoeba_6 ? 1 :
7287 i == Xamoeba_7 ? 2 :
7288 i == Xamoeba_8 ? 3 :
7289 i == Xexit_2 ? j + 8 :
7290 i == Xexit_3 ? j + 16 :
7291 i == Xdynamite_1 ? 0 :
7292 i == Xdynamite_2 ? 8 :
7293 i == Xdynamite_3 ? 16 :
7294 i == Xdynamite_4 ? 24 :
7295 i == Xsand_stonein_1 ? j + 1 :
7296 i == Xsand_stonein_2 ? j + 9 :
7297 i == Xsand_stonein_3 ? j + 17 :
7298 i == Xsand_stonein_4 ? j + 25 :
7299 i == Xsand_stoneout_1 && j == 0 ? 0 :
7300 i == Xsand_stoneout_1 && j == 1 ? 0 :
7301 i == Xsand_stoneout_1 && j == 2 ? 1 :
7302 i == Xsand_stoneout_1 && j == 3 ? 2 :
7303 i == Xsand_stoneout_1 && j == 4 ? 2 :
7304 i == Xsand_stoneout_1 && j == 5 ? 3 :
7305 i == Xsand_stoneout_1 && j == 6 ? 4 :
7306 i == Xsand_stoneout_1 && j == 7 ? 4 :
7307 i == Xsand_stoneout_2 && j == 0 ? 5 :
7308 i == Xsand_stoneout_2 && j == 1 ? 6 :
7309 i == Xsand_stoneout_2 && j == 2 ? 7 :
7310 i == Xsand_stoneout_2 && j == 3 ? 8 :
7311 i == Xsand_stoneout_2 && j == 4 ? 9 :
7312 i == Xsand_stoneout_2 && j == 5 ? 11 :
7313 i == Xsand_stoneout_2 && j == 6 ? 13 :
7314 i == Xsand_stoneout_2 && j == 7 ? 15 :
7315 i == Xboom_bug && j == 1 ? 2 :
7316 i == Xboom_bug && j == 2 ? 2 :
7317 i == Xboom_bug && j == 3 ? 4 :
7318 i == Xboom_bug && j == 4 ? 4 :
7319 i == Xboom_bug && j == 5 ? 2 :
7320 i == Xboom_bug && j == 6 ? 2 :
7321 i == Xboom_bug && j == 7 ? 0 :
7322 i == Xboom_bomb && j == 1 ? 2 :
7323 i == Xboom_bomb && j == 2 ? 2 :
7324 i == Xboom_bomb && j == 3 ? 4 :
7325 i == Xboom_bomb && j == 4 ? 4 :
7326 i == Xboom_bomb && j == 5 ? 2 :
7327 i == Xboom_bomb && j == 6 ? 2 :
7328 i == Xboom_bomb && j == 7 ? 0 :
7329 i == Xboom_android && j == 7 ? 6 :
7330 i == Xboom_1 && j == 1 ? 2 :
7331 i == Xboom_1 && j == 2 ? 2 :
7332 i == Xboom_1 && j == 3 ? 4 :
7333 i == Xboom_1 && j == 4 ? 4 :
7334 i == Xboom_1 && j == 5 ? 6 :
7335 i == Xboom_1 && j == 6 ? 6 :
7336 i == Xboom_1 && j == 7 ? 8 :
7337 i == Xboom_2 && j == 0 ? 8 :
7338 i == Xboom_2 && j == 1 ? 8 :
7339 i == Xboom_2 && j == 2 ? 10 :
7340 i == Xboom_2 && j == 3 ? 10 :
7341 i == Xboom_2 && j == 4 ? 10 :
7342 i == Xboom_2 && j == 5 ? 12 :
7343 i == Xboom_2 && j == 6 ? 12 :
7344 i == Xboom_2 && j == 7 ? 12 :
7345 special_animation && j == 4 ? 3 :
7346 effective_action != action ? 0 :
7350 Bitmap *debug_bitmap = g_em->bitmap;
7351 int debug_src_x = g_em->src_x;
7352 int debug_src_y = g_em->src_y;
7355 int frame = getAnimationFrame(g->anim_frames,
7358 g->anim_start_frame,
7361 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y,
7362 g->double_movement && is_backside);
7364 g_em->bitmap = src_bitmap;
7365 g_em->src_x = src_x;
7366 g_em->src_y = src_y;
7367 g_em->src_offset_x = 0;
7368 g_em->src_offset_y = 0;
7369 g_em->dst_offset_x = 0;
7370 g_em->dst_offset_y = 0;
7371 g_em->width = TILEX;
7372 g_em->height = TILEY;
7374 g_em->preserve_background = FALSE;
7377 set_crumbled_graphics_EM(g_em, has_crumbled_graphics, crumbled,
7382 g_em->crumbled_bitmap = NULL;
7383 g_em->crumbled_src_x = 0;
7384 g_em->crumbled_src_y = 0;
7385 g_em->crumbled_border_size = 0;
7387 g_em->has_crumbled_graphics = FALSE;
7390 if (has_crumbled_graphics && crumbled == IMG_EMPTY_SPACE)
7391 printf("::: empty crumbled: %d [%s], %d, %d\n",
7392 effective_element, element_info[effective_element].token_name,
7393 effective_action, direction);
7396 /* if element can be crumbled, but certain action graphics are just empty
7397 space (like instantly snapping sand to empty space in 1 frame), do not
7398 treat these empty space graphics as crumbled graphics in EMC engine */
7399 if (has_crumbled_graphics && crumbled != IMG_EMPTY_SPACE)
7401 int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
7402 g_crumbled->anim_delay,
7403 g_crumbled->anim_mode,
7404 g_crumbled->anim_start_frame,
7407 getGraphicSource(crumbled, frame_crumbled, &src_bitmap, &src_x, &src_y);
7409 g_em->has_crumbled_graphics = TRUE;
7410 g_em->crumbled_bitmap = src_bitmap;
7411 g_em->crumbled_src_x = src_x;
7412 g_em->crumbled_src_y = src_y;
7413 g_em->crumbled_border_size = graphic_info[crumbled].border_size;
7417 if (g_em == &graphic_info_em_object[207][0])
7418 printf("... %d, %d [%d, %d, %d, %d] [%d, %d, %d, %d, %d, %d => %d]\n",
7419 graphic_info_em_object[207][0].crumbled_src_x,
7420 graphic_info_em_object[207][0].crumbled_src_y,
7422 crumbled, frame, src_x, src_y,
7427 g->anim_start_frame,
7429 gfx.anim_random_frame,
7434 printf("::: EMC tile %d is crumbled\n", i);
7440 if (element == EL_ROCK &&
7441 effective_action == ACTION_FILLING)
7442 printf("::: has_action_graphics == %d\n", has_action_graphics);
7445 if ((!g->double_movement && (effective_action == ACTION_FALLING ||
7446 effective_action == ACTION_MOVING ||
7447 effective_action == ACTION_PUSHING ||
7448 effective_action == ACTION_EATING)) ||
7449 (!has_action_graphics && (effective_action == ACTION_FILLING ||
7450 effective_action == ACTION_EMPTYING)))
7453 (effective_action == ACTION_FALLING ||
7454 effective_action == ACTION_FILLING ||
7455 effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
7456 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
7457 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? 1 : 0);
7458 int num_steps = (i == Ydrip_s1 ? 16 :
7459 i == Ydrip_s1B ? 16 :
7460 i == Ydrip_s2 ? 16 :
7461 i == Ydrip_s2B ? 16 :
7462 i == Xsand_stonein_1 ? 32 :
7463 i == Xsand_stonein_2 ? 32 :
7464 i == Xsand_stonein_3 ? 32 :
7465 i == Xsand_stonein_4 ? 32 :
7466 i == Xsand_stoneout_1 ? 16 :
7467 i == Xsand_stoneout_2 ? 16 : 8);
7468 int cx = ABS(dx) * (TILEX / num_steps);
7469 int cy = ABS(dy) * (TILEY / num_steps);
7470 int step_frame = (i == Ydrip_s2 ? j + 8 :
7471 i == Ydrip_s2B ? j + 8 :
7472 i == Xsand_stonein_2 ? j + 8 :
7473 i == Xsand_stonein_3 ? j + 16 :
7474 i == Xsand_stonein_4 ? j + 24 :
7475 i == Xsand_stoneout_2 ? j + 8 : j) + 1;
7476 int step = (is_backside ? step_frame : num_steps - step_frame);
7478 if (is_backside) /* tile where movement starts */
7480 if (dx < 0 || dy < 0)
7482 g_em->src_offset_x = cx * step;
7483 g_em->src_offset_y = cy * step;
7487 g_em->dst_offset_x = cx * step;
7488 g_em->dst_offset_y = cy * step;
7491 else /* tile where movement ends */
7493 if (dx < 0 || dy < 0)
7495 g_em->dst_offset_x = cx * step;
7496 g_em->dst_offset_y = cy * step;
7500 g_em->src_offset_x = cx * step;
7501 g_em->src_offset_y = cy * step;
7505 g_em->width = TILEX - cx * step;
7506 g_em->height = TILEY - cy * step;
7509 /* create unique graphic identifier to decide if tile must be redrawn */
7510 /* bit 31 - 16 (16 bit): EM style graphic
7511 bit 15 - 12 ( 4 bit): EM style frame
7512 bit 11 - 6 ( 6 bit): graphic width
7513 bit 5 - 0 ( 6 bit): graphic height */
7514 g_em->unique_identifier =
7515 (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
7519 /* skip check for EMC elements not contained in original EMC artwork */
7520 if (element == EL_EMC_FAKE_ACID)
7523 if (g_em->bitmap != debug_bitmap ||
7524 g_em->src_x != debug_src_x ||
7525 g_em->src_y != debug_src_y ||
7526 g_em->src_offset_x != 0 ||
7527 g_em->src_offset_y != 0 ||
7528 g_em->dst_offset_x != 0 ||
7529 g_em->dst_offset_y != 0 ||
7530 g_em->width != TILEX ||
7531 g_em->height != TILEY)
7533 static int last_i = -1;
7541 printf("::: EMC GFX ERROR for element %d -> %d ('%s', '%s', %d)",
7542 i, element, element_info[element].token_name,
7543 element_action_info[effective_action].suffix, direction);
7545 if (element != effective_element)
7546 printf(" [%d ('%s')]",
7548 element_info[effective_element].token_name);
7552 if (g_em->bitmap != debug_bitmap)
7553 printf(" %d (%d): different bitmap! (0x%08x != 0x%08x)\n",
7554 j, is_backside, (int)(g_em->bitmap), (int)(debug_bitmap));
7556 if (g_em->src_x != debug_src_x ||
7557 g_em->src_y != debug_src_y)
7558 printf(" frame %d (%c): %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
7559 j, (is_backside ? 'B' : 'F'),
7560 g_em->src_x, g_em->src_y,
7561 g_em->src_x / 32, g_em->src_y / 32,
7562 debug_src_x, debug_src_y,
7563 debug_src_x / 32, debug_src_y / 32);
7565 if (g_em->src_offset_x != 0 ||
7566 g_em->src_offset_y != 0 ||
7567 g_em->dst_offset_x != 0 ||
7568 g_em->dst_offset_y != 0)
7569 printf(" %d (%d): offsets %d,%d and %d,%d should be all 0\n",
7571 g_em->src_offset_x, g_em->src_offset_y,
7572 g_em->dst_offset_x, g_em->dst_offset_y);
7574 if (g_em->width != TILEX ||
7575 g_em->height != TILEY)
7576 printf(" %d (%d): size %d,%d should be %d,%d\n",
7578 g_em->width, g_em->height, TILEX, TILEY);
7580 num_em_gfx_errors++;
7587 for (i = 0; i < TILE_MAX; i++)
7589 for (j = 0; j < 8; j++)
7591 int element = object_mapping[i].element_rnd;
7592 int action = object_mapping[i].action;
7593 int direction = object_mapping[i].direction;
7594 boolean is_backside = object_mapping[i].is_backside;
7595 int graphic_action = el_act_dir2img(element, action, direction);
7596 int graphic_default = el_act_dir2img(element, ACTION_DEFAULT, direction);
7598 if ((action == ACTION_SMASHED_BY_ROCK ||
7599 action == ACTION_SMASHED_BY_SPRING ||
7600 action == ACTION_EATING) &&
7601 graphic_action == graphic_default)
7603 int e = (action == ACTION_SMASHED_BY_ROCK ? Ystone_s :
7604 action == ACTION_SMASHED_BY_SPRING ? Yspring_s :
7605 direction == MV_LEFT ? (is_backside? Yspring_wB: Yspring_w) :
7606 direction == MV_RIGHT ? (is_backside? Yspring_eB: Yspring_e) :
7609 /* no separate animation for "smashed by rock" -- use rock instead */
7610 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
7611 struct GraphicInfo_EM *g_xx = &graphic_info_em_object[e][7 - j];
7613 g_em->bitmap = g_xx->bitmap;
7614 g_em->src_x = g_xx->src_x;
7615 g_em->src_y = g_xx->src_y;
7616 g_em->src_offset_x = g_xx->src_offset_x;
7617 g_em->src_offset_y = g_xx->src_offset_y;
7618 g_em->dst_offset_x = g_xx->dst_offset_x;
7619 g_em->dst_offset_y = g_xx->dst_offset_y;
7620 g_em->width = g_xx->width;
7621 g_em->height = g_xx->height;
7622 g_em->unique_identifier = g_xx->unique_identifier;
7625 g_em->preserve_background = TRUE;
7630 for (p = 0; p < MAX_PLAYERS; p++)
7632 for (i = 0; i < SPR_MAX; i++)
7634 int element = player_mapping[p][i].element_rnd;
7635 int action = player_mapping[p][i].action;
7636 int direction = player_mapping[p][i].direction;
7638 for (j = 0; j < 8; j++)
7640 int effective_element = element;
7641 int effective_action = action;
7642 int graphic = (direction == MV_NONE ?
7643 el_act2img(effective_element, effective_action) :
7644 el_act_dir2img(effective_element, effective_action,
7646 struct GraphicInfo *g = &graphic_info[graphic];
7647 struct GraphicInfo_EM *g_em = &graphic_info_em_player[p][i][7 - j];
7653 Bitmap *debug_bitmap = g_em->bitmap;
7654 int debug_src_x = g_em->src_x;
7655 int debug_src_y = g_em->src_y;
7658 int frame = getAnimationFrame(g->anim_frames,
7661 g->anim_start_frame,
7664 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
7666 g_em->bitmap = src_bitmap;
7667 g_em->src_x = src_x;
7668 g_em->src_y = src_y;
7669 g_em->src_offset_x = 0;
7670 g_em->src_offset_y = 0;
7671 g_em->dst_offset_x = 0;
7672 g_em->dst_offset_y = 0;
7673 g_em->width = TILEX;
7674 g_em->height = TILEY;
7678 /* skip check for EMC elements not contained in original EMC artwork */
7679 if (element == EL_PLAYER_3 ||
7680 element == EL_PLAYER_4)
7683 if (g_em->bitmap != debug_bitmap ||
7684 g_em->src_x != debug_src_x ||
7685 g_em->src_y != debug_src_y)
7687 static int last_i = -1;
7695 printf("::: EMC GFX ERROR for p/a %d/%d -> %d ('%s', '%s', %d)",
7696 p, i, element, element_info[element].token_name,
7697 element_action_info[effective_action].suffix, direction);
7699 if (element != effective_element)
7700 printf(" [%d ('%s')]",
7702 element_info[effective_element].token_name);
7706 if (g_em->bitmap != debug_bitmap)
7707 printf(" %d: different bitmap! (0x%08x != 0x%08x)\n",
7708 j, (int)(g_em->bitmap), (int)(debug_bitmap));
7710 if (g_em->src_x != debug_src_x ||
7711 g_em->src_y != debug_src_y)
7712 printf(" frame %d: %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
7714 g_em->src_x, g_em->src_y,
7715 g_em->src_x / 32, g_em->src_y / 32,
7716 debug_src_x, debug_src_y,
7717 debug_src_x / 32, debug_src_y / 32);
7719 num_em_gfx_errors++;
7729 printf("::: [%d errors found]\n", num_em_gfx_errors);
7735 void PlayMenuSoundExt(int sound)
7737 if (sound == SND_UNDEFINED)
7740 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
7741 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
7744 if (IS_LOOP_SOUND(sound))
7745 PlaySoundLoop(sound);
7750 void PlayMenuSound()
7752 PlayMenuSoundExt(menu.sound[game_status]);
7755 void PlayMenuSoundStereo(int sound, int stereo_position)
7757 if (sound == SND_UNDEFINED)
7760 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
7761 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
7764 if (IS_LOOP_SOUND(sound))
7765 PlaySoundExt(sound, SOUND_MAX_VOLUME, stereo_position, SND_CTRL_PLAY_LOOP);
7767 PlaySoundStereo(sound, stereo_position);
7770 void PlayMenuSoundIfLoopExt(int sound)
7772 if (sound == SND_UNDEFINED)
7775 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
7776 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
7779 if (IS_LOOP_SOUND(sound))
7780 PlaySoundLoop(sound);
7783 void PlayMenuSoundIfLoop()
7785 PlayMenuSoundIfLoopExt(menu.sound[game_status]);
7788 void PlayMenuMusicExt(int music)
7790 if (music == MUS_UNDEFINED)
7793 if (!setup.sound_music)
7799 void PlayMenuMusic()
7801 PlayMenuMusicExt(menu.music[game_status]);
7804 void PlaySoundActivating()
7807 PlaySound(SND_MENU_ITEM_ACTIVATING);
7811 void PlaySoundSelecting()
7814 PlaySound(SND_MENU_ITEM_SELECTING);
7818 void ToggleFullscreenIfNeeded()
7820 boolean change_fullscreen = (setup.fullscreen !=
7821 video.fullscreen_enabled);
7822 boolean change_fullscreen_mode = (video.fullscreen_enabled &&
7823 !strEqual(setup.fullscreen_mode,
7824 video.fullscreen_mode_current));
7826 if (!video.fullscreen_available)
7830 if (change_fullscreen || change_fullscreen_mode)
7832 if (setup.fullscreen != video.fullscreen_enabled ||
7833 setup.fullscreen_mode != video.fullscreen_mode_current)
7836 Bitmap *tmp_backbuffer = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
7838 /* save backbuffer content which gets lost when toggling fullscreen mode */
7839 BlitBitmap(backbuffer, tmp_backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
7842 if (change_fullscreen_mode)
7844 if (setup.fullscreen && video.fullscreen_enabled)
7847 /* keep fullscreen, but change fullscreen mode (screen resolution) */
7849 /* (this is now set in sdl.c) */
7851 video.fullscreen_mode_current = setup.fullscreen_mode;
7853 video.fullscreen_enabled = FALSE; /* force new fullscreen mode */
7856 /* toggle fullscreen */
7857 ChangeVideoModeIfNeeded(setup.fullscreen);
7859 setup.fullscreen = video.fullscreen_enabled;
7861 /* restore backbuffer content from temporary backbuffer backup bitmap */
7862 BlitBitmap(tmp_backbuffer, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
7864 FreeBitmap(tmp_backbuffer);
7867 /* update visible window/screen */
7868 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
7870 redraw_mask = REDRAW_ALL;