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 if (game.use_masked_pushing && IS_MOVING(jx, jy))
2725 /* this allows transparent pushing animation over non-black background */
2728 DrawLevelElement(jx, jy, Back[jx][jy]);
2730 DrawLevelElement(jx, jy, EL_EMPTY);
2732 if (Back[next_jx][next_jy])
2733 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
2735 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
2737 else if (Back[next_jx][next_jy])
2738 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
2740 if (Back[next_jx][next_jy])
2741 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
2745 printf("::: %d, %d, %d, %d [%d] [%d, %d, %d] [%d] [%d, %d] [%d, %d]\n",
2746 jx, px, player->GfxPos, player->StepFrame,
2751 GfxFrame[jx][jy], GfxFrame[next_jx][next_jy]);
2755 /* do not draw (EM style) pushing animation when pushing is finished */
2756 /* (two-tile animations usually do not contain start and end frame) */
2757 if (graphic_info[graphic].double_movement && !IS_MOVING(jx, jy))
2758 DrawLevelElement(next_jx, next_jy, Feld[next_jx][next_jy]);
2760 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
2762 /* masked drawing is needed for EMC style (double) movement graphics */
2763 /* !!! (ONLY WHEN DRAWING PUSHED ELEMENT OVER THE PLAYER) !!! */
2764 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
2769 #if DRAW_PLAYER_OVER_PUSHED_ELEMENT
2770 /* ----------------------------------------------------------------------- */
2771 /* draw player himself */
2772 /* ----------------------------------------------------------------------- */
2774 graphic = getPlayerGraphic(player, move_dir);
2776 /* in the case of changed player action or direction, prevent the current
2777 animation frame from being restarted for identical animations */
2778 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
2779 player->Frame = last_player_frame;
2781 frame = getGraphicAnimationFrame(graphic, player->Frame);
2785 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
2786 sxx = player->GfxPos;
2788 syy = player->GfxPos;
2791 if (!setup.soft_scrolling && ScreenMovPos)
2794 if (player_is_opaque)
2795 DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
2797 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
2799 if (SHIELD_ON(player))
2801 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
2802 IMG_SHIELD_NORMAL_ACTIVE);
2803 int frame = getGraphicAnimationFrame(graphic, -1);
2805 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
2809 /* ----------------------------------------------------------------------- */
2810 /* draw things in front of player (active dynamite or dynabombs) */
2811 /* ----------------------------------------------------------------------- */
2813 if (IS_ACTIVE_BOMB(element))
2815 graphic = el2img(element);
2816 frame = getGraphicAnimationFrame(graphic, GfxFrame[jx][jy]);
2818 if (game.emulation == EMU_SUPAPLEX)
2819 DrawGraphic(sx, sy, IMG_SP_DISK_RED, frame);
2821 DrawGraphicThruMask(sx, sy, graphic, frame);
2824 if (player_is_moving && last_element == EL_EXPLOSION)
2826 int element = (GfxElement[last_jx][last_jy] != EL_UNDEFINED ?
2827 GfxElement[last_jx][last_jy] : EL_EMPTY);
2828 int graphic = el_act2img(element, ACTION_EXPLODING);
2829 int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
2830 int phase = ExplodePhase[last_jx][last_jy] - 1;
2831 int frame = getGraphicAnimationFrame(graphic, phase - delay);
2834 DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy), graphic, frame);
2837 /* ----------------------------------------------------------------------- */
2838 /* draw elements the player is just walking/passing through/under */
2839 /* ----------------------------------------------------------------------- */
2841 if (player_is_moving)
2843 /* handle the field the player is leaving ... */
2844 if (IS_ACCESSIBLE_INSIDE(last_element))
2845 DrawLevelField(last_jx, last_jy);
2846 else if (IS_ACCESSIBLE_UNDER(last_element))
2847 DrawLevelFieldThruMask(last_jx, last_jy);
2850 /* do not redraw accessible elements if the player is just pushing them */
2851 if (!player_is_moving || !player->is_pushing)
2853 /* ... and the field the player is entering */
2854 if (IS_ACCESSIBLE_INSIDE(element))
2855 DrawLevelField(jx, jy);
2856 else if (IS_ACCESSIBLE_UNDER(element))
2857 DrawLevelFieldThruMask(jx, jy);
2860 MarkTileDirty(sx, sy);
2863 /* ------------------------------------------------------------------------- */
2865 void WaitForEventToContinue()
2867 boolean still_wait = TRUE;
2869 /* simulate releasing mouse button over last gadget, if still pressed */
2871 HandleGadgets(-1, -1, 0);
2873 button_status = MB_RELEASED;
2889 case EVENT_BUTTONPRESS:
2890 case EVENT_KEYPRESS:
2894 case EVENT_KEYRELEASE:
2895 ClearPlayerAction();
2899 HandleOtherEvents(&event);
2903 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
2910 /* don't eat all CPU time */
2915 #define MAX_REQUEST_LINES 13
2916 #define MAX_REQUEST_LINE_FONT1_LEN 7
2917 #define MAX_REQUEST_LINE_FONT2_LEN 10
2919 boolean Request(char *text, unsigned int req_state)
2921 int mx, my, ty, result = -1;
2922 unsigned int old_door_state;
2923 int last_game_status = game_status; /* save current game status */
2924 int max_request_line_len = MAX_REQUEST_LINE_FONT1_LEN;
2925 int font_nr = FONT_TEXT_2;
2926 int max_word_len = 0;
2929 for (text_ptr = text; *text_ptr; text_ptr++)
2931 max_word_len = (*text_ptr != ' ' ? max_word_len + 1 : 0);
2933 if (max_word_len > MAX_REQUEST_LINE_FONT1_LEN)
2935 max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
2937 font_nr = FONT_TEXT_1;
2939 font_nr = FONT_LEVEL_NUMBER;
2946 if (game_status == GAME_MODE_PLAYING)
2948 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
2949 BlitScreenToBitmap_EM(backbuffer);
2950 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
2951 BlitScreenToBitmap_SP(backbuffer);
2954 /* disable deactivated drawing when quick-loading level tape recording */
2955 if (tape.playing && tape.deactivate_display)
2956 TapeDeactivateDisplayOff(TRUE);
2958 SetMouseCursor(CURSOR_DEFAULT);
2960 #if defined(NETWORK_AVALIABLE)
2961 /* pause network game while waiting for request to answer */
2962 if (options.network &&
2963 game_status == GAME_MODE_PLAYING &&
2964 req_state & REQUEST_WAIT_FOR_INPUT)
2965 SendToServer_PausePlaying();
2968 old_door_state = GetDoorState();
2970 /* simulate releasing mouse button over last gadget, if still pressed */
2972 HandleGadgets(-1, -1, 0);
2976 if (old_door_state & DOOR_OPEN_1)
2978 CloseDoor(DOOR_CLOSE_1);
2980 /* save old door content */
2981 BlitBitmap(bitmap_db_door, bitmap_db_door,
2982 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
2983 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
2987 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
2990 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
2992 /* clear door drawing field */
2993 DrawBackground(DX, DY, DXSIZE, DYSIZE);
2995 /* force DOOR font inside door area */
2996 game_status = GAME_MODE_PSEUDO_DOOR;
2998 /* write text for request */
2999 for (ty = 0; ty < MAX_REQUEST_LINES; ty++)
3001 char text_line[max_request_line_len + 1];
3007 for (tl = 0, tx = 0; tx < max_request_line_len; tl++, tx++)
3010 if (!tc || tc == ' ')
3021 strncpy(text_line, text, tl);
3024 DrawText(DX + (DXSIZE - tl * getFontWidth(font_nr)) / 2,
3025 DY + 8 + ty * (getFontHeight(font_nr) + 2),
3026 text_line, font_nr);
3028 text += tl + (tc == ' ' ? 1 : 0);
3031 game_status = last_game_status; /* restore current game status */
3033 if (req_state & REQ_ASK)
3035 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
3036 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
3038 else if (req_state & REQ_CONFIRM)
3040 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
3042 else if (req_state & REQ_PLAYER)
3044 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
3045 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
3046 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
3047 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
3050 /* copy request gadgets to door backbuffer */
3051 BlitBitmap(drawto, bitmap_db_door,
3052 DX, DY, DXSIZE, DYSIZE,
3053 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
3055 OpenDoor(DOOR_OPEN_1);
3057 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
3059 if (game_status == GAME_MODE_PLAYING)
3061 SetPanelBackground();
3062 SetDrawBackgroundMask(REDRAW_DOOR_1);
3066 SetDrawBackgroundMask(REDRAW_FIELD);
3072 if (game_status != GAME_MODE_MAIN)
3075 button_status = MB_RELEASED;
3077 request_gadget_id = -1;
3079 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
3091 case EVENT_BUTTONPRESS:
3092 case EVENT_BUTTONRELEASE:
3093 case EVENT_MOTIONNOTIFY:
3095 if (event.type == EVENT_MOTIONNOTIFY)
3097 if (!PointerInWindow(window))
3098 continue; /* window and pointer are on different screens */
3103 motion_status = TRUE;
3104 mx = ((MotionEvent *) &event)->x;
3105 my = ((MotionEvent *) &event)->y;
3109 motion_status = FALSE;
3110 mx = ((ButtonEvent *) &event)->x;
3111 my = ((ButtonEvent *) &event)->y;
3112 if (event.type == EVENT_BUTTONPRESS)
3113 button_status = ((ButtonEvent *) &event)->button;
3115 button_status = MB_RELEASED;
3118 /* this sets 'request_gadget_id' */
3119 HandleGadgets(mx, my, button_status);
3121 switch (request_gadget_id)
3123 case TOOL_CTRL_ID_YES:
3126 case TOOL_CTRL_ID_NO:
3129 case TOOL_CTRL_ID_CONFIRM:
3130 result = TRUE | FALSE;
3133 case TOOL_CTRL_ID_PLAYER_1:
3136 case TOOL_CTRL_ID_PLAYER_2:
3139 case TOOL_CTRL_ID_PLAYER_3:
3142 case TOOL_CTRL_ID_PLAYER_4:
3153 case EVENT_KEYPRESS:
3154 switch (GetEventKey((KeyEvent *)&event, TRUE))
3157 if (req_state & REQ_CONFIRM)
3173 if (req_state & REQ_PLAYER)
3177 case EVENT_KEYRELEASE:
3178 ClearPlayerAction();
3182 HandleOtherEvents(&event);
3186 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
3188 int joy = AnyJoystick();
3190 if (joy & JOY_BUTTON_1)
3192 else if (joy & JOY_BUTTON_2)
3198 if (game_status == GAME_MODE_PLAYING && local_player->LevelSolved_GameEnd)
3200 HandleGameActions();
3206 if (!PendingEvent()) /* delay only if no pending events */
3217 if (!PendingEvent()) /* delay only if no pending events */
3220 /* don't eat all CPU time */
3227 if (game_status != GAME_MODE_MAIN)
3232 if (!(req_state & REQ_STAY_OPEN))
3234 CloseDoor(DOOR_CLOSE_1);
3236 if (((old_door_state & DOOR_OPEN_1) && !(req_state & REQ_STAY_CLOSED)) ||
3237 (req_state & REQ_REOPEN))
3238 OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
3243 if (game_status == GAME_MODE_PLAYING)
3245 SetPanelBackground();
3246 SetDrawBackgroundMask(REDRAW_DOOR_1);
3250 SetDrawBackgroundMask(REDRAW_FIELD);
3253 #if defined(NETWORK_AVALIABLE)
3254 /* continue network game after request */
3255 if (options.network &&
3256 game_status == GAME_MODE_PLAYING &&
3257 req_state & REQUEST_WAIT_FOR_INPUT)
3258 SendToServer_ContinuePlaying();
3261 /* restore deactivated drawing when quick-loading level tape recording */
3262 if (tape.playing && tape.deactivate_display)
3263 TapeDeactivateDisplayOn();
3268 unsigned int OpenDoor(unsigned int door_state)
3270 if (door_state & DOOR_COPY_BACK)
3272 if (door_state & DOOR_OPEN_1)
3273 BlitBitmap(bitmap_db_door, bitmap_db_door,
3274 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
3275 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
3277 if (door_state & DOOR_OPEN_2)
3278 BlitBitmap(bitmap_db_door, bitmap_db_door,
3279 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY2, VXSIZE, VYSIZE,
3280 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
3282 door_state &= ~DOOR_COPY_BACK;
3285 return MoveDoor(door_state);
3288 unsigned int CloseDoor(unsigned int door_state)
3290 unsigned int old_door_state = GetDoorState();
3292 if (!(door_state & DOOR_NO_COPY_BACK))
3294 if (old_door_state & DOOR_OPEN_1)
3295 BlitBitmap(backbuffer, bitmap_db_door,
3296 DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
3298 if (old_door_state & DOOR_OPEN_2)
3299 BlitBitmap(backbuffer, bitmap_db_door,
3300 VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
3302 door_state &= ~DOOR_NO_COPY_BACK;
3305 return MoveDoor(door_state);
3308 unsigned int GetDoorState()
3310 return MoveDoor(DOOR_GET_STATE);
3313 unsigned int SetDoorState(unsigned int door_state)
3315 return MoveDoor(door_state | DOOR_SET_STATE);
3318 unsigned int MoveDoor(unsigned int door_state)
3320 static int door1 = DOOR_OPEN_1;
3321 static int door2 = DOOR_CLOSE_2;
3322 unsigned long door_delay = 0;
3323 unsigned long door_delay_value;
3326 if (door_1.width < 0 || door_1.width > DXSIZE)
3327 door_1.width = DXSIZE;
3328 if (door_1.height < 0 || door_1.height > DYSIZE)
3329 door_1.height = DYSIZE;
3330 if (door_2.width < 0 || door_2.width > VXSIZE)
3331 door_2.width = VXSIZE;
3332 if (door_2.height < 0 || door_2.height > VYSIZE)
3333 door_2.height = VYSIZE;
3335 if (door_state == DOOR_GET_STATE)
3336 return (door1 | door2);
3338 if (door_state & DOOR_SET_STATE)
3340 if (door_state & DOOR_ACTION_1)
3341 door1 = door_state & DOOR_ACTION_1;
3342 if (door_state & DOOR_ACTION_2)
3343 door2 = door_state & DOOR_ACTION_2;
3345 return (door1 | door2);
3348 if (!(door_state & DOOR_FORCE_REDRAW))
3350 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
3351 door_state &= ~DOOR_OPEN_1;
3352 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
3353 door_state &= ~DOOR_CLOSE_1;
3354 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
3355 door_state &= ~DOOR_OPEN_2;
3356 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
3357 door_state &= ~DOOR_CLOSE_2;
3360 door_delay_value = (door_state & DOOR_ACTION_1 ? door_1.step_delay :
3363 if (setup.quick_doors)
3365 stepsize = 20; /* must be chosen to always draw last frame */
3366 door_delay_value = 0;
3369 if (global.autoplay_leveldir)
3371 door_state |= DOOR_NO_DELAY;
3372 door_state &= ~DOOR_CLOSE_ALL;
3376 if (game_status == GAME_MODE_EDITOR)
3377 door_state |= DOOR_NO_DELAY;
3380 if (door_state & DOOR_ACTION)
3382 boolean handle_door_1 = (door_state & DOOR_ACTION_1);
3383 boolean handle_door_2 = (door_state & DOOR_ACTION_2);
3384 boolean door_1_done = (!handle_door_1);
3385 boolean door_2_done = (!handle_door_2);
3386 boolean door_1_vertical = (door_1.anim_mode & ANIM_VERTICAL);
3387 boolean door_2_vertical = (door_2.anim_mode & ANIM_VERTICAL);
3388 int door_size_1 = (door_1_vertical ? door_1.height : door_1.width);
3389 int door_size_2 = (door_2_vertical ? door_2.height : door_2.width);
3390 int max_door_size_1 = (door_1_vertical ? DYSIZE : DXSIZE);
3391 int max_door_size_2 = (door_2_vertical ? VYSIZE : VXSIZE);
3392 int door_size = (handle_door_1 ? door_size_1 : door_size_2);
3393 int max_door_size = (handle_door_1 ? max_door_size_1 : max_door_size_2);
3394 int door_skip = max_door_size - door_size;
3395 int end = door_size;
3396 int start = ((door_state & DOOR_NO_DELAY) ? end : 0);
3399 if (!(door_state & DOOR_NO_DELAY) && !setup.quick_doors)
3401 /* opening door sound has priority over simultaneously closing door */
3402 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
3403 PlayMenuSoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
3404 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
3405 PlayMenuSoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
3408 for (k = start; k <= end && !(door_1_done && door_2_done); k += stepsize)
3411 Bitmap *bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
3412 GC gc = bitmap->stored_clip_gc;
3414 if (door_state & DOOR_ACTION_1)
3416 int a = MIN(x * door_1.step_offset, end);
3417 int p = (door_state & DOOR_OPEN_1 ? end - a : a);
3418 int i = p + door_skip;
3420 if (door_1.anim_mode & ANIM_STATIC_PANEL)
3422 BlitBitmap(bitmap_db_door, drawto,
3423 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1,
3424 DXSIZE, DYSIZE, DX, DY);
3428 BlitBitmap(bitmap_db_door, drawto,
3429 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + p / 2,
3430 DXSIZE, DYSIZE - p / 2, DX, DY);
3432 ClearRectangle(drawto, DX, DY + DYSIZE - p / 2, DXSIZE, p / 2);
3435 if (door_1.anim_mode & ANIM_HORIZONTAL && x <= DXSIZE)
3437 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
3438 int dst1_x = DX + DXSIZE - i, dst1_y = DY;
3439 int src2_x = DXSIZE - i, src2_y = DOOR_GFX_PAGEY1;
3440 int dst2_x = DX, dst2_y = DY;
3441 int width = i, height = DYSIZE;
3443 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
3444 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
3447 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
3448 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
3451 else if (door_1.anim_mode & ANIM_VERTICAL && x <= DYSIZE)
3453 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
3454 int dst1_x = DX, dst1_y = DY + DYSIZE - i;
3455 int src2_x = 0, src2_y = DOOR_GFX_PAGEY1 + DYSIZE - i;
3456 int dst2_x = DX, dst2_y = DY;
3457 int width = DXSIZE, height = i;
3459 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
3460 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
3463 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
3464 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
3467 else if (x <= DXSIZE) /* ANIM_DEFAULT */
3469 int j = (door_1.anim_mode == ANIM_DEFAULT ? (DXSIZE - i) / 3 : 0);
3471 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
3472 BlitBitmapMasked(bitmap, drawto,
3473 DXSIZE, DOOR_GFX_PAGEY1, i, 77,
3474 DX + DXSIZE - i, DY + j);
3475 BlitBitmapMasked(bitmap, drawto,
3476 DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63,
3477 DX + DXSIZE - i, DY + 140 + j);
3478 SetClipOrigin(bitmap, gc, DX - DXSIZE + i,
3479 DY - (DOOR_GFX_PAGEY1 + j));
3480 BlitBitmapMasked(bitmap, drawto,
3481 DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j,
3483 BlitBitmapMasked(bitmap, drawto,
3484 DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63,
3487 BlitBitmapMasked(bitmap, drawto,
3488 DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
3490 BlitBitmapMasked(bitmap, drawto,
3491 DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
3493 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
3494 BlitBitmapMasked(bitmap, drawto,
3495 DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
3496 DX + DXSIZE - i, DY + 77 + j);
3497 BlitBitmapMasked(bitmap, drawto,
3498 DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
3499 DX + DXSIZE - i, DY + 203 + j);
3502 redraw_mask |= REDRAW_DOOR_1;
3503 door_1_done = (a == end);
3506 if (door_state & DOOR_ACTION_2)
3508 int a = MIN(x * door_2.step_offset, door_size);
3509 int p = (door_state & DOOR_OPEN_2 ? door_size - a : a);
3510 int i = p + door_skip;
3512 if (door_2.anim_mode & ANIM_STATIC_PANEL)
3514 BlitBitmap(bitmap_db_door, drawto,
3515 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2,
3516 VXSIZE, VYSIZE, VX, VY);
3518 else if (x <= VYSIZE)
3520 BlitBitmap(bitmap_db_door, drawto,
3521 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + p / 2,
3522 VXSIZE, VYSIZE - p / 2, VX, VY);
3524 ClearRectangle(drawto, VX, VY + VYSIZE - p / 2, VXSIZE, p / 2);
3527 if (door_2.anim_mode & ANIM_HORIZONTAL && x <= VXSIZE)
3529 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
3530 int dst1_x = VX + VXSIZE - i, dst1_y = VY;
3531 int src2_x = VXSIZE - i, src2_y = DOOR_GFX_PAGEY2;
3532 int dst2_x = VX, dst2_y = VY;
3533 int width = i, height = VYSIZE;
3535 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
3536 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
3539 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
3540 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
3543 else if (door_2.anim_mode & ANIM_VERTICAL && x <= VYSIZE)
3545 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
3546 int dst1_x = VX, dst1_y = VY + VYSIZE - i;
3547 int src2_x = 0, src2_y = DOOR_GFX_PAGEY2 + VYSIZE - i;
3548 int dst2_x = VX, dst2_y = VY;
3549 int width = VXSIZE, height = i;
3551 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
3552 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
3555 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
3556 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
3559 else if (x <= VXSIZE) /* ANIM_DEFAULT */
3561 int j = (door_2.anim_mode == ANIM_DEFAULT ? (VXSIZE - i) / 3 : 0);
3563 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
3564 BlitBitmapMasked(bitmap, drawto,
3565 VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2,
3566 VX + VXSIZE - i, VY + j);
3567 SetClipOrigin(bitmap, gc,
3568 VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
3569 BlitBitmapMasked(bitmap, drawto,
3570 VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j,
3573 BlitBitmapMasked(bitmap, drawto,
3574 VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2,
3575 i, VYSIZE / 2, VX, VY + VYSIZE / 2 - j);
3576 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
3577 BlitBitmapMasked(bitmap, drawto,
3578 VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2,
3580 VX + VXSIZE - i, VY + VYSIZE / 2 + j);
3583 redraw_mask |= REDRAW_DOOR_2;
3584 door_2_done = (a == VXSIZE);
3587 if (!(door_state & DOOR_NO_DELAY))
3591 if (game_status == GAME_MODE_MAIN)
3594 WaitUntilDelayReached(&door_delay, door_delay_value);
3599 if (door_state & DOOR_ACTION_1)
3600 door1 = door_state & DOOR_ACTION_1;
3601 if (door_state & DOOR_ACTION_2)
3602 door2 = door_state & DOOR_ACTION_2;
3604 return (door1 | door2);
3607 void DrawSpecialEditorDoor()
3609 /* draw bigger toolbox window */
3610 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
3611 DOOR_GFX_PAGEX7, 0, EXSIZE + 8, 8,
3613 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
3614 EX - 6, VY - 4, EXSIZE + 12, EYSIZE - VYSIZE + 4,
3617 redraw_mask |= REDRAW_ALL;
3620 void UndrawSpecialEditorDoor()
3622 /* draw normal tape recorder window */
3623 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
3624 EX - 6, EY - 12, EXSIZE + 12, EYSIZE - VYSIZE + 12,
3627 redraw_mask |= REDRAW_ALL;
3631 /* ---------- new tool button stuff ---------------------------------------- */
3633 /* graphic position values for tool buttons */
3634 #define TOOL_BUTTON_YES_XPOS 2
3635 #define TOOL_BUTTON_YES_YPOS 250
3636 #define TOOL_BUTTON_YES_GFX_YPOS 0
3637 #define TOOL_BUTTON_YES_XSIZE 46
3638 #define TOOL_BUTTON_YES_YSIZE 28
3639 #define TOOL_BUTTON_NO_XPOS 52
3640 #define TOOL_BUTTON_NO_YPOS TOOL_BUTTON_YES_YPOS
3641 #define TOOL_BUTTON_NO_GFX_YPOS TOOL_BUTTON_YES_GFX_YPOS
3642 #define TOOL_BUTTON_NO_XSIZE TOOL_BUTTON_YES_XSIZE
3643 #define TOOL_BUTTON_NO_YSIZE TOOL_BUTTON_YES_YSIZE
3644 #define TOOL_BUTTON_CONFIRM_XPOS TOOL_BUTTON_YES_XPOS
3645 #define TOOL_BUTTON_CONFIRM_YPOS TOOL_BUTTON_YES_YPOS
3646 #define TOOL_BUTTON_CONFIRM_GFX_YPOS 30
3647 #define TOOL_BUTTON_CONFIRM_XSIZE 96
3648 #define TOOL_BUTTON_CONFIRM_YSIZE TOOL_BUTTON_YES_YSIZE
3649 #define TOOL_BUTTON_PLAYER_XSIZE 30
3650 #define TOOL_BUTTON_PLAYER_YSIZE 30
3651 #define TOOL_BUTTON_PLAYER_GFX_XPOS 5
3652 #define TOOL_BUTTON_PLAYER_GFX_YPOS 185
3653 #define TOOL_BUTTON_PLAYER_XPOS (5 + TOOL_BUTTON_PLAYER_XSIZE / 2)
3654 #define TOOL_BUTTON_PLAYER_YPOS (215 - TOOL_BUTTON_PLAYER_YSIZE / 2)
3655 #define TOOL_BUTTON_PLAYER1_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3656 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
3657 #define TOOL_BUTTON_PLAYER2_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3658 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
3659 #define TOOL_BUTTON_PLAYER3_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3660 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
3661 #define TOOL_BUTTON_PLAYER4_XPOS (TOOL_BUTTON_PLAYER_XPOS \
3662 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
3663 #define TOOL_BUTTON_PLAYER1_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3664 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
3665 #define TOOL_BUTTON_PLAYER2_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3666 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
3667 #define TOOL_BUTTON_PLAYER3_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3668 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
3669 #define TOOL_BUTTON_PLAYER4_YPOS (TOOL_BUTTON_PLAYER_YPOS \
3670 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
3679 } toolbutton_info[NUM_TOOL_BUTTONS] =
3682 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_GFX_YPOS,
3683 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_YPOS,
3684 TOOL_BUTTON_YES_XSIZE, TOOL_BUTTON_YES_YSIZE,
3689 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_GFX_YPOS,
3690 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_YPOS,
3691 TOOL_BUTTON_NO_XSIZE, TOOL_BUTTON_NO_YSIZE,
3696 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_GFX_YPOS,
3697 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_YPOS,
3698 TOOL_BUTTON_CONFIRM_XSIZE, TOOL_BUTTON_CONFIRM_YSIZE,
3699 TOOL_CTRL_ID_CONFIRM,
3703 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3704 TOOL_BUTTON_PLAYER1_XPOS, TOOL_BUTTON_PLAYER1_YPOS,
3705 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3706 TOOL_CTRL_ID_PLAYER_1,
3710 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3711 TOOL_BUTTON_PLAYER2_XPOS, TOOL_BUTTON_PLAYER2_YPOS,
3712 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3713 TOOL_CTRL_ID_PLAYER_2,
3717 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3718 TOOL_BUTTON_PLAYER3_XPOS, TOOL_BUTTON_PLAYER3_YPOS,
3719 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3720 TOOL_CTRL_ID_PLAYER_3,
3724 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3725 TOOL_BUTTON_PLAYER4_XPOS, TOOL_BUTTON_PLAYER4_YPOS,
3726 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
3727 TOOL_CTRL_ID_PLAYER_4,
3732 void CreateToolButtons()
3736 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3738 Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
3739 Bitmap *deco_bitmap = None;
3740 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
3741 struct GadgetInfo *gi;
3742 unsigned long event_mask;
3743 int gd_xoffset, gd_yoffset;
3744 int gd_x1, gd_x2, gd_y;
3747 event_mask = GD_EVENT_RELEASED;
3749 gd_xoffset = toolbutton_info[i].xpos;
3750 gd_yoffset = toolbutton_info[i].ypos;
3751 gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
3752 gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
3753 gd_y = DOOR_GFX_PAGEY1 + gd_yoffset;
3755 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
3757 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
3759 getMiniGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr),
3760 &deco_bitmap, &deco_x, &deco_y);
3761 deco_xpos = (toolbutton_info[i].width - MINI_TILEX) / 2;
3762 deco_ypos = (toolbutton_info[i].height - MINI_TILEY) / 2;
3765 gi = CreateGadget(GDI_CUSTOM_ID, id,
3766 GDI_INFO_TEXT, toolbutton_info[i].infotext,
3767 GDI_X, DX + toolbutton_info[i].x,
3768 GDI_Y, DY + toolbutton_info[i].y,
3769 GDI_WIDTH, toolbutton_info[i].width,
3770 GDI_HEIGHT, toolbutton_info[i].height,
3771 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
3772 GDI_STATE, GD_BUTTON_UNPRESSED,
3773 GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
3774 GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
3775 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
3776 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
3777 GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
3778 GDI_DECORATION_SHIFTING, 1, 1,
3779 GDI_DIRECT_DRAW, FALSE,
3780 GDI_EVENT_MASK, event_mask,
3781 GDI_CALLBACK_ACTION, HandleToolButtons,
3785 Error(ERR_EXIT, "cannot create gadget");
3787 tool_gadget[id] = gi;
3791 void FreeToolButtons()
3795 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3796 FreeGadget(tool_gadget[i]);
3799 static void UnmapToolButtons()
3803 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3804 UnmapGadget(tool_gadget[i]);
3807 static void HandleToolButtons(struct GadgetInfo *gi)
3809 request_gadget_id = gi->custom_id;
3812 static struct Mapping_EM_to_RND_object
3815 boolean is_rnd_to_em_mapping; /* unique mapping EM <-> RND */
3816 boolean is_backside; /* backside of moving element */
3822 em_object_mapping_list[] =
3825 Xblank, TRUE, FALSE,
3829 Yacid_splash_eB, FALSE, FALSE,
3830 EL_ACID_SPLASH_RIGHT, -1, -1
3833 Yacid_splash_wB, FALSE, FALSE,
3834 EL_ACID_SPLASH_LEFT, -1, -1
3837 #ifdef EM_ENGINE_BAD_ROLL
3839 Xstone_force_e, FALSE, FALSE,
3840 EL_ROCK, -1, MV_BIT_RIGHT
3843 Xstone_force_w, FALSE, FALSE,
3844 EL_ROCK, -1, MV_BIT_LEFT
3847 Xnut_force_e, FALSE, FALSE,
3848 EL_NUT, -1, MV_BIT_RIGHT
3851 Xnut_force_w, FALSE, FALSE,
3852 EL_NUT, -1, MV_BIT_LEFT
3855 Xspring_force_e, FALSE, FALSE,
3856 EL_SPRING, -1, MV_BIT_RIGHT
3859 Xspring_force_w, FALSE, FALSE,
3860 EL_SPRING, -1, MV_BIT_LEFT
3863 Xemerald_force_e, FALSE, FALSE,
3864 EL_EMERALD, -1, MV_BIT_RIGHT
3867 Xemerald_force_w, FALSE, FALSE,
3868 EL_EMERALD, -1, MV_BIT_LEFT
3871 Xdiamond_force_e, FALSE, FALSE,
3872 EL_DIAMOND, -1, MV_BIT_RIGHT
3875 Xdiamond_force_w, FALSE, FALSE,
3876 EL_DIAMOND, -1, MV_BIT_LEFT
3879 Xbomb_force_e, FALSE, FALSE,
3880 EL_BOMB, -1, MV_BIT_RIGHT
3883 Xbomb_force_w, FALSE, FALSE,
3884 EL_BOMB, -1, MV_BIT_LEFT
3886 #endif /* EM_ENGINE_BAD_ROLL */
3889 Xstone, TRUE, FALSE,
3893 Xstone_pause, FALSE, FALSE,
3897 Xstone_fall, FALSE, FALSE,
3901 Ystone_s, FALSE, FALSE,
3902 EL_ROCK, ACTION_FALLING, -1
3905 Ystone_sB, FALSE, TRUE,
3906 EL_ROCK, ACTION_FALLING, -1
3909 Ystone_e, FALSE, FALSE,
3910 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
3913 Ystone_eB, FALSE, TRUE,
3914 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
3917 Ystone_w, FALSE, FALSE,
3918 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
3921 Ystone_wB, FALSE, TRUE,
3922 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
3929 Xnut_pause, FALSE, FALSE,
3933 Xnut_fall, FALSE, FALSE,
3937 Ynut_s, FALSE, FALSE,
3938 EL_NUT, ACTION_FALLING, -1
3941 Ynut_sB, FALSE, TRUE,
3942 EL_NUT, ACTION_FALLING, -1
3945 Ynut_e, FALSE, FALSE,
3946 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
3949 Ynut_eB, FALSE, TRUE,
3950 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
3953 Ynut_w, FALSE, FALSE,
3954 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
3957 Ynut_wB, FALSE, TRUE,
3958 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
3961 Xbug_n, TRUE, FALSE,
3965 Xbug_e, TRUE, FALSE,
3966 EL_BUG_RIGHT, -1, -1
3969 Xbug_s, TRUE, FALSE,
3973 Xbug_w, TRUE, FALSE,
3977 Xbug_gon, FALSE, FALSE,
3981 Xbug_goe, FALSE, FALSE,
3982 EL_BUG_RIGHT, -1, -1
3985 Xbug_gos, FALSE, FALSE,
3989 Xbug_gow, FALSE, FALSE,
3993 Ybug_n, FALSE, FALSE,
3994 EL_BUG, ACTION_MOVING, MV_BIT_UP
3997 Ybug_nB, FALSE, TRUE,
3998 EL_BUG, ACTION_MOVING, MV_BIT_UP
4001 Ybug_e, FALSE, FALSE,
4002 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
4005 Ybug_eB, FALSE, TRUE,
4006 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
4009 Ybug_s, FALSE, FALSE,
4010 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
4013 Ybug_sB, FALSE, TRUE,
4014 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
4017 Ybug_w, FALSE, FALSE,
4018 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
4021 Ybug_wB, FALSE, TRUE,
4022 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
4025 Ybug_w_n, FALSE, FALSE,
4026 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
4029 Ybug_n_e, FALSE, FALSE,
4030 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
4033 Ybug_e_s, FALSE, FALSE,
4034 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
4037 Ybug_s_w, FALSE, FALSE,
4038 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
4041 Ybug_e_n, FALSE, FALSE,
4042 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
4045 Ybug_s_e, FALSE, FALSE,
4046 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
4049 Ybug_w_s, FALSE, FALSE,
4050 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
4053 Ybug_n_w, FALSE, FALSE,
4054 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
4057 Ybug_stone, FALSE, FALSE,
4058 EL_BUG, ACTION_SMASHED_BY_ROCK, -1
4061 Ybug_spring, FALSE, FALSE,
4062 EL_BUG, ACTION_SMASHED_BY_SPRING, -1
4065 Xtank_n, TRUE, FALSE,
4066 EL_SPACESHIP_UP, -1, -1
4069 Xtank_e, TRUE, FALSE,
4070 EL_SPACESHIP_RIGHT, -1, -1
4073 Xtank_s, TRUE, FALSE,
4074 EL_SPACESHIP_DOWN, -1, -1
4077 Xtank_w, TRUE, FALSE,
4078 EL_SPACESHIP_LEFT, -1, -1
4081 Xtank_gon, FALSE, FALSE,
4082 EL_SPACESHIP_UP, -1, -1
4085 Xtank_goe, FALSE, FALSE,
4086 EL_SPACESHIP_RIGHT, -1, -1
4089 Xtank_gos, FALSE, FALSE,
4090 EL_SPACESHIP_DOWN, -1, -1
4093 Xtank_gow, FALSE, FALSE,
4094 EL_SPACESHIP_LEFT, -1, -1
4097 Ytank_n, FALSE, FALSE,
4098 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
4101 Ytank_nB, FALSE, TRUE,
4102 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
4105 Ytank_e, FALSE, FALSE,
4106 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
4109 Ytank_eB, FALSE, TRUE,
4110 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
4113 Ytank_s, FALSE, FALSE,
4114 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
4117 Ytank_sB, FALSE, TRUE,
4118 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
4121 Ytank_w, FALSE, FALSE,
4122 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
4125 Ytank_wB, FALSE, TRUE,
4126 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
4129 Ytank_w_n, FALSE, FALSE,
4130 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
4133 Ytank_n_e, FALSE, FALSE,
4134 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
4137 Ytank_e_s, FALSE, FALSE,
4138 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
4141 Ytank_s_w, FALSE, FALSE,
4142 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
4145 Ytank_e_n, FALSE, FALSE,
4146 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
4149 Ytank_s_e, FALSE, FALSE,
4150 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
4153 Ytank_w_s, FALSE, FALSE,
4154 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
4157 Ytank_n_w, FALSE, FALSE,
4158 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
4161 Ytank_stone, FALSE, FALSE,
4162 EL_SPACESHIP, ACTION_SMASHED_BY_ROCK, -1
4165 Ytank_spring, FALSE, FALSE,
4166 EL_SPACESHIP, ACTION_SMASHED_BY_SPRING, -1
4169 Xandroid, TRUE, FALSE,
4170 EL_EMC_ANDROID, ACTION_ACTIVE, -1
4173 Xandroid_1_n, FALSE, FALSE,
4174 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
4177 Xandroid_2_n, FALSE, FALSE,
4178 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
4181 Xandroid_1_e, FALSE, FALSE,
4182 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
4185 Xandroid_2_e, FALSE, FALSE,
4186 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
4189 Xandroid_1_w, FALSE, FALSE,
4190 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
4193 Xandroid_2_w, FALSE, FALSE,
4194 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
4197 Xandroid_1_s, FALSE, FALSE,
4198 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
4201 Xandroid_2_s, FALSE, FALSE,
4202 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
4205 Yandroid_n, FALSE, FALSE,
4206 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
4209 Yandroid_nB, FALSE, TRUE,
4210 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
4213 Yandroid_ne, FALSE, FALSE,
4214 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPRIGHT
4217 Yandroid_neB, FALSE, TRUE,
4218 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPRIGHT
4221 Yandroid_e, FALSE, FALSE,
4222 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
4225 Yandroid_eB, FALSE, TRUE,
4226 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
4229 Yandroid_se, FALSE, FALSE,
4230 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNRIGHT
4233 Yandroid_seB, FALSE, TRUE,
4234 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNRIGHT
4237 Yandroid_s, FALSE, FALSE,
4238 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
4241 Yandroid_sB, FALSE, TRUE,
4242 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
4245 Yandroid_sw, FALSE, FALSE,
4246 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNLEFT
4249 Yandroid_swB, FALSE, TRUE,
4250 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNLEFT
4253 Yandroid_w, FALSE, FALSE,
4254 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
4257 Yandroid_wB, FALSE, TRUE,
4258 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
4261 Yandroid_nw, FALSE, FALSE,
4262 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPLEFT
4265 Yandroid_nwB, FALSE, TRUE,
4266 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPLEFT
4269 Xspring, TRUE, FALSE,
4273 Xspring_pause, FALSE, FALSE,
4277 Xspring_e, FALSE, FALSE,
4281 Xspring_w, FALSE, FALSE,
4285 Xspring_fall, FALSE, FALSE,
4289 Yspring_s, FALSE, FALSE,
4290 EL_SPRING, ACTION_FALLING, -1
4293 Yspring_sB, FALSE, TRUE,
4294 EL_SPRING, ACTION_FALLING, -1
4297 Yspring_e, FALSE, FALSE,
4298 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
4301 Yspring_eB, FALSE, TRUE,
4302 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
4305 Yspring_w, FALSE, FALSE,
4306 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
4309 Yspring_wB, FALSE, TRUE,
4310 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
4313 Yspring_kill_e, FALSE, FALSE,
4314 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
4317 Yspring_kill_eB, FALSE, TRUE,
4318 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
4321 Yspring_kill_w, FALSE, FALSE,
4322 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
4325 Yspring_kill_wB, FALSE, TRUE,
4326 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
4329 Xeater_n, TRUE, FALSE,
4330 EL_YAMYAM_UP, -1, -1
4333 Xeater_e, TRUE, FALSE,
4334 EL_YAMYAM_RIGHT, -1, -1
4337 Xeater_w, TRUE, FALSE,
4338 EL_YAMYAM_LEFT, -1, -1
4341 Xeater_s, TRUE, FALSE,
4342 EL_YAMYAM_DOWN, -1, -1
4345 Yeater_n, FALSE, FALSE,
4346 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
4349 Yeater_nB, FALSE, TRUE,
4350 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
4353 Yeater_e, FALSE, FALSE,
4354 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
4357 Yeater_eB, FALSE, TRUE,
4358 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
4361 Yeater_s, FALSE, FALSE,
4362 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
4365 Yeater_sB, FALSE, TRUE,
4366 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
4369 Yeater_w, FALSE, FALSE,
4370 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
4373 Yeater_wB, FALSE, TRUE,
4374 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
4377 Yeater_stone, FALSE, FALSE,
4378 EL_YAMYAM, ACTION_SMASHED_BY_ROCK, -1
4381 Yeater_spring, FALSE, FALSE,
4382 EL_YAMYAM, ACTION_SMASHED_BY_SPRING, -1
4385 Xalien, TRUE, FALSE,
4389 Xalien_pause, FALSE, FALSE,
4393 Yalien_n, FALSE, FALSE,
4394 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
4397 Yalien_nB, FALSE, TRUE,
4398 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
4401 Yalien_e, FALSE, FALSE,
4402 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
4405 Yalien_eB, FALSE, TRUE,
4406 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
4409 Yalien_s, FALSE, FALSE,
4410 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
4413 Yalien_sB, FALSE, TRUE,
4414 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
4417 Yalien_w, FALSE, FALSE,
4418 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
4421 Yalien_wB, FALSE, TRUE,
4422 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
4425 Yalien_stone, FALSE, FALSE,
4426 EL_ROBOT, ACTION_SMASHED_BY_ROCK, -1
4429 Yalien_spring, FALSE, FALSE,
4430 EL_ROBOT, ACTION_SMASHED_BY_SPRING, -1
4433 Xemerald, TRUE, FALSE,
4437 Xemerald_pause, FALSE, FALSE,
4441 Xemerald_fall, FALSE, FALSE,
4445 Xemerald_shine, FALSE, FALSE,
4446 EL_EMERALD, ACTION_TWINKLING, -1
4449 Yemerald_s, FALSE, FALSE,
4450 EL_EMERALD, ACTION_FALLING, -1
4453 Yemerald_sB, FALSE, TRUE,
4454 EL_EMERALD, ACTION_FALLING, -1
4457 Yemerald_e, FALSE, FALSE,
4458 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
4461 Yemerald_eB, FALSE, TRUE,
4462 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
4465 Yemerald_w, FALSE, FALSE,
4466 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
4469 Yemerald_wB, FALSE, TRUE,
4470 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
4473 Yemerald_eat, FALSE, FALSE,
4474 EL_EMERALD, ACTION_COLLECTING, -1
4477 Yemerald_stone, FALSE, FALSE,
4478 EL_NUT, ACTION_BREAKING, -1
4481 Xdiamond, TRUE, FALSE,
4485 Xdiamond_pause, FALSE, FALSE,
4489 Xdiamond_fall, FALSE, FALSE,
4493 Xdiamond_shine, FALSE, FALSE,
4494 EL_DIAMOND, ACTION_TWINKLING, -1
4497 Ydiamond_s, FALSE, FALSE,
4498 EL_DIAMOND, ACTION_FALLING, -1
4501 Ydiamond_sB, FALSE, TRUE,
4502 EL_DIAMOND, ACTION_FALLING, -1
4505 Ydiamond_e, FALSE, FALSE,
4506 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
4509 Ydiamond_eB, FALSE, TRUE,
4510 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
4513 Ydiamond_w, FALSE, FALSE,
4514 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
4517 Ydiamond_wB, FALSE, TRUE,
4518 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
4521 Ydiamond_eat, FALSE, FALSE,
4522 EL_DIAMOND, ACTION_COLLECTING, -1
4525 Ydiamond_stone, FALSE, FALSE,
4526 EL_DIAMOND, ACTION_SMASHED_BY_ROCK, -1
4529 Xdrip_fall, TRUE, FALSE,
4530 EL_AMOEBA_DROP, -1, -1
4533 Xdrip_stretch, FALSE, FALSE,
4534 EL_AMOEBA_DROP, ACTION_FALLING, -1
4537 Xdrip_stretchB, FALSE, TRUE,
4538 EL_AMOEBA_DROP, ACTION_FALLING, -1
4541 Xdrip_eat, FALSE, FALSE,
4542 EL_AMOEBA_DROP, ACTION_GROWING, -1
4545 Ydrip_s1, FALSE, FALSE,
4546 EL_AMOEBA_DROP, ACTION_FALLING, -1
4549 Ydrip_s1B, FALSE, TRUE,
4550 EL_AMOEBA_DROP, ACTION_FALLING, -1
4553 Ydrip_s2, FALSE, FALSE,
4554 EL_AMOEBA_DROP, ACTION_FALLING, -1
4557 Ydrip_s2B, FALSE, TRUE,
4558 EL_AMOEBA_DROP, ACTION_FALLING, -1
4565 Xbomb_pause, FALSE, FALSE,
4569 Xbomb_fall, FALSE, FALSE,
4573 Ybomb_s, FALSE, FALSE,
4574 EL_BOMB, ACTION_FALLING, -1
4577 Ybomb_sB, FALSE, TRUE,
4578 EL_BOMB, ACTION_FALLING, -1
4581 Ybomb_e, FALSE, FALSE,
4582 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
4585 Ybomb_eB, FALSE, TRUE,
4586 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
4589 Ybomb_w, FALSE, FALSE,
4590 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
4593 Ybomb_wB, FALSE, TRUE,
4594 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
4597 Ybomb_eat, FALSE, FALSE,
4598 EL_BOMB, ACTION_ACTIVATING, -1
4601 Xballoon, TRUE, FALSE,
4605 Yballoon_n, FALSE, FALSE,
4606 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
4609 Yballoon_nB, FALSE, TRUE,
4610 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
4613 Yballoon_e, FALSE, FALSE,
4614 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
4617 Yballoon_eB, FALSE, TRUE,
4618 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
4621 Yballoon_s, FALSE, FALSE,
4622 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
4625 Yballoon_sB, FALSE, TRUE,
4626 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
4629 Yballoon_w, FALSE, FALSE,
4630 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
4633 Yballoon_wB, FALSE, TRUE,
4634 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
4637 Xgrass, TRUE, FALSE,
4638 EL_EMC_GRASS, -1, -1
4641 Ygrass_nB, FALSE, FALSE,
4642 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_UP
4645 Ygrass_eB, FALSE, FALSE,
4646 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_RIGHT
4649 Ygrass_sB, FALSE, FALSE,
4650 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_DOWN
4653 Ygrass_wB, FALSE, FALSE,
4654 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_LEFT
4661 Ydirt_nB, FALSE, FALSE,
4662 EL_SAND, ACTION_DIGGING, MV_BIT_UP
4665 Ydirt_eB, FALSE, FALSE,
4666 EL_SAND, ACTION_DIGGING, MV_BIT_RIGHT
4669 Ydirt_sB, FALSE, FALSE,
4670 EL_SAND, ACTION_DIGGING, MV_BIT_DOWN
4673 Ydirt_wB, FALSE, FALSE,
4674 EL_SAND, ACTION_DIGGING, MV_BIT_LEFT
4677 Xacid_ne, TRUE, FALSE,
4678 EL_ACID_POOL_TOPRIGHT, -1, -1
4681 Xacid_se, TRUE, FALSE,
4682 EL_ACID_POOL_BOTTOMRIGHT, -1, -1
4685 Xacid_s, TRUE, FALSE,
4686 EL_ACID_POOL_BOTTOM, -1, -1
4689 Xacid_sw, TRUE, FALSE,
4690 EL_ACID_POOL_BOTTOMLEFT, -1, -1
4693 Xacid_nw, TRUE, FALSE,
4694 EL_ACID_POOL_TOPLEFT, -1, -1
4697 Xacid_1, TRUE, FALSE,
4701 Xacid_2, FALSE, FALSE,
4705 Xacid_3, FALSE, FALSE,
4709 Xacid_4, FALSE, FALSE,
4713 Xacid_5, FALSE, FALSE,
4717 Xacid_6, FALSE, FALSE,
4721 Xacid_7, FALSE, FALSE,
4725 Xacid_8, FALSE, FALSE,
4729 Xball_1, TRUE, FALSE,
4730 EL_EMC_MAGIC_BALL, -1, -1
4733 Xball_1B, FALSE, FALSE,
4734 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
4737 Xball_2, FALSE, FALSE,
4738 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
4741 Xball_2B, FALSE, FALSE,
4742 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
4745 Yball_eat, FALSE, FALSE,
4746 EL_EMC_MAGIC_BALL, ACTION_DROPPING, -1
4749 Ykey_1_eat, FALSE, FALSE,
4750 EL_EM_KEY_1, ACTION_COLLECTING, -1
4753 Ykey_2_eat, FALSE, FALSE,
4754 EL_EM_KEY_2, ACTION_COLLECTING, -1
4757 Ykey_3_eat, FALSE, FALSE,
4758 EL_EM_KEY_3, ACTION_COLLECTING, -1
4761 Ykey_4_eat, FALSE, FALSE,
4762 EL_EM_KEY_4, ACTION_COLLECTING, -1
4765 Ykey_5_eat, FALSE, FALSE,
4766 EL_EMC_KEY_5, ACTION_COLLECTING, -1
4769 Ykey_6_eat, FALSE, FALSE,
4770 EL_EMC_KEY_6, ACTION_COLLECTING, -1
4773 Ykey_7_eat, FALSE, FALSE,
4774 EL_EMC_KEY_7, ACTION_COLLECTING, -1
4777 Ykey_8_eat, FALSE, FALSE,
4778 EL_EMC_KEY_8, ACTION_COLLECTING, -1
4781 Ylenses_eat, FALSE, FALSE,
4782 EL_EMC_LENSES, ACTION_COLLECTING, -1
4785 Ymagnify_eat, FALSE, FALSE,
4786 EL_EMC_MAGNIFIER, ACTION_COLLECTING, -1
4789 Ygrass_eat, FALSE, FALSE,
4790 EL_EMC_GRASS, ACTION_SNAPPING, -1
4793 Ydirt_eat, FALSE, FALSE,
4794 EL_SAND, ACTION_SNAPPING, -1
4797 Xgrow_ns, TRUE, FALSE,
4798 EL_EXPANDABLE_WALL_VERTICAL, -1, -1
4801 Ygrow_ns_eat, FALSE, FALSE,
4802 EL_EXPANDABLE_WALL_VERTICAL, ACTION_GROWING, -1
4805 Xgrow_ew, TRUE, FALSE,
4806 EL_EXPANDABLE_WALL_HORIZONTAL, -1, -1
4809 Ygrow_ew_eat, FALSE, FALSE,
4810 EL_EXPANDABLE_WALL_HORIZONTAL, ACTION_GROWING, -1
4813 Xwonderwall, TRUE, FALSE,
4814 EL_MAGIC_WALL, -1, -1
4817 XwonderwallB, FALSE, FALSE,
4818 EL_MAGIC_WALL, ACTION_ACTIVE, -1
4821 Xamoeba_1, TRUE, FALSE,
4822 EL_AMOEBA_DRY, ACTION_OTHER, -1
4825 Xamoeba_2, FALSE, FALSE,
4826 EL_AMOEBA_DRY, ACTION_OTHER, -1
4829 Xamoeba_3, FALSE, FALSE,
4830 EL_AMOEBA_DRY, ACTION_OTHER, -1
4833 Xamoeba_4, FALSE, FALSE,
4834 EL_AMOEBA_DRY, ACTION_OTHER, -1
4837 Xamoeba_5, TRUE, FALSE,
4838 EL_AMOEBA_WET, ACTION_OTHER, -1
4841 Xamoeba_6, FALSE, FALSE,
4842 EL_AMOEBA_WET, ACTION_OTHER, -1
4845 Xamoeba_7, FALSE, FALSE,
4846 EL_AMOEBA_WET, ACTION_OTHER, -1
4849 Xamoeba_8, FALSE, FALSE,
4850 EL_AMOEBA_WET, ACTION_OTHER, -1
4853 Xdoor_1, TRUE, FALSE,
4854 EL_EM_GATE_1, -1, -1
4857 Xdoor_2, TRUE, FALSE,
4858 EL_EM_GATE_2, -1, -1
4861 Xdoor_3, TRUE, FALSE,
4862 EL_EM_GATE_3, -1, -1
4865 Xdoor_4, TRUE, FALSE,
4866 EL_EM_GATE_4, -1, -1
4869 Xdoor_5, TRUE, FALSE,
4870 EL_EMC_GATE_5, -1, -1
4873 Xdoor_6, TRUE, FALSE,
4874 EL_EMC_GATE_6, -1, -1
4877 Xdoor_7, TRUE, FALSE,
4878 EL_EMC_GATE_7, -1, -1
4881 Xdoor_8, TRUE, FALSE,
4882 EL_EMC_GATE_8, -1, -1
4885 Xkey_1, TRUE, FALSE,
4889 Xkey_2, TRUE, FALSE,
4893 Xkey_3, TRUE, FALSE,
4897 Xkey_4, TRUE, FALSE,
4901 Xkey_5, TRUE, FALSE,
4902 EL_EMC_KEY_5, -1, -1
4905 Xkey_6, TRUE, FALSE,
4906 EL_EMC_KEY_6, -1, -1
4909 Xkey_7, TRUE, FALSE,
4910 EL_EMC_KEY_7, -1, -1
4913 Xkey_8, TRUE, FALSE,
4914 EL_EMC_KEY_8, -1, -1
4917 Xwind_n, TRUE, FALSE,
4918 EL_BALLOON_SWITCH_UP, -1, -1
4921 Xwind_e, TRUE, FALSE,
4922 EL_BALLOON_SWITCH_RIGHT, -1, -1
4925 Xwind_s, TRUE, FALSE,
4926 EL_BALLOON_SWITCH_DOWN, -1, -1
4929 Xwind_w, TRUE, FALSE,
4930 EL_BALLOON_SWITCH_LEFT, -1, -1
4933 Xwind_nesw, TRUE, FALSE,
4934 EL_BALLOON_SWITCH_ANY, -1, -1
4937 Xwind_stop, TRUE, FALSE,
4938 EL_BALLOON_SWITCH_NONE, -1, -1
4942 EL_EM_EXIT_CLOSED, -1, -1
4945 Xexit_1, TRUE, FALSE,
4946 EL_EM_EXIT_OPEN, -1, -1
4949 Xexit_2, FALSE, FALSE,
4950 EL_EM_EXIT_OPEN, -1, -1
4953 Xexit_3, FALSE, FALSE,
4954 EL_EM_EXIT_OPEN, -1, -1
4957 Xdynamite, TRUE, FALSE,
4958 EL_EM_DYNAMITE, -1, -1
4961 Ydynamite_eat, FALSE, FALSE,
4962 EL_EM_DYNAMITE, ACTION_COLLECTING, -1
4965 Xdynamite_1, TRUE, FALSE,
4966 EL_EM_DYNAMITE_ACTIVE, -1, -1
4969 Xdynamite_2, FALSE, FALSE,
4970 EL_EM_DYNAMITE_ACTIVE, -1, -1
4973 Xdynamite_3, FALSE, FALSE,
4974 EL_EM_DYNAMITE_ACTIVE, -1, -1
4977 Xdynamite_4, FALSE, FALSE,
4978 EL_EM_DYNAMITE_ACTIVE, -1, -1
4981 Xbumper, TRUE, FALSE,
4982 EL_EMC_SPRING_BUMPER, -1, -1
4985 XbumperB, FALSE, FALSE,
4986 EL_EMC_SPRING_BUMPER, ACTION_ACTIVE, -1
4989 Xwheel, TRUE, FALSE,
4990 EL_ROBOT_WHEEL, -1, -1
4993 XwheelB, FALSE, FALSE,
4994 EL_ROBOT_WHEEL, ACTION_ACTIVE, -1
4997 Xswitch, TRUE, FALSE,
4998 EL_EMC_MAGIC_BALL_SWITCH, -1, -1
5001 XswitchB, FALSE, FALSE,
5002 EL_EMC_MAGIC_BALL_SWITCH, ACTION_ACTIVE, -1
5006 EL_QUICKSAND_EMPTY, -1, -1
5009 Xsand_stone, TRUE, FALSE,
5010 EL_QUICKSAND_FULL, -1, -1
5013 Xsand_stonein_1, FALSE, TRUE,
5014 EL_ROCK, ACTION_FILLING, -1
5017 Xsand_stonein_2, FALSE, TRUE,
5018 EL_ROCK, ACTION_FILLING, -1
5021 Xsand_stonein_3, FALSE, TRUE,
5022 EL_ROCK, ACTION_FILLING, -1
5025 Xsand_stonein_4, FALSE, TRUE,
5026 EL_ROCK, ACTION_FILLING, -1
5030 Xsand_stonesand_1, FALSE, FALSE,
5031 EL_QUICKSAND_EMPTYING, -1, -1
5034 Xsand_stonesand_2, FALSE, FALSE,
5035 EL_QUICKSAND_EMPTYING, -1, -1
5038 Xsand_stonesand_3, FALSE, FALSE,
5039 EL_QUICKSAND_EMPTYING, -1, -1
5042 Xsand_stonesand_4, FALSE, FALSE,
5043 EL_QUICKSAND_EMPTYING, -1, -1
5046 Xsand_stonesand_quickout_1, FALSE, FALSE,
5047 EL_QUICKSAND_EMPTYING, -1, -1
5050 Xsand_stonesand_quickout_2, FALSE, FALSE,
5051 EL_QUICKSAND_EMPTYING, -1, -1
5055 Xsand_stonesand_1, FALSE, FALSE,
5056 EL_QUICKSAND_FULL, -1, -1
5059 Xsand_stonesand_2, FALSE, FALSE,
5060 EL_QUICKSAND_FULL, -1, -1
5063 Xsand_stonesand_3, FALSE, FALSE,
5064 EL_QUICKSAND_FULL, -1, -1
5067 Xsand_stonesand_4, FALSE, FALSE,
5068 EL_QUICKSAND_FULL, -1, -1
5072 Xsand_stoneout_1, FALSE, FALSE,
5073 EL_ROCK, ACTION_EMPTYING, -1
5076 Xsand_stoneout_2, FALSE, FALSE,
5077 EL_ROCK, ACTION_EMPTYING, -1
5081 Xsand_sandstone_1, FALSE, FALSE,
5082 EL_QUICKSAND_FILLING, -1, -1
5085 Xsand_sandstone_2, FALSE, FALSE,
5086 EL_QUICKSAND_FILLING, -1, -1
5089 Xsand_sandstone_3, FALSE, FALSE,
5090 EL_QUICKSAND_FILLING, -1, -1
5093 Xsand_sandstone_4, FALSE, FALSE,
5094 EL_QUICKSAND_FILLING, -1, -1
5098 Xsand_sandstone_1, FALSE, FALSE,
5099 EL_QUICKSAND_FULL, -1, -1
5102 Xsand_sandstone_2, FALSE, FALSE,
5103 EL_QUICKSAND_FULL, -1, -1
5106 Xsand_sandstone_3, FALSE, FALSE,
5107 EL_QUICKSAND_FULL, -1, -1
5110 Xsand_sandstone_4, FALSE, FALSE,
5111 EL_QUICKSAND_FULL, -1, -1
5115 Xplant, TRUE, FALSE,
5116 EL_EMC_PLANT, -1, -1
5119 Yplant, FALSE, FALSE,
5120 EL_EMC_PLANT, -1, -1
5123 Xlenses, TRUE, FALSE,
5124 EL_EMC_LENSES, -1, -1
5127 Xmagnify, TRUE, FALSE,
5128 EL_EMC_MAGNIFIER, -1, -1
5131 Xdripper, TRUE, FALSE,
5132 EL_EMC_DRIPPER, -1, -1
5135 XdripperB, FALSE, FALSE,
5136 EL_EMC_DRIPPER, ACTION_ACTIVE, -1
5139 Xfake_blank, TRUE, FALSE,
5140 EL_INVISIBLE_WALL, -1, -1
5143 Xfake_blankB, FALSE, FALSE,
5144 EL_INVISIBLE_WALL, ACTION_ACTIVE, -1
5147 Xfake_grass, TRUE, FALSE,
5148 EL_EMC_FAKE_GRASS, -1, -1
5151 Xfake_grassB, FALSE, FALSE,
5152 EL_EMC_FAKE_GRASS, ACTION_ACTIVE, -1
5155 Xfake_door_1, TRUE, FALSE,
5156 EL_EM_GATE_1_GRAY, -1, -1
5159 Xfake_door_2, TRUE, FALSE,
5160 EL_EM_GATE_2_GRAY, -1, -1
5163 Xfake_door_3, TRUE, FALSE,
5164 EL_EM_GATE_3_GRAY, -1, -1
5167 Xfake_door_4, TRUE, FALSE,
5168 EL_EM_GATE_4_GRAY, -1, -1
5171 Xfake_door_5, TRUE, FALSE,
5172 EL_EMC_GATE_5_GRAY, -1, -1
5175 Xfake_door_6, TRUE, FALSE,
5176 EL_EMC_GATE_6_GRAY, -1, -1
5179 Xfake_door_7, TRUE, FALSE,
5180 EL_EMC_GATE_7_GRAY, -1, -1
5183 Xfake_door_8, TRUE, FALSE,
5184 EL_EMC_GATE_8_GRAY, -1, -1
5187 Xfake_acid_1, TRUE, FALSE,
5188 EL_EMC_FAKE_ACID, -1, -1
5191 Xfake_acid_2, FALSE, FALSE,
5192 EL_EMC_FAKE_ACID, -1, -1
5195 Xfake_acid_3, FALSE, FALSE,
5196 EL_EMC_FAKE_ACID, -1, -1
5199 Xfake_acid_4, FALSE, FALSE,
5200 EL_EMC_FAKE_ACID, -1, -1
5203 Xfake_acid_5, FALSE, FALSE,
5204 EL_EMC_FAKE_ACID, -1, -1
5207 Xfake_acid_6, FALSE, FALSE,
5208 EL_EMC_FAKE_ACID, -1, -1
5211 Xfake_acid_7, FALSE, FALSE,
5212 EL_EMC_FAKE_ACID, -1, -1
5215 Xfake_acid_8, FALSE, FALSE,
5216 EL_EMC_FAKE_ACID, -1, -1
5219 Xsteel_1, TRUE, FALSE,
5220 EL_STEELWALL, -1, -1
5223 Xsteel_2, TRUE, FALSE,
5224 EL_EMC_STEELWALL_2, -1, -1
5227 Xsteel_3, TRUE, FALSE,
5228 EL_EMC_STEELWALL_3, -1, -1
5231 Xsteel_4, TRUE, FALSE,
5232 EL_EMC_STEELWALL_4, -1, -1
5235 Xwall_1, TRUE, FALSE,
5239 Xwall_2, TRUE, FALSE,
5240 EL_EMC_WALL_14, -1, -1
5243 Xwall_3, TRUE, FALSE,
5244 EL_EMC_WALL_15, -1, -1
5247 Xwall_4, TRUE, FALSE,
5248 EL_EMC_WALL_16, -1, -1
5251 Xround_wall_1, TRUE, FALSE,
5252 EL_WALL_SLIPPERY, -1, -1
5255 Xround_wall_2, TRUE, FALSE,
5256 EL_EMC_WALL_SLIPPERY_2, -1, -1
5259 Xround_wall_3, TRUE, FALSE,
5260 EL_EMC_WALL_SLIPPERY_3, -1, -1
5263 Xround_wall_4, TRUE, FALSE,
5264 EL_EMC_WALL_SLIPPERY_4, -1, -1
5267 Xdecor_1, TRUE, FALSE,
5268 EL_EMC_WALL_8, -1, -1
5271 Xdecor_2, TRUE, FALSE,
5272 EL_EMC_WALL_6, -1, -1
5275 Xdecor_3, TRUE, FALSE,
5276 EL_EMC_WALL_4, -1, -1
5279 Xdecor_4, TRUE, FALSE,
5280 EL_EMC_WALL_7, -1, -1
5283 Xdecor_5, TRUE, FALSE,
5284 EL_EMC_WALL_5, -1, -1
5287 Xdecor_6, TRUE, FALSE,
5288 EL_EMC_WALL_9, -1, -1
5291 Xdecor_7, TRUE, FALSE,
5292 EL_EMC_WALL_10, -1, -1
5295 Xdecor_8, TRUE, FALSE,
5296 EL_EMC_WALL_1, -1, -1
5299 Xdecor_9, TRUE, FALSE,
5300 EL_EMC_WALL_2, -1, -1
5303 Xdecor_10, TRUE, FALSE,
5304 EL_EMC_WALL_3, -1, -1
5307 Xdecor_11, TRUE, FALSE,
5308 EL_EMC_WALL_11, -1, -1
5311 Xdecor_12, TRUE, FALSE,
5312 EL_EMC_WALL_12, -1, -1
5315 Xalpha_0, TRUE, FALSE,
5316 EL_CHAR('0'), -1, -1
5319 Xalpha_1, TRUE, FALSE,
5320 EL_CHAR('1'), -1, -1
5323 Xalpha_2, TRUE, FALSE,
5324 EL_CHAR('2'), -1, -1
5327 Xalpha_3, TRUE, FALSE,
5328 EL_CHAR('3'), -1, -1
5331 Xalpha_4, TRUE, FALSE,
5332 EL_CHAR('4'), -1, -1
5335 Xalpha_5, TRUE, FALSE,
5336 EL_CHAR('5'), -1, -1
5339 Xalpha_6, TRUE, FALSE,
5340 EL_CHAR('6'), -1, -1
5343 Xalpha_7, TRUE, FALSE,
5344 EL_CHAR('7'), -1, -1
5347 Xalpha_8, TRUE, FALSE,
5348 EL_CHAR('8'), -1, -1
5351 Xalpha_9, TRUE, FALSE,
5352 EL_CHAR('9'), -1, -1
5355 Xalpha_excla, TRUE, FALSE,
5356 EL_CHAR('!'), -1, -1
5359 Xalpha_quote, TRUE, FALSE,
5360 EL_CHAR('"'), -1, -1
5363 Xalpha_comma, TRUE, FALSE,
5364 EL_CHAR(','), -1, -1
5367 Xalpha_minus, TRUE, FALSE,
5368 EL_CHAR('-'), -1, -1
5371 Xalpha_perio, TRUE, FALSE,
5372 EL_CHAR('.'), -1, -1
5375 Xalpha_colon, TRUE, FALSE,
5376 EL_CHAR(':'), -1, -1
5379 Xalpha_quest, TRUE, FALSE,
5380 EL_CHAR('?'), -1, -1
5383 Xalpha_a, TRUE, FALSE,
5384 EL_CHAR('A'), -1, -1
5387 Xalpha_b, TRUE, FALSE,
5388 EL_CHAR('B'), -1, -1
5391 Xalpha_c, TRUE, FALSE,
5392 EL_CHAR('C'), -1, -1
5395 Xalpha_d, TRUE, FALSE,
5396 EL_CHAR('D'), -1, -1
5399 Xalpha_e, TRUE, FALSE,
5400 EL_CHAR('E'), -1, -1
5403 Xalpha_f, TRUE, FALSE,
5404 EL_CHAR('F'), -1, -1
5407 Xalpha_g, TRUE, FALSE,
5408 EL_CHAR('G'), -1, -1
5411 Xalpha_h, TRUE, FALSE,
5412 EL_CHAR('H'), -1, -1
5415 Xalpha_i, TRUE, FALSE,
5416 EL_CHAR('I'), -1, -1
5419 Xalpha_j, TRUE, FALSE,
5420 EL_CHAR('J'), -1, -1
5423 Xalpha_k, TRUE, FALSE,
5424 EL_CHAR('K'), -1, -1
5427 Xalpha_l, TRUE, FALSE,
5428 EL_CHAR('L'), -1, -1
5431 Xalpha_m, TRUE, FALSE,
5432 EL_CHAR('M'), -1, -1
5435 Xalpha_n, TRUE, FALSE,
5436 EL_CHAR('N'), -1, -1
5439 Xalpha_o, TRUE, FALSE,
5440 EL_CHAR('O'), -1, -1
5443 Xalpha_p, TRUE, FALSE,
5444 EL_CHAR('P'), -1, -1
5447 Xalpha_q, TRUE, FALSE,
5448 EL_CHAR('Q'), -1, -1
5451 Xalpha_r, TRUE, FALSE,
5452 EL_CHAR('R'), -1, -1
5455 Xalpha_s, TRUE, FALSE,
5456 EL_CHAR('S'), -1, -1
5459 Xalpha_t, TRUE, FALSE,
5460 EL_CHAR('T'), -1, -1
5463 Xalpha_u, TRUE, FALSE,
5464 EL_CHAR('U'), -1, -1
5467 Xalpha_v, TRUE, FALSE,
5468 EL_CHAR('V'), -1, -1
5471 Xalpha_w, TRUE, FALSE,
5472 EL_CHAR('W'), -1, -1
5475 Xalpha_x, TRUE, FALSE,
5476 EL_CHAR('X'), -1, -1
5479 Xalpha_y, TRUE, FALSE,
5480 EL_CHAR('Y'), -1, -1
5483 Xalpha_z, TRUE, FALSE,
5484 EL_CHAR('Z'), -1, -1
5487 Xalpha_arrow_e, TRUE, FALSE,
5488 EL_CHAR('>'), -1, -1
5491 Xalpha_arrow_w, TRUE, FALSE,
5492 EL_CHAR('<'), -1, -1
5495 Xalpha_copyr, TRUE, FALSE,
5496 EL_CHAR('©'), -1, -1
5500 Xboom_bug, FALSE, FALSE,
5501 EL_BUG, ACTION_EXPLODING, -1
5504 Xboom_bomb, FALSE, FALSE,
5505 EL_BOMB, ACTION_EXPLODING, -1
5508 Xboom_android, FALSE, FALSE,
5509 EL_EMC_ANDROID, ACTION_OTHER, -1
5512 Xboom_1, FALSE, FALSE,
5513 EL_DEFAULT, ACTION_EXPLODING, -1
5516 Xboom_2, FALSE, FALSE,
5517 EL_DEFAULT, ACTION_EXPLODING, -1
5520 Znormal, FALSE, FALSE,
5524 Zdynamite, FALSE, FALSE,
5528 Zplayer, FALSE, FALSE,
5532 ZBORDER, FALSE, FALSE,
5542 static struct Mapping_EM_to_RND_player
5551 em_player_mapping_list[] =
5555 EL_PLAYER_1, ACTION_MOVING, MV_BIT_UP,
5559 EL_PLAYER_1, ACTION_MOVING, MV_BIT_RIGHT,
5563 EL_PLAYER_1, ACTION_MOVING, MV_BIT_DOWN,
5567 EL_PLAYER_1, ACTION_MOVING, MV_BIT_LEFT,
5571 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_UP,
5575 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_RIGHT,
5579 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_DOWN,
5583 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_LEFT,
5587 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_UP,
5591 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_RIGHT,
5595 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_DOWN,
5599 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_LEFT,
5603 EL_PLAYER_2, ACTION_MOVING, MV_BIT_UP,
5607 EL_PLAYER_2, ACTION_MOVING, MV_BIT_RIGHT,
5611 EL_PLAYER_2, ACTION_MOVING, MV_BIT_DOWN,
5615 EL_PLAYER_2, ACTION_MOVING, MV_BIT_LEFT,
5619 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_UP,
5623 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_RIGHT,
5627 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_DOWN,
5631 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_LEFT,
5635 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_UP,
5639 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_RIGHT,
5643 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_DOWN,
5647 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_LEFT,
5651 EL_PLAYER_1, ACTION_DEFAULT, -1,
5655 EL_PLAYER_2, ACTION_DEFAULT, -1,
5659 EL_PLAYER_3, ACTION_MOVING, MV_BIT_UP,
5663 EL_PLAYER_3, ACTION_MOVING, MV_BIT_RIGHT,
5667 EL_PLAYER_3, ACTION_MOVING, MV_BIT_DOWN,
5671 EL_PLAYER_3, ACTION_MOVING, MV_BIT_LEFT,
5675 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_UP,
5679 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_RIGHT,
5683 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_DOWN,
5687 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_LEFT,
5691 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_UP,
5695 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_RIGHT,
5699 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_DOWN,
5703 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_LEFT,
5707 EL_PLAYER_4, ACTION_MOVING, MV_BIT_UP,
5711 EL_PLAYER_4, ACTION_MOVING, MV_BIT_RIGHT,
5715 EL_PLAYER_4, ACTION_MOVING, MV_BIT_DOWN,
5719 EL_PLAYER_4, ACTION_MOVING, MV_BIT_LEFT,
5723 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_UP,
5727 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_RIGHT,
5731 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_DOWN,
5735 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_LEFT,
5739 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_UP,
5743 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_RIGHT,
5747 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_DOWN,
5751 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_LEFT,
5755 EL_PLAYER_3, ACTION_DEFAULT, -1,
5759 EL_PLAYER_4, ACTION_DEFAULT, -1,
5768 int map_element_RND_to_EM(int element_rnd)
5770 static unsigned short mapping_RND_to_EM[NUM_FILE_ELEMENTS];
5771 static boolean mapping_initialized = FALSE;
5773 if (!mapping_initialized)
5777 /* return "Xalpha_quest" for all undefined elements in mapping array */
5778 for (i = 0; i < NUM_FILE_ELEMENTS; i++)
5779 mapping_RND_to_EM[i] = Xalpha_quest;
5781 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5782 if (em_object_mapping_list[i].is_rnd_to_em_mapping)
5783 mapping_RND_to_EM[em_object_mapping_list[i].element_rnd] =
5784 em_object_mapping_list[i].element_em;
5786 mapping_initialized = TRUE;
5789 if (element_rnd >= 0 && element_rnd < NUM_FILE_ELEMENTS)
5790 return mapping_RND_to_EM[element_rnd];
5792 Error(ERR_WARN, "invalid RND level element %d", element_rnd);
5797 int map_element_EM_to_RND(int element_em)
5799 static unsigned short mapping_EM_to_RND[TILE_MAX];
5800 static boolean mapping_initialized = FALSE;
5802 if (!mapping_initialized)
5806 /* return "EL_UNKNOWN" for all undefined elements in mapping array */
5807 for (i = 0; i < TILE_MAX; i++)
5808 mapping_EM_to_RND[i] = EL_UNKNOWN;
5810 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5811 mapping_EM_to_RND[em_object_mapping_list[i].element_em] =
5812 em_object_mapping_list[i].element_rnd;
5814 mapping_initialized = TRUE;
5817 if (element_em >= 0 && element_em < TILE_MAX)
5818 return mapping_EM_to_RND[element_em];
5820 Error(ERR_WARN, "invalid EM level element %d", element_em);
5825 void map_android_clone_elements_RND_to_EM(struct LevelInfo *level)
5827 struct LevelInfo_EM *level_em = level->native_em_level;
5828 struct LEVEL *lev = level_em->lev;
5831 for (i = 0; i < TILE_MAX; i++)
5832 lev->android_array[i] = Xblank;
5834 for (i = 0; i < level->num_android_clone_elements; i++)
5836 int element_rnd = level->android_clone_element[i];
5837 int element_em = map_element_RND_to_EM(element_rnd);
5839 for (j = 0; em_object_mapping_list[j].element_em != -1; j++)
5840 if (em_object_mapping_list[j].element_rnd == element_rnd)
5841 lev->android_array[em_object_mapping_list[j].element_em] = element_em;
5845 void map_android_clone_elements_EM_to_RND(struct LevelInfo *level)
5847 struct LevelInfo_EM *level_em = level->native_em_level;
5848 struct LEVEL *lev = level_em->lev;
5851 level->num_android_clone_elements = 0;
5853 for (i = 0; i < TILE_MAX; i++)
5855 int element_em = lev->android_array[i];
5857 boolean element_found = FALSE;
5859 if (element_em == Xblank)
5862 element_rnd = map_element_EM_to_RND(element_em);
5864 for (j = 0; j < level->num_android_clone_elements; j++)
5865 if (level->android_clone_element[j] == element_rnd)
5866 element_found = TRUE;
5870 level->android_clone_element[level->num_android_clone_elements++] =
5873 if (level->num_android_clone_elements == MAX_ANDROID_ELEMENTS)
5878 if (level->num_android_clone_elements == 0)
5880 level->num_android_clone_elements = 1;
5881 level->android_clone_element[0] = EL_EMPTY;
5885 int map_direction_RND_to_EM(int direction)
5887 return (direction == MV_UP ? 0 :
5888 direction == MV_RIGHT ? 1 :
5889 direction == MV_DOWN ? 2 :
5890 direction == MV_LEFT ? 3 :
5894 int map_direction_EM_to_RND(int direction)
5896 return (direction == 0 ? MV_UP :
5897 direction == 1 ? MV_RIGHT :
5898 direction == 2 ? MV_DOWN :
5899 direction == 3 ? MV_LEFT :
5903 int get_next_element(int element)
5907 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
5908 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
5909 case EL_QUICKSAND_FAST_FILLING: return EL_QUICKSAND_FAST_FULL;
5910 case EL_QUICKSAND_FAST_EMPTYING: return EL_QUICKSAND_FAST_EMPTY;
5911 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
5912 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
5913 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
5914 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
5915 case EL_DC_MAGIC_WALL_FILLING: return EL_DC_MAGIC_WALL_FULL;
5916 case EL_DC_MAGIC_WALL_EMPTYING: return EL_DC_MAGIC_WALL_ACTIVE;
5917 case EL_AMOEBA_DROPPING: return EL_AMOEBA_WET;
5919 default: return element;
5924 int el_act_dir2img(int element, int action, int direction)
5926 element = GFX_ELEMENT(element);
5928 if (direction == MV_NONE)
5929 return element_info[element].graphic[action];
5931 direction = MV_DIR_TO_BIT(direction);
5933 return element_info[element].direction_graphic[action][direction];
5936 int el_act_dir2img(int element, int action, int direction)
5938 element = GFX_ELEMENT(element);
5939 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
5941 /* direction_graphic[][] == graphic[] for undefined direction graphics */
5942 return element_info[element].direction_graphic[action][direction];
5947 static int el_act_dir2crm(int element, int action, int direction)
5949 element = GFX_ELEMENT(element);
5951 if (direction == MV_NONE)
5952 return element_info[element].crumbled[action];
5954 direction = MV_DIR_TO_BIT(direction);
5956 return element_info[element].direction_crumbled[action][direction];
5959 static int el_act_dir2crm(int element, int action, int direction)
5961 element = GFX_ELEMENT(element);
5962 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
5964 /* direction_graphic[][] == graphic[] for undefined direction graphics */
5965 return element_info[element].direction_crumbled[action][direction];
5969 int el_act2img(int element, int action)
5971 element = GFX_ELEMENT(element);
5973 return element_info[element].graphic[action];
5976 int el_act2crm(int element, int action)
5978 element = GFX_ELEMENT(element);
5980 return element_info[element].crumbled[action];
5983 int el_dir2img(int element, int direction)
5985 element = GFX_ELEMENT(element);
5987 return el_act_dir2img(element, ACTION_DEFAULT, direction);
5990 int el2baseimg(int element)
5992 return element_info[element].graphic[ACTION_DEFAULT];
5995 int el2img(int element)
5997 element = GFX_ELEMENT(element);
5999 return element_info[element].graphic[ACTION_DEFAULT];
6002 int el2edimg(int element)
6004 element = GFX_ELEMENT(element);
6006 return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
6009 int el2preimg(int element)
6011 element = GFX_ELEMENT(element);
6013 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];
6016 int el2panelimg(int element)
6018 element = GFX_ELEMENT(element);
6020 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PANEL];
6023 int font2baseimg(int font_nr)
6025 return font_info[font_nr].special_graphic[GFX_SPECIAL_ARG_DEFAULT];
6028 int getBeltNrFromBeltElement(int element)
6030 return (element < EL_CONVEYOR_BELT_2_LEFT ? 0 :
6031 element < EL_CONVEYOR_BELT_3_LEFT ? 1 :
6032 element < EL_CONVEYOR_BELT_4_LEFT ? 2 : 3);
6035 int getBeltNrFromBeltActiveElement(int element)
6037 return (element < EL_CONVEYOR_BELT_2_LEFT_ACTIVE ? 0 :
6038 element < EL_CONVEYOR_BELT_3_LEFT_ACTIVE ? 1 :
6039 element < EL_CONVEYOR_BELT_4_LEFT_ACTIVE ? 2 : 3);
6042 int getBeltNrFromBeltSwitchElement(int element)
6044 return (element < EL_CONVEYOR_BELT_2_SWITCH_LEFT ? 0 :
6045 element < EL_CONVEYOR_BELT_3_SWITCH_LEFT ? 1 :
6046 element < EL_CONVEYOR_BELT_4_SWITCH_LEFT ? 2 : 3);
6049 int getBeltDirNrFromBeltElement(int element)
6051 static int belt_base_element[4] =
6053 EL_CONVEYOR_BELT_1_LEFT,
6054 EL_CONVEYOR_BELT_2_LEFT,
6055 EL_CONVEYOR_BELT_3_LEFT,
6056 EL_CONVEYOR_BELT_4_LEFT
6059 int belt_nr = getBeltNrFromBeltElement(element);
6060 int belt_dir_nr = element - belt_base_element[belt_nr];
6062 return (belt_dir_nr % 3);
6065 int getBeltDirNrFromBeltSwitchElement(int element)
6067 static int belt_base_element[4] =
6069 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
6070 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
6071 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
6072 EL_CONVEYOR_BELT_4_SWITCH_LEFT
6075 int belt_nr = getBeltNrFromBeltSwitchElement(element);
6076 int belt_dir_nr = element - belt_base_element[belt_nr];
6078 return (belt_dir_nr % 3);
6081 int getBeltDirFromBeltElement(int element)
6083 static int belt_move_dir[3] =
6090 int belt_dir_nr = getBeltDirNrFromBeltElement(element);
6092 return belt_move_dir[belt_dir_nr];
6095 int getBeltDirFromBeltSwitchElement(int element)
6097 static int belt_move_dir[3] =
6104 int belt_dir_nr = getBeltDirNrFromBeltSwitchElement(element);
6106 return belt_move_dir[belt_dir_nr];
6109 int getBeltElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
6111 static int belt_base_element[4] =
6113 EL_CONVEYOR_BELT_1_LEFT,
6114 EL_CONVEYOR_BELT_2_LEFT,
6115 EL_CONVEYOR_BELT_3_LEFT,
6116 EL_CONVEYOR_BELT_4_LEFT
6119 return belt_base_element[belt_nr] + belt_dir_nr;
6122 int getBeltElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
6124 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
6126 return getBeltElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
6129 int getBeltSwitchElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
6131 static int belt_base_element[4] =
6133 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
6134 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
6135 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
6136 EL_CONVEYOR_BELT_4_SWITCH_LEFT
6139 return belt_base_element[belt_nr] + belt_dir_nr;
6142 int getBeltSwitchElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
6144 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
6146 return getBeltSwitchElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
6149 int getNumActivePlayers_EM()
6151 int num_players = 0;
6157 for (i = 0; i < MAX_PLAYERS; i++)
6158 if (tape.player_participates[i])
6164 int getGameFrameDelay_EM(int native_em_game_frame_delay)
6166 int game_frame_delay_value;
6168 game_frame_delay_value =
6169 (tape.playing && tape.fast_forward ? FfwdFrameDelay :
6170 GameFrameDelay == GAME_FRAME_DELAY ? native_em_game_frame_delay :
6173 if (tape.playing && tape.warp_forward && !tape.pausing)
6174 game_frame_delay_value = 0;
6176 return game_frame_delay_value;
6179 unsigned int InitRND(long seed)
6181 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
6182 return InitEngineRandom_EM(seed);
6183 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
6184 return InitEngineRandom_SP(seed);
6186 return InitEngineRandom_RND(seed);
6190 static struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
6191 static struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
6194 inline static int get_effective_element_EM(int tile, int frame_em)
6196 int element = object_mapping[tile].element_rnd;
6197 int action = object_mapping[tile].action;
6198 boolean is_backside = object_mapping[tile].is_backside;
6199 boolean action_removing = (action == ACTION_DIGGING ||
6200 action == ACTION_SNAPPING ||
6201 action == ACTION_COLLECTING);
6207 case Yacid_splash_eB:
6208 case Yacid_splash_wB:
6209 return (frame_em > 5 ? EL_EMPTY : element);
6215 else /* frame_em == 7 */
6219 case Yacid_splash_eB:
6220 case Yacid_splash_wB:
6223 case Yemerald_stone:
6226 case Ydiamond_stone:
6230 case Xdrip_stretchB:
6249 case Xsand_stonein_1:
6250 case Xsand_stonein_2:
6251 case Xsand_stonein_3:
6252 case Xsand_stonein_4:
6256 return (is_backside || action_removing ? EL_EMPTY : element);
6261 inline static boolean check_linear_animation_EM(int tile)
6265 case Xsand_stonesand_1:
6266 case Xsand_stonesand_quickout_1:
6267 case Xsand_sandstone_1:
6268 case Xsand_stonein_1:
6269 case Xsand_stoneout_1:
6294 inline static void set_crumbled_graphics_EM(struct GraphicInfo_EM *g_em,
6295 boolean has_crumbled_graphics,
6296 int crumbled, int sync_frame)
6298 /* if element can be crumbled, but certain action graphics are just empty
6299 space (like instantly snapping sand to empty space in 1 frame), do not
6300 treat these empty space graphics as crumbled graphics in EMC engine */
6301 if (crumbled == IMG_EMPTY_SPACE)
6302 has_crumbled_graphics = FALSE;
6304 if (has_crumbled_graphics)
6306 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
6307 int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
6308 g_crumbled->anim_delay,
6309 g_crumbled->anim_mode,
6310 g_crumbled->anim_start_frame,
6313 getGraphicSource(crumbled, frame_crumbled, &g_em->crumbled_bitmap,
6314 &g_em->crumbled_src_x, &g_em->crumbled_src_y);
6316 g_em->crumbled_border_size = graphic_info[crumbled].border_size;
6318 g_em->has_crumbled_graphics = TRUE;
6322 g_em->crumbled_bitmap = NULL;
6323 g_em->crumbled_src_x = 0;
6324 g_em->crumbled_src_y = 0;
6325 g_em->crumbled_border_size = 0;
6327 g_em->has_crumbled_graphics = FALSE;
6331 void ResetGfxAnimation_EM(int x, int y, int tile)
6336 void SetGfxAnimation_EM(struct GraphicInfo_EM *g_em,
6337 int tile, int frame_em, int x, int y)
6339 int action = object_mapping[tile].action;
6341 int direction = object_mapping[tile].direction;
6342 int effective_element = get_effective_element_EM(tile, frame_em);
6343 int graphic = (direction == MV_NONE ?
6344 el_act2img(effective_element, action) :
6345 el_act_dir2img(effective_element, action, direction));
6346 struct GraphicInfo *g = &graphic_info[graphic];
6349 boolean action_removing = (action == ACTION_DIGGING ||
6350 action == ACTION_SNAPPING ||
6351 action == ACTION_COLLECTING);
6352 boolean action_moving = (action == ACTION_FALLING ||
6353 action == ACTION_MOVING ||
6354 action == ACTION_PUSHING ||
6355 action == ACTION_EATING ||
6356 action == ACTION_FILLING ||
6357 action == ACTION_EMPTYING);
6358 boolean action_falling = (action == ACTION_FALLING ||
6359 action == ACTION_FILLING ||
6360 action == ACTION_EMPTYING);
6362 /* special case: graphic uses "2nd movement tile" and has defined
6363 7 frames for movement animation (or less) => use default graphic
6364 for last (8th) frame which ends the movement animation */
6365 if (g->double_movement && g->anim_frames < 8 && frame_em == 7)
6367 action = ACTION_DEFAULT; /* (keep action_* unchanged for now) */
6368 graphic = (direction == MV_NONE ?
6369 el_act2img(effective_element, action) :
6370 el_act_dir2img(effective_element, action, direction));
6372 g = &graphic_info[graphic];
6376 if (tile == Xsand_stonesand_1 ||
6377 tile == Xsand_stonesand_2 ||
6378 tile == Xsand_stonesand_3 ||
6379 tile == Xsand_stonesand_4)
6380 printf("::: 1: quicksand frame %d [%d]\n", GfxFrame[x][y], tile);
6384 if ((action_removing || check_linear_animation_EM(tile)) && frame_em == 0)
6388 // printf("::: resetting... [%d]\n", tile);
6391 if (action_removing || check_linear_animation_EM(tile))
6393 GfxFrame[x][y] = frame_em;
6395 // printf("::: resetting... [%d]\n", tile);
6398 else if (action_moving)
6400 boolean is_backside = object_mapping[tile].is_backside;
6404 int direction = object_mapping[tile].direction;
6405 int move_dir = (action_falling ? MV_DOWN : direction);
6410 /* !!! TEST !!! NEW !!! DOES NOT WORK RIGHT YET !!! */
6411 if (g->double_movement && frame_em == 0)
6415 // printf("::: resetting... [%d]\n", tile);
6419 if (move_dir == MV_LEFT)
6420 GfxFrame[x - 1][y] = GfxFrame[x][y];
6421 else if (move_dir == MV_RIGHT)
6422 GfxFrame[x + 1][y] = GfxFrame[x][y];
6423 else if (move_dir == MV_UP)
6424 GfxFrame[x][y - 1] = GfxFrame[x][y];
6425 else if (move_dir == MV_DOWN)
6426 GfxFrame[x][y + 1] = GfxFrame[x][y];
6433 /* special case: animation for Xsand_stonesand_quickout_1/2 twice as fast */
6434 if (tile == Xsand_stonesand_quickout_1 ||
6435 tile == Xsand_stonesand_quickout_2)
6440 if (tile == Xsand_stonesand_1 ||
6441 tile == Xsand_stonesand_2 ||
6442 tile == Xsand_stonesand_3 ||
6443 tile == Xsand_stonesand_4)
6444 printf("::: 2: quicksand frame %d [%d]\n", GfxFrame[x][y], tile);
6448 if (graphic_info[graphic].anim_global_sync)
6449 sync_frame = FrameCounter;
6450 else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY))
6451 sync_frame = GfxFrame[x][y];
6453 sync_frame = 0; /* playfield border (pseudo steel) */
6455 SetRandomAnimationValue(x, y);
6457 int frame = getAnimationFrame(g->anim_frames,
6460 g->anim_start_frame,
6463 g_em->unique_identifier =
6464 (graphic << 16) | ((frame % 8) << 12) | (g_em->width << 6) | g_em->height;
6468 void getGraphicSourceObjectExt_EM(struct GraphicInfo_EM *g_em,
6469 int tile, int frame_em, int x, int y)
6471 int action = object_mapping[tile].action;
6472 int direction = object_mapping[tile].direction;
6473 boolean is_backside = object_mapping[tile].is_backside;
6474 int effective_element = get_effective_element_EM(tile, frame_em);
6476 int effective_action = action;
6478 int effective_action = (frame_em < 7 ? action : ACTION_DEFAULT);
6480 int graphic = (direction == MV_NONE ?
6481 el_act2img(effective_element, effective_action) :
6482 el_act_dir2img(effective_element, effective_action,
6484 int crumbled = (direction == MV_NONE ?
6485 el_act2crm(effective_element, effective_action) :
6486 el_act_dir2crm(effective_element, effective_action,
6488 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
6489 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
6490 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
6491 struct GraphicInfo *g = &graphic_info[graphic];
6493 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
6497 /* special case: graphic uses "2nd movement tile" and has defined
6498 7 frames for movement animation (or less) => use default graphic
6499 for last (8th) frame which ends the movement animation */
6500 if (g->double_movement && g->anim_frames < 8 && frame_em == 7)
6502 effective_action = ACTION_DEFAULT;
6503 graphic = (direction == MV_NONE ?
6504 el_act2img(effective_element, effective_action) :
6505 el_act_dir2img(effective_element, effective_action,
6507 crumbled = (direction == MV_NONE ?
6508 el_act2crm(effective_element, effective_action) :
6509 el_act_dir2crm(effective_element, effective_action,
6512 g = &graphic_info[graphic];
6522 if (frame_em == 0) /* reset animation frame for certain elements */
6524 if (check_linear_animation_EM(tile))
6529 if (graphic_info[graphic].anim_global_sync)
6530 sync_frame = FrameCounter;
6531 else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY))
6532 sync_frame = GfxFrame[x][y];
6534 sync_frame = 0; /* playfield border (pseudo steel) */
6536 SetRandomAnimationValue(x, y);
6541 int xxx_sync_frame = (i == Xdrip_stretch ? 7 :
6542 i == Xdrip_stretchB ? 7 :
6543 i == Ydrip_s2 ? j + 8 :
6544 i == Ydrip_s2B ? j + 8 :
6553 i == Xfake_acid_1 ? 0 :
6554 i == Xfake_acid_2 ? 10 :
6555 i == Xfake_acid_3 ? 20 :
6556 i == Xfake_acid_4 ? 30 :
6557 i == Xfake_acid_5 ? 40 :
6558 i == Xfake_acid_6 ? 50 :
6559 i == Xfake_acid_7 ? 60 :
6560 i == Xfake_acid_8 ? 70 :
6562 i == Xball_2B ? j + 8 :
6563 i == Yball_eat ? j + 1 :
6564 i == Ykey_1_eat ? j + 1 :
6565 i == Ykey_2_eat ? j + 1 :
6566 i == Ykey_3_eat ? j + 1 :
6567 i == Ykey_4_eat ? j + 1 :
6568 i == Ykey_5_eat ? j + 1 :
6569 i == Ykey_6_eat ? j + 1 :
6570 i == Ykey_7_eat ? j + 1 :
6571 i == Ykey_8_eat ? j + 1 :
6572 i == Ylenses_eat ? j + 1 :
6573 i == Ymagnify_eat ? j + 1 :
6574 i == Ygrass_eat ? j + 1 :
6575 i == Ydirt_eat ? j + 1 :
6576 i == Xamoeba_1 ? 0 :
6577 i == Xamoeba_2 ? 1 :
6578 i == Xamoeba_3 ? 2 :
6579 i == Xamoeba_4 ? 3 :
6580 i == Xamoeba_5 ? 0 :
6581 i == Xamoeba_6 ? 1 :
6582 i == Xamoeba_7 ? 2 :
6583 i == Xamoeba_8 ? 3 :
6584 i == Xexit_2 ? j + 8 :
6585 i == Xexit_3 ? j + 16 :
6586 i == Xdynamite_1 ? 0 :
6587 i == Xdynamite_2 ? 8 :
6588 i == Xdynamite_3 ? 16 :
6589 i == Xdynamite_4 ? 24 :
6590 i == Xsand_stonein_1 ? j + 1 :
6591 i == Xsand_stonein_2 ? j + 9 :
6592 i == Xsand_stonein_3 ? j + 17 :
6593 i == Xsand_stonein_4 ? j + 25 :
6594 i == Xsand_stoneout_1 && j == 0 ? 0 :
6595 i == Xsand_stoneout_1 && j == 1 ? 0 :
6596 i == Xsand_stoneout_1 && j == 2 ? 1 :
6597 i == Xsand_stoneout_1 && j == 3 ? 2 :
6598 i == Xsand_stoneout_1 && j == 4 ? 2 :
6599 i == Xsand_stoneout_1 && j == 5 ? 3 :
6600 i == Xsand_stoneout_1 && j == 6 ? 4 :
6601 i == Xsand_stoneout_1 && j == 7 ? 4 :
6602 i == Xsand_stoneout_2 && j == 0 ? 5 :
6603 i == Xsand_stoneout_2 && j == 1 ? 6 :
6604 i == Xsand_stoneout_2 && j == 2 ? 7 :
6605 i == Xsand_stoneout_2 && j == 3 ? 8 :
6606 i == Xsand_stoneout_2 && j == 4 ? 9 :
6607 i == Xsand_stoneout_2 && j == 5 ? 11 :
6608 i == Xsand_stoneout_2 && j == 6 ? 13 :
6609 i == Xsand_stoneout_2 && j == 7 ? 15 :
6610 i == Xboom_bug && j == 1 ? 2 :
6611 i == Xboom_bug && j == 2 ? 2 :
6612 i == Xboom_bug && j == 3 ? 4 :
6613 i == Xboom_bug && j == 4 ? 4 :
6614 i == Xboom_bug && j == 5 ? 2 :
6615 i == Xboom_bug && j == 6 ? 2 :
6616 i == Xboom_bug && j == 7 ? 0 :
6617 i == Xboom_bomb && j == 1 ? 2 :
6618 i == Xboom_bomb && j == 2 ? 2 :
6619 i == Xboom_bomb && j == 3 ? 4 :
6620 i == Xboom_bomb && j == 4 ? 4 :
6621 i == Xboom_bomb && j == 5 ? 2 :
6622 i == Xboom_bomb && j == 6 ? 2 :
6623 i == Xboom_bomb && j == 7 ? 0 :
6624 i == Xboom_android && j == 7 ? 6 :
6625 i == Xboom_1 && j == 1 ? 2 :
6626 i == Xboom_1 && j == 2 ? 2 :
6627 i == Xboom_1 && j == 3 ? 4 :
6628 i == Xboom_1 && j == 4 ? 4 :
6629 i == Xboom_1 && j == 5 ? 6 :
6630 i == Xboom_1 && j == 6 ? 6 :
6631 i == Xboom_1 && j == 7 ? 8 :
6632 i == Xboom_2 && j == 0 ? 8 :
6633 i == Xboom_2 && j == 1 ? 8 :
6634 i == Xboom_2 && j == 2 ? 10 :
6635 i == Xboom_2 && j == 3 ? 10 :
6636 i == Xboom_2 && j == 4 ? 10 :
6637 i == Xboom_2 && j == 5 ? 12 :
6638 i == Xboom_2 && j == 6 ? 12 :
6639 i == Xboom_2 && j == 7 ? 12 :
6641 special_animation && j == 4 ? 3 :
6642 effective_action != action ? 0 :
6648 int xxx_effective_action;
6649 int xxx_has_action_graphics;
6652 int element = object_mapping[i].element_rnd;
6653 int action = object_mapping[i].action;
6654 int direction = object_mapping[i].direction;
6655 boolean is_backside = object_mapping[i].is_backside;
6657 boolean action_removing = (action == ACTION_DIGGING ||
6658 action == ACTION_SNAPPING ||
6659 action == ACTION_COLLECTING);
6661 boolean action_exploding = ((action == ACTION_EXPLODING ||
6662 action == ACTION_SMASHED_BY_ROCK ||
6663 action == ACTION_SMASHED_BY_SPRING) &&
6664 element != EL_DIAMOND);
6665 boolean action_active = (action == ACTION_ACTIVE);
6666 boolean action_other = (action == ACTION_OTHER);
6670 int effective_element = get_effective_element_EM(i, j);
6672 int effective_element = (j > 5 && i == Yacid_splash_eB ? EL_EMPTY :
6673 j > 5 && i == Yacid_splash_wB ? EL_EMPTY :
6675 i == Xdrip_stretch ? element :
6676 i == Xdrip_stretchB ? element :
6677 i == Ydrip_s1 ? element :
6678 i == Ydrip_s1B ? element :
6679 i == Xball_1B ? element :
6680 i == Xball_2 ? element :
6681 i == Xball_2B ? element :
6682 i == Yball_eat ? element :
6683 i == Ykey_1_eat ? element :
6684 i == Ykey_2_eat ? element :
6685 i == Ykey_3_eat ? element :
6686 i == Ykey_4_eat ? element :
6687 i == Ykey_5_eat ? element :
6688 i == Ykey_6_eat ? element :
6689 i == Ykey_7_eat ? element :
6690 i == Ykey_8_eat ? element :
6691 i == Ylenses_eat ? element :
6692 i == Ymagnify_eat ? element :
6693 i == Ygrass_eat ? element :
6694 i == Ydirt_eat ? element :
6695 i == Yemerald_stone ? EL_EMERALD :
6696 i == Ydiamond_stone ? EL_ROCK :
6697 i == Xsand_stonein_1 ? element :
6698 i == Xsand_stonein_2 ? element :
6699 i == Xsand_stonein_3 ? element :
6700 i == Xsand_stonein_4 ? element :
6701 is_backside ? EL_EMPTY :
6702 action_removing ? EL_EMPTY :
6705 int effective_action = (j < 7 ? action :
6706 i == Xdrip_stretch ? action :
6707 i == Xdrip_stretchB ? action :
6708 i == Ydrip_s1 ? action :
6709 i == Ydrip_s1B ? action :
6710 i == Xball_1B ? action :
6711 i == Xball_2 ? action :
6712 i == Xball_2B ? action :
6713 i == Yball_eat ? action :
6714 i == Ykey_1_eat ? action :
6715 i == Ykey_2_eat ? action :
6716 i == Ykey_3_eat ? action :
6717 i == Ykey_4_eat ? action :
6718 i == Ykey_5_eat ? action :
6719 i == Ykey_6_eat ? action :
6720 i == Ykey_7_eat ? action :
6721 i == Ykey_8_eat ? action :
6722 i == Ylenses_eat ? action :
6723 i == Ymagnify_eat ? action :
6724 i == Ygrass_eat ? action :
6725 i == Ydirt_eat ? action :
6726 i == Xsand_stonein_1 ? action :
6727 i == Xsand_stonein_2 ? action :
6728 i == Xsand_stonein_3 ? action :
6729 i == Xsand_stonein_4 ? action :
6730 i == Xsand_stoneout_1 ? action :
6731 i == Xsand_stoneout_2 ? action :
6732 i == Xboom_android ? ACTION_EXPLODING :
6733 action_exploding ? ACTION_EXPLODING :
6734 action_active ? action :
6735 action_other ? action :
6737 int graphic = (el_act_dir2img(effective_element, effective_action,
6739 int crumbled = (el_act_dir2crm(effective_element, effective_action,
6741 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
6742 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
6743 boolean has_action_graphics = (graphic != base_graphic);
6744 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
6745 struct GraphicInfo *g = &graphic_info[graphic];
6747 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
6749 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
6752 /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
6753 boolean special_animation = (action != ACTION_DEFAULT &&
6754 g->anim_frames == 3 &&
6755 g->anim_delay == 2 &&
6756 g->anim_mode & ANIM_LINEAR);
6757 xxx_sync_frame = (i == Xdrip_stretch ? 7 :
6758 i == Xdrip_stretchB ? 7 :
6759 i == Ydrip_s2 ? j + 8 :
6760 i == Ydrip_s2B ? j + 8 :
6769 i == Xfake_acid_1 ? 0 :
6770 i == Xfake_acid_2 ? 10 :
6771 i == Xfake_acid_3 ? 20 :
6772 i == Xfake_acid_4 ? 30 :
6773 i == Xfake_acid_5 ? 40 :
6774 i == Xfake_acid_6 ? 50 :
6775 i == Xfake_acid_7 ? 60 :
6776 i == Xfake_acid_8 ? 70 :
6778 i == Xball_2B ? j + 8 :
6779 i == Yball_eat ? j + 1 :
6780 i == Ykey_1_eat ? j + 1 :
6781 i == Ykey_2_eat ? j + 1 :
6782 i == Ykey_3_eat ? j + 1 :
6783 i == Ykey_4_eat ? j + 1 :
6784 i == Ykey_5_eat ? j + 1 :
6785 i == Ykey_6_eat ? j + 1 :
6786 i == Ykey_7_eat ? j + 1 :
6787 i == Ykey_8_eat ? j + 1 :
6788 i == Ylenses_eat ? j + 1 :
6789 i == Ymagnify_eat ? j + 1 :
6790 i == Ygrass_eat ? j + 1 :
6791 i == Ydirt_eat ? j + 1 :
6792 i == Xamoeba_1 ? 0 :
6793 i == Xamoeba_2 ? 1 :
6794 i == Xamoeba_3 ? 2 :
6795 i == Xamoeba_4 ? 3 :
6796 i == Xamoeba_5 ? 0 :
6797 i == Xamoeba_6 ? 1 :
6798 i == Xamoeba_7 ? 2 :
6799 i == Xamoeba_8 ? 3 :
6800 i == Xexit_2 ? j + 8 :
6801 i == Xexit_3 ? j + 16 :
6802 i == Xdynamite_1 ? 0 :
6803 i == Xdynamite_2 ? 8 :
6804 i == Xdynamite_3 ? 16 :
6805 i == Xdynamite_4 ? 24 :
6806 i == Xsand_stonein_1 ? j + 1 :
6807 i == Xsand_stonein_2 ? j + 9 :
6808 i == Xsand_stonein_3 ? j + 17 :
6809 i == Xsand_stonein_4 ? j + 25 :
6810 i == Xsand_stoneout_1 && j == 0 ? 0 :
6811 i == Xsand_stoneout_1 && j == 1 ? 0 :
6812 i == Xsand_stoneout_1 && j == 2 ? 1 :
6813 i == Xsand_stoneout_1 && j == 3 ? 2 :
6814 i == Xsand_stoneout_1 && j == 4 ? 2 :
6815 i == Xsand_stoneout_1 && j == 5 ? 3 :
6816 i == Xsand_stoneout_1 && j == 6 ? 4 :
6817 i == Xsand_stoneout_1 && j == 7 ? 4 :
6818 i == Xsand_stoneout_2 && j == 0 ? 5 :
6819 i == Xsand_stoneout_2 && j == 1 ? 6 :
6820 i == Xsand_stoneout_2 && j == 2 ? 7 :
6821 i == Xsand_stoneout_2 && j == 3 ? 8 :
6822 i == Xsand_stoneout_2 && j == 4 ? 9 :
6823 i == Xsand_stoneout_2 && j == 5 ? 11 :
6824 i == Xsand_stoneout_2 && j == 6 ? 13 :
6825 i == Xsand_stoneout_2 && j == 7 ? 15 :
6826 i == Xboom_bug && j == 1 ? 2 :
6827 i == Xboom_bug && j == 2 ? 2 :
6828 i == Xboom_bug && j == 3 ? 4 :
6829 i == Xboom_bug && j == 4 ? 4 :
6830 i == Xboom_bug && j == 5 ? 2 :
6831 i == Xboom_bug && j == 6 ? 2 :
6832 i == Xboom_bug && j == 7 ? 0 :
6833 i == Xboom_bomb && j == 1 ? 2 :
6834 i == Xboom_bomb && j == 2 ? 2 :
6835 i == Xboom_bomb && j == 3 ? 4 :
6836 i == Xboom_bomb && j == 4 ? 4 :
6837 i == Xboom_bomb && j == 5 ? 2 :
6838 i == Xboom_bomb && j == 6 ? 2 :
6839 i == Xboom_bomb && j == 7 ? 0 :
6840 i == Xboom_android && j == 7 ? 6 :
6841 i == Xboom_1 && j == 1 ? 2 :
6842 i == Xboom_1 && j == 2 ? 2 :
6843 i == Xboom_1 && j == 3 ? 4 :
6844 i == Xboom_1 && j == 4 ? 4 :
6845 i == Xboom_1 && j == 5 ? 6 :
6846 i == Xboom_1 && j == 6 ? 6 :
6847 i == Xboom_1 && j == 7 ? 8 :
6848 i == Xboom_2 && j == 0 ? 8 :
6849 i == Xboom_2 && j == 1 ? 8 :
6850 i == Xboom_2 && j == 2 ? 10 :
6851 i == Xboom_2 && j == 3 ? 10 :
6852 i == Xboom_2 && j == 4 ? 10 :
6853 i == Xboom_2 && j == 5 ? 12 :
6854 i == Xboom_2 && j == 6 ? 12 :
6855 i == Xboom_2 && j == 7 ? 12 :
6856 special_animation && j == 4 ? 3 :
6857 effective_action != action ? 0 :
6860 xxx_effective_action = effective_action;
6861 xxx_has_action_graphics = has_action_graphics;
6866 int frame = getAnimationFrame(g->anim_frames,
6869 g->anim_start_frame,
6883 int old_src_x = g_em->src_x;
6884 int old_src_y = g_em->src_y;
6888 getGraphicSourceExt(graphic, frame, &g_em->bitmap, &g_em->src_x, &g_em->src_y,
6889 g->double_movement && is_backside);
6891 getGraphicSourceExt(graphic, frame, &g_em->bitmap,
6892 &g_em->src_x, &g_em->src_y, FALSE);
6903 if (graphic == IMG_BUG_MOVING_RIGHT)
6904 printf("::: %d, %d, %d: %d, %d [%d, %d -> %d, %d]\n", graphic, x, y,
6905 g->double_movement, is_backside,
6906 old_src_x, old_src_y, g_em->src_x, g_em->src_y);
6914 g_em->src_offset_x = 0;
6915 g_em->src_offset_y = 0;
6916 g_em->dst_offset_x = 0;
6917 g_em->dst_offset_y = 0;
6918 g_em->width = TILEX;
6919 g_em->height = TILEY;
6921 g_em->preserve_background = FALSE;
6924 /* (updating the "crumbled" graphic definitions is probably not really needed,
6925 as animations for crumbled graphics can't be longer than one EMC cycle) */
6927 set_crumbled_graphics_EM(g_em, has_crumbled_graphics, crumbled,
6932 g_em->crumbled_bitmap = NULL;
6933 g_em->crumbled_src_x = 0;
6934 g_em->crumbled_src_y = 0;
6936 g_em->has_crumbled_graphics = FALSE;
6938 if (has_crumbled_graphics && crumbled != IMG_EMPTY_SPACE)
6940 int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
6941 g_crumbled->anim_delay,
6942 g_crumbled->anim_mode,
6943 g_crumbled->anim_start_frame,
6946 getGraphicSource(crumbled, frame_crumbled, &g_em->crumbled_bitmap,
6947 &g_em->crumbled_src_x, &g_em->crumbled_src_y);
6949 g_em->has_crumbled_graphics = TRUE;
6955 int effective_action = xxx_effective_action;
6956 int has_action_graphics = xxx_has_action_graphics;
6958 if ((!g->double_movement && (effective_action == ACTION_FALLING ||
6959 effective_action == ACTION_MOVING ||
6960 effective_action == ACTION_PUSHING ||
6961 effective_action == ACTION_EATING)) ||
6962 (!has_action_graphics && (effective_action == ACTION_FILLING ||
6963 effective_action == ACTION_EMPTYING)))
6966 (effective_action == ACTION_FALLING ||
6967 effective_action == ACTION_FILLING ||
6968 effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
6969 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
6970 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? 1 : 0);
6971 int num_steps = (i == Ydrip_s1 ? 16 :
6972 i == Ydrip_s1B ? 16 :
6973 i == Ydrip_s2 ? 16 :
6974 i == Ydrip_s2B ? 16 :
6975 i == Xsand_stonein_1 ? 32 :
6976 i == Xsand_stonein_2 ? 32 :
6977 i == Xsand_stonein_3 ? 32 :
6978 i == Xsand_stonein_4 ? 32 :
6979 i == Xsand_stoneout_1 ? 16 :
6980 i == Xsand_stoneout_2 ? 16 : 8);
6981 int cx = ABS(dx) * (TILEX / num_steps);
6982 int cy = ABS(dy) * (TILEY / num_steps);
6983 int step_frame = (i == Ydrip_s2 ? j + 8 :
6984 i == Ydrip_s2B ? j + 8 :
6985 i == Xsand_stonein_2 ? j + 8 :
6986 i == Xsand_stonein_3 ? j + 16 :
6987 i == Xsand_stonein_4 ? j + 24 :
6988 i == Xsand_stoneout_2 ? j + 8 : j) + 1;
6989 int step = (is_backside ? step_frame : num_steps - step_frame);
6991 if (is_backside) /* tile where movement starts */
6993 if (dx < 0 || dy < 0)
6995 g_em->src_offset_x = cx * step;
6996 g_em->src_offset_y = cy * step;
7000 g_em->dst_offset_x = cx * step;
7001 g_em->dst_offset_y = cy * step;
7004 else /* tile where movement ends */
7006 if (dx < 0 || dy < 0)
7008 g_em->dst_offset_x = cx * step;
7009 g_em->dst_offset_y = cy * step;
7013 g_em->src_offset_x = cx * step;
7014 g_em->src_offset_y = cy * step;
7018 g_em->width = TILEX - cx * step;
7019 g_em->height = TILEY - cy * step;
7022 /* create unique graphic identifier to decide if tile must be redrawn */
7023 /* bit 31 - 16 (16 bit): EM style graphic
7024 bit 15 - 12 ( 4 bit): EM style frame
7025 bit 11 - 6 ( 6 bit): graphic width
7026 bit 5 - 0 ( 6 bit): graphic height */
7027 g_em->unique_identifier =
7028 (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
7034 void getGraphicSourcePlayerExt_EM(struct GraphicInfo_EM *g_em,
7035 int player_nr, int anim, int frame_em)
7037 int element = player_mapping[player_nr][anim].element_rnd;
7038 int action = player_mapping[player_nr][anim].action;
7039 int direction = player_mapping[player_nr][anim].direction;
7040 int graphic = (direction == MV_NONE ?
7041 el_act2img(element, action) :
7042 el_act_dir2img(element, action, direction));
7043 struct GraphicInfo *g = &graphic_info[graphic];
7046 InitPlayerGfxAnimation(&stored_player[player_nr], action, direction);
7048 stored_player[player_nr].StepFrame = frame_em;
7050 sync_frame = stored_player[player_nr].Frame;
7052 int frame = getAnimationFrame(g->anim_frames,
7055 g->anim_start_frame,
7058 getGraphicSourceExt(graphic, frame, &g_em->bitmap,
7059 &g_em->src_x, &g_em->src_y, FALSE);
7062 printf("::: %d: %d, %d [%d]\n",
7064 stored_player[player_nr].Frame,
7065 stored_player[player_nr].StepFrame,
7070 void InitGraphicInfo_EM(void)
7073 struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
7074 struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
7079 int num_em_gfx_errors = 0;
7081 if (graphic_info_em_object[0][0].bitmap == NULL)
7083 /* EM graphics not yet initialized in em_open_all() */
7088 printf("::: [4 errors can be ignored (1 x 'bomb', 3 x 'em_dynamite']\n");
7091 /* always start with reliable default values */
7092 for (i = 0; i < TILE_MAX; i++)
7094 object_mapping[i].element_rnd = EL_UNKNOWN;
7095 object_mapping[i].is_backside = FALSE;
7096 object_mapping[i].action = ACTION_DEFAULT;
7097 object_mapping[i].direction = MV_NONE;
7100 /* always start with reliable default values */
7101 for (p = 0; p < MAX_PLAYERS; p++)
7103 for (i = 0; i < SPR_MAX; i++)
7105 player_mapping[p][i].element_rnd = EL_UNKNOWN;
7106 player_mapping[p][i].action = ACTION_DEFAULT;
7107 player_mapping[p][i].direction = MV_NONE;
7111 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
7113 int e = em_object_mapping_list[i].element_em;
7115 object_mapping[e].element_rnd = em_object_mapping_list[i].element_rnd;
7116 object_mapping[e].is_backside = em_object_mapping_list[i].is_backside;
7118 if (em_object_mapping_list[i].action != -1)
7119 object_mapping[e].action = em_object_mapping_list[i].action;
7121 if (em_object_mapping_list[i].direction != -1)
7122 object_mapping[e].direction =
7123 MV_DIR_FROM_BIT(em_object_mapping_list[i].direction);
7126 for (i = 0; em_player_mapping_list[i].action_em != -1; i++)
7128 int a = em_player_mapping_list[i].action_em;
7129 int p = em_player_mapping_list[i].player_nr;
7131 player_mapping[p][a].element_rnd = em_player_mapping_list[i].element_rnd;
7133 if (em_player_mapping_list[i].action != -1)
7134 player_mapping[p][a].action = em_player_mapping_list[i].action;
7136 if (em_player_mapping_list[i].direction != -1)
7137 player_mapping[p][a].direction =
7138 MV_DIR_FROM_BIT(em_player_mapping_list[i].direction);
7141 for (i = 0; i < TILE_MAX; i++)
7143 int element = object_mapping[i].element_rnd;
7144 int action = object_mapping[i].action;
7145 int direction = object_mapping[i].direction;
7146 boolean is_backside = object_mapping[i].is_backside;
7148 boolean action_removing = (action == ACTION_DIGGING ||
7149 action == ACTION_SNAPPING ||
7150 action == ACTION_COLLECTING);
7152 boolean action_exploding = ((action == ACTION_EXPLODING ||
7153 action == ACTION_SMASHED_BY_ROCK ||
7154 action == ACTION_SMASHED_BY_SPRING) &&
7155 element != EL_DIAMOND);
7156 boolean action_active = (action == ACTION_ACTIVE);
7157 boolean action_other = (action == ACTION_OTHER);
7159 for (j = 0; j < 8; j++)
7162 int effective_element = get_effective_element_EM(i, j);
7164 int effective_element = (j > 5 && i == Yacid_splash_eB ? EL_EMPTY :
7165 j > 5 && i == Yacid_splash_wB ? EL_EMPTY :
7167 i == Xdrip_stretch ? element :
7168 i == Xdrip_stretchB ? element :
7169 i == Ydrip_s1 ? element :
7170 i == Ydrip_s1B ? element :
7171 i == Xball_1B ? element :
7172 i == Xball_2 ? element :
7173 i == Xball_2B ? element :
7174 i == Yball_eat ? element :
7175 i == Ykey_1_eat ? element :
7176 i == Ykey_2_eat ? element :
7177 i == Ykey_3_eat ? element :
7178 i == Ykey_4_eat ? element :
7179 i == Ykey_5_eat ? element :
7180 i == Ykey_6_eat ? element :
7181 i == Ykey_7_eat ? element :
7182 i == Ykey_8_eat ? element :
7183 i == Ylenses_eat ? element :
7184 i == Ymagnify_eat ? element :
7185 i == Ygrass_eat ? element :
7186 i == Ydirt_eat ? element :
7187 i == Yemerald_stone ? EL_EMERALD :
7188 i == Ydiamond_stone ? EL_ROCK :
7189 i == Xsand_stonein_1 ? element :
7190 i == Xsand_stonein_2 ? element :
7191 i == Xsand_stonein_3 ? element :
7192 i == Xsand_stonein_4 ? element :
7193 is_backside ? EL_EMPTY :
7194 action_removing ? EL_EMPTY :
7197 int effective_action = (j < 7 ? action :
7198 i == Xdrip_stretch ? action :
7199 i == Xdrip_stretchB ? action :
7200 i == Ydrip_s1 ? action :
7201 i == Ydrip_s1B ? action :
7202 i == Xball_1B ? action :
7203 i == Xball_2 ? action :
7204 i == Xball_2B ? action :
7205 i == Yball_eat ? action :
7206 i == Ykey_1_eat ? action :
7207 i == Ykey_2_eat ? action :
7208 i == Ykey_3_eat ? action :
7209 i == Ykey_4_eat ? action :
7210 i == Ykey_5_eat ? action :
7211 i == Ykey_6_eat ? action :
7212 i == Ykey_7_eat ? action :
7213 i == Ykey_8_eat ? action :
7214 i == Ylenses_eat ? action :
7215 i == Ymagnify_eat ? action :
7216 i == Ygrass_eat ? action :
7217 i == Ydirt_eat ? action :
7218 i == Xsand_stonein_1 ? action :
7219 i == Xsand_stonein_2 ? action :
7220 i == Xsand_stonein_3 ? action :
7221 i == Xsand_stonein_4 ? action :
7222 i == Xsand_stoneout_1 ? action :
7223 i == Xsand_stoneout_2 ? action :
7224 i == Xboom_android ? ACTION_EXPLODING :
7225 action_exploding ? ACTION_EXPLODING :
7226 action_active ? action :
7227 action_other ? action :
7229 int graphic = (el_act_dir2img(effective_element, effective_action,
7231 int crumbled = (el_act_dir2crm(effective_element, effective_action,
7233 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
7234 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
7235 boolean has_action_graphics = (graphic != base_graphic);
7236 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
7237 struct GraphicInfo *g = &graphic_info[graphic];
7239 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
7241 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
7244 /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
7245 boolean special_animation = (action != ACTION_DEFAULT &&
7246 g->anim_frames == 3 &&
7247 g->anim_delay == 2 &&
7248 g->anim_mode & ANIM_LINEAR);
7249 int sync_frame = (i == Xdrip_stretch ? 7 :
7250 i == Xdrip_stretchB ? 7 :
7251 i == Ydrip_s2 ? j + 8 :
7252 i == Ydrip_s2B ? j + 8 :
7261 i == Xfake_acid_1 ? 0 :
7262 i == Xfake_acid_2 ? 10 :
7263 i == Xfake_acid_3 ? 20 :
7264 i == Xfake_acid_4 ? 30 :
7265 i == Xfake_acid_5 ? 40 :
7266 i == Xfake_acid_6 ? 50 :
7267 i == Xfake_acid_7 ? 60 :
7268 i == Xfake_acid_8 ? 70 :
7270 i == Xball_2B ? j + 8 :
7271 i == Yball_eat ? j + 1 :
7272 i == Ykey_1_eat ? j + 1 :
7273 i == Ykey_2_eat ? j + 1 :
7274 i == Ykey_3_eat ? j + 1 :
7275 i == Ykey_4_eat ? j + 1 :
7276 i == Ykey_5_eat ? j + 1 :
7277 i == Ykey_6_eat ? j + 1 :
7278 i == Ykey_7_eat ? j + 1 :
7279 i == Ykey_8_eat ? j + 1 :
7280 i == Ylenses_eat ? j + 1 :
7281 i == Ymagnify_eat ? j + 1 :
7282 i == Ygrass_eat ? j + 1 :
7283 i == Ydirt_eat ? j + 1 :
7284 i == Xamoeba_1 ? 0 :
7285 i == Xamoeba_2 ? 1 :
7286 i == Xamoeba_3 ? 2 :
7287 i == Xamoeba_4 ? 3 :
7288 i == Xamoeba_5 ? 0 :
7289 i == Xamoeba_6 ? 1 :
7290 i == Xamoeba_7 ? 2 :
7291 i == Xamoeba_8 ? 3 :
7292 i == Xexit_2 ? j + 8 :
7293 i == Xexit_3 ? j + 16 :
7294 i == Xdynamite_1 ? 0 :
7295 i == Xdynamite_2 ? 8 :
7296 i == Xdynamite_3 ? 16 :
7297 i == Xdynamite_4 ? 24 :
7298 i == Xsand_stonein_1 ? j + 1 :
7299 i == Xsand_stonein_2 ? j + 9 :
7300 i == Xsand_stonein_3 ? j + 17 :
7301 i == Xsand_stonein_4 ? j + 25 :
7302 i == Xsand_stoneout_1 && j == 0 ? 0 :
7303 i == Xsand_stoneout_1 && j == 1 ? 0 :
7304 i == Xsand_stoneout_1 && j == 2 ? 1 :
7305 i == Xsand_stoneout_1 && j == 3 ? 2 :
7306 i == Xsand_stoneout_1 && j == 4 ? 2 :
7307 i == Xsand_stoneout_1 && j == 5 ? 3 :
7308 i == Xsand_stoneout_1 && j == 6 ? 4 :
7309 i == Xsand_stoneout_1 && j == 7 ? 4 :
7310 i == Xsand_stoneout_2 && j == 0 ? 5 :
7311 i == Xsand_stoneout_2 && j == 1 ? 6 :
7312 i == Xsand_stoneout_2 && j == 2 ? 7 :
7313 i == Xsand_stoneout_2 && j == 3 ? 8 :
7314 i == Xsand_stoneout_2 && j == 4 ? 9 :
7315 i == Xsand_stoneout_2 && j == 5 ? 11 :
7316 i == Xsand_stoneout_2 && j == 6 ? 13 :
7317 i == Xsand_stoneout_2 && j == 7 ? 15 :
7318 i == Xboom_bug && j == 1 ? 2 :
7319 i == Xboom_bug && j == 2 ? 2 :
7320 i == Xboom_bug && j == 3 ? 4 :
7321 i == Xboom_bug && j == 4 ? 4 :
7322 i == Xboom_bug && j == 5 ? 2 :
7323 i == Xboom_bug && j == 6 ? 2 :
7324 i == Xboom_bug && j == 7 ? 0 :
7325 i == Xboom_bomb && j == 1 ? 2 :
7326 i == Xboom_bomb && j == 2 ? 2 :
7327 i == Xboom_bomb && j == 3 ? 4 :
7328 i == Xboom_bomb && j == 4 ? 4 :
7329 i == Xboom_bomb && j == 5 ? 2 :
7330 i == Xboom_bomb && j == 6 ? 2 :
7331 i == Xboom_bomb && j == 7 ? 0 :
7332 i == Xboom_android && j == 7 ? 6 :
7333 i == Xboom_1 && j == 1 ? 2 :
7334 i == Xboom_1 && j == 2 ? 2 :
7335 i == Xboom_1 && j == 3 ? 4 :
7336 i == Xboom_1 && j == 4 ? 4 :
7337 i == Xboom_1 && j == 5 ? 6 :
7338 i == Xboom_1 && j == 6 ? 6 :
7339 i == Xboom_1 && j == 7 ? 8 :
7340 i == Xboom_2 && j == 0 ? 8 :
7341 i == Xboom_2 && j == 1 ? 8 :
7342 i == Xboom_2 && j == 2 ? 10 :
7343 i == Xboom_2 && j == 3 ? 10 :
7344 i == Xboom_2 && j == 4 ? 10 :
7345 i == Xboom_2 && j == 5 ? 12 :
7346 i == Xboom_2 && j == 6 ? 12 :
7347 i == Xboom_2 && j == 7 ? 12 :
7348 special_animation && j == 4 ? 3 :
7349 effective_action != action ? 0 :
7353 Bitmap *debug_bitmap = g_em->bitmap;
7354 int debug_src_x = g_em->src_x;
7355 int debug_src_y = g_em->src_y;
7358 int frame = getAnimationFrame(g->anim_frames,
7361 g->anim_start_frame,
7364 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y,
7365 g->double_movement && is_backside);
7367 g_em->bitmap = src_bitmap;
7368 g_em->src_x = src_x;
7369 g_em->src_y = src_y;
7370 g_em->src_offset_x = 0;
7371 g_em->src_offset_y = 0;
7372 g_em->dst_offset_x = 0;
7373 g_em->dst_offset_y = 0;
7374 g_em->width = TILEX;
7375 g_em->height = TILEY;
7377 g_em->preserve_background = FALSE;
7380 set_crumbled_graphics_EM(g_em, has_crumbled_graphics, crumbled,
7385 g_em->crumbled_bitmap = NULL;
7386 g_em->crumbled_src_x = 0;
7387 g_em->crumbled_src_y = 0;
7388 g_em->crumbled_border_size = 0;
7390 g_em->has_crumbled_graphics = FALSE;
7393 if (has_crumbled_graphics && crumbled == IMG_EMPTY_SPACE)
7394 printf("::: empty crumbled: %d [%s], %d, %d\n",
7395 effective_element, element_info[effective_element].token_name,
7396 effective_action, direction);
7399 /* if element can be crumbled, but certain action graphics are just empty
7400 space (like instantly snapping sand to empty space in 1 frame), do not
7401 treat these empty space graphics as crumbled graphics in EMC engine */
7402 if (has_crumbled_graphics && crumbled != IMG_EMPTY_SPACE)
7404 int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
7405 g_crumbled->anim_delay,
7406 g_crumbled->anim_mode,
7407 g_crumbled->anim_start_frame,
7410 getGraphicSource(crumbled, frame_crumbled, &src_bitmap, &src_x, &src_y);
7412 g_em->has_crumbled_graphics = TRUE;
7413 g_em->crumbled_bitmap = src_bitmap;
7414 g_em->crumbled_src_x = src_x;
7415 g_em->crumbled_src_y = src_y;
7416 g_em->crumbled_border_size = graphic_info[crumbled].border_size;
7420 if (g_em == &graphic_info_em_object[207][0])
7421 printf("... %d, %d [%d, %d, %d, %d] [%d, %d, %d, %d, %d, %d => %d]\n",
7422 graphic_info_em_object[207][0].crumbled_src_x,
7423 graphic_info_em_object[207][0].crumbled_src_y,
7425 crumbled, frame, src_x, src_y,
7430 g->anim_start_frame,
7432 gfx.anim_random_frame,
7437 printf("::: EMC tile %d is crumbled\n", i);
7443 if (element == EL_ROCK &&
7444 effective_action == ACTION_FILLING)
7445 printf("::: has_action_graphics == %d\n", has_action_graphics);
7448 if ((!g->double_movement && (effective_action == ACTION_FALLING ||
7449 effective_action == ACTION_MOVING ||
7450 effective_action == ACTION_PUSHING ||
7451 effective_action == ACTION_EATING)) ||
7452 (!has_action_graphics && (effective_action == ACTION_FILLING ||
7453 effective_action == ACTION_EMPTYING)))
7456 (effective_action == ACTION_FALLING ||
7457 effective_action == ACTION_FILLING ||
7458 effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
7459 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
7460 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? 1 : 0);
7461 int num_steps = (i == Ydrip_s1 ? 16 :
7462 i == Ydrip_s1B ? 16 :
7463 i == Ydrip_s2 ? 16 :
7464 i == Ydrip_s2B ? 16 :
7465 i == Xsand_stonein_1 ? 32 :
7466 i == Xsand_stonein_2 ? 32 :
7467 i == Xsand_stonein_3 ? 32 :
7468 i == Xsand_stonein_4 ? 32 :
7469 i == Xsand_stoneout_1 ? 16 :
7470 i == Xsand_stoneout_2 ? 16 : 8);
7471 int cx = ABS(dx) * (TILEX / num_steps);
7472 int cy = ABS(dy) * (TILEY / num_steps);
7473 int step_frame = (i == Ydrip_s2 ? j + 8 :
7474 i == Ydrip_s2B ? j + 8 :
7475 i == Xsand_stonein_2 ? j + 8 :
7476 i == Xsand_stonein_3 ? j + 16 :
7477 i == Xsand_stonein_4 ? j + 24 :
7478 i == Xsand_stoneout_2 ? j + 8 : j) + 1;
7479 int step = (is_backside ? step_frame : num_steps - step_frame);
7481 if (is_backside) /* tile where movement starts */
7483 if (dx < 0 || dy < 0)
7485 g_em->src_offset_x = cx * step;
7486 g_em->src_offset_y = cy * step;
7490 g_em->dst_offset_x = cx * step;
7491 g_em->dst_offset_y = cy * step;
7494 else /* tile where movement ends */
7496 if (dx < 0 || dy < 0)
7498 g_em->dst_offset_x = cx * step;
7499 g_em->dst_offset_y = cy * step;
7503 g_em->src_offset_x = cx * step;
7504 g_em->src_offset_y = cy * step;
7508 g_em->width = TILEX - cx * step;
7509 g_em->height = TILEY - cy * step;
7512 /* create unique graphic identifier to decide if tile must be redrawn */
7513 /* bit 31 - 16 (16 bit): EM style graphic
7514 bit 15 - 12 ( 4 bit): EM style frame
7515 bit 11 - 6 ( 6 bit): graphic width
7516 bit 5 - 0 ( 6 bit): graphic height */
7517 g_em->unique_identifier =
7518 (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
7522 /* skip check for EMC elements not contained in original EMC artwork */
7523 if (element == EL_EMC_FAKE_ACID)
7526 if (g_em->bitmap != debug_bitmap ||
7527 g_em->src_x != debug_src_x ||
7528 g_em->src_y != debug_src_y ||
7529 g_em->src_offset_x != 0 ||
7530 g_em->src_offset_y != 0 ||
7531 g_em->dst_offset_x != 0 ||
7532 g_em->dst_offset_y != 0 ||
7533 g_em->width != TILEX ||
7534 g_em->height != TILEY)
7536 static int last_i = -1;
7544 printf("::: EMC GFX ERROR for element %d -> %d ('%s', '%s', %d)",
7545 i, element, element_info[element].token_name,
7546 element_action_info[effective_action].suffix, direction);
7548 if (element != effective_element)
7549 printf(" [%d ('%s')]",
7551 element_info[effective_element].token_name);
7555 if (g_em->bitmap != debug_bitmap)
7556 printf(" %d (%d): different bitmap! (0x%08x != 0x%08x)\n",
7557 j, is_backside, (int)(g_em->bitmap), (int)(debug_bitmap));
7559 if (g_em->src_x != debug_src_x ||
7560 g_em->src_y != debug_src_y)
7561 printf(" frame %d (%c): %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
7562 j, (is_backside ? 'B' : 'F'),
7563 g_em->src_x, g_em->src_y,
7564 g_em->src_x / 32, g_em->src_y / 32,
7565 debug_src_x, debug_src_y,
7566 debug_src_x / 32, debug_src_y / 32);
7568 if (g_em->src_offset_x != 0 ||
7569 g_em->src_offset_y != 0 ||
7570 g_em->dst_offset_x != 0 ||
7571 g_em->dst_offset_y != 0)
7572 printf(" %d (%d): offsets %d,%d and %d,%d should be all 0\n",
7574 g_em->src_offset_x, g_em->src_offset_y,
7575 g_em->dst_offset_x, g_em->dst_offset_y);
7577 if (g_em->width != TILEX ||
7578 g_em->height != TILEY)
7579 printf(" %d (%d): size %d,%d should be %d,%d\n",
7581 g_em->width, g_em->height, TILEX, TILEY);
7583 num_em_gfx_errors++;
7590 for (i = 0; i < TILE_MAX; i++)
7592 for (j = 0; j < 8; j++)
7594 int element = object_mapping[i].element_rnd;
7595 int action = object_mapping[i].action;
7596 int direction = object_mapping[i].direction;
7597 boolean is_backside = object_mapping[i].is_backside;
7598 int graphic_action = el_act_dir2img(element, action, direction);
7599 int graphic_default = el_act_dir2img(element, ACTION_DEFAULT, direction);
7601 if ((action == ACTION_SMASHED_BY_ROCK ||
7602 action == ACTION_SMASHED_BY_SPRING ||
7603 action == ACTION_EATING) &&
7604 graphic_action == graphic_default)
7606 int e = (action == ACTION_SMASHED_BY_ROCK ? Ystone_s :
7607 action == ACTION_SMASHED_BY_SPRING ? Yspring_s :
7608 direction == MV_LEFT ? (is_backside? Yspring_wB: Yspring_w) :
7609 direction == MV_RIGHT ? (is_backside? Yspring_eB: Yspring_e) :
7612 /* no separate animation for "smashed by rock" -- use rock instead */
7613 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
7614 struct GraphicInfo_EM *g_xx = &graphic_info_em_object[e][7 - j];
7616 g_em->bitmap = g_xx->bitmap;
7617 g_em->src_x = g_xx->src_x;
7618 g_em->src_y = g_xx->src_y;
7619 g_em->src_offset_x = g_xx->src_offset_x;
7620 g_em->src_offset_y = g_xx->src_offset_y;
7621 g_em->dst_offset_x = g_xx->dst_offset_x;
7622 g_em->dst_offset_y = g_xx->dst_offset_y;
7623 g_em->width = g_xx->width;
7624 g_em->height = g_xx->height;
7625 g_em->unique_identifier = g_xx->unique_identifier;
7628 g_em->preserve_background = TRUE;
7633 for (p = 0; p < MAX_PLAYERS; p++)
7635 for (i = 0; i < SPR_MAX; i++)
7637 int element = player_mapping[p][i].element_rnd;
7638 int action = player_mapping[p][i].action;
7639 int direction = player_mapping[p][i].direction;
7641 for (j = 0; j < 8; j++)
7643 int effective_element = element;
7644 int effective_action = action;
7645 int graphic = (direction == MV_NONE ?
7646 el_act2img(effective_element, effective_action) :
7647 el_act_dir2img(effective_element, effective_action,
7649 struct GraphicInfo *g = &graphic_info[graphic];
7650 struct GraphicInfo_EM *g_em = &graphic_info_em_player[p][i][7 - j];
7656 Bitmap *debug_bitmap = g_em->bitmap;
7657 int debug_src_x = g_em->src_x;
7658 int debug_src_y = g_em->src_y;
7661 int frame = getAnimationFrame(g->anim_frames,
7664 g->anim_start_frame,
7667 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
7669 g_em->bitmap = src_bitmap;
7670 g_em->src_x = src_x;
7671 g_em->src_y = src_y;
7672 g_em->src_offset_x = 0;
7673 g_em->src_offset_y = 0;
7674 g_em->dst_offset_x = 0;
7675 g_em->dst_offset_y = 0;
7676 g_em->width = TILEX;
7677 g_em->height = TILEY;
7681 /* skip check for EMC elements not contained in original EMC artwork */
7682 if (element == EL_PLAYER_3 ||
7683 element == EL_PLAYER_4)
7686 if (g_em->bitmap != debug_bitmap ||
7687 g_em->src_x != debug_src_x ||
7688 g_em->src_y != debug_src_y)
7690 static int last_i = -1;
7698 printf("::: EMC GFX ERROR for p/a %d/%d -> %d ('%s', '%s', %d)",
7699 p, i, element, element_info[element].token_name,
7700 element_action_info[effective_action].suffix, direction);
7702 if (element != effective_element)
7703 printf(" [%d ('%s')]",
7705 element_info[effective_element].token_name);
7709 if (g_em->bitmap != debug_bitmap)
7710 printf(" %d: different bitmap! (0x%08x != 0x%08x)\n",
7711 j, (int)(g_em->bitmap), (int)(debug_bitmap));
7713 if (g_em->src_x != debug_src_x ||
7714 g_em->src_y != debug_src_y)
7715 printf(" frame %d: %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
7717 g_em->src_x, g_em->src_y,
7718 g_em->src_x / 32, g_em->src_y / 32,
7719 debug_src_x, debug_src_y,
7720 debug_src_x / 32, debug_src_y / 32);
7722 num_em_gfx_errors++;
7732 printf("::: [%d errors found]\n", num_em_gfx_errors);
7738 void getGraphicSource_SP(struct GraphicInfo_SP *g_sp,
7739 int graphic, int sync_frame, int x, int y)
7742 /* currently we get the actual graphic animation frame */
7743 int frame = sync_frame;
7745 /* (future implementations may provide a synchronization frame instead) */
7746 int frame = getGraphicAnimationFrame(graphic, sync_frame);
7749 getGraphicSource(graphic, frame, &g_sp->bitmap, &g_sp->src_x, &g_sp->src_y);
7752 int getGraphicInfo_Delay(int graphic)
7754 return graphic_info[graphic].anim_delay;
7757 void PlayMenuSoundExt(int sound)
7759 if (sound == SND_UNDEFINED)
7762 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
7763 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
7766 if (IS_LOOP_SOUND(sound))
7767 PlaySoundLoop(sound);
7772 void PlayMenuSound()
7774 PlayMenuSoundExt(menu.sound[game_status]);
7777 void PlayMenuSoundStereo(int sound, int stereo_position)
7779 if (sound == SND_UNDEFINED)
7782 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
7783 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
7786 if (IS_LOOP_SOUND(sound))
7787 PlaySoundExt(sound, SOUND_MAX_VOLUME, stereo_position, SND_CTRL_PLAY_LOOP);
7789 PlaySoundStereo(sound, stereo_position);
7792 void PlayMenuSoundIfLoopExt(int sound)
7794 if (sound == SND_UNDEFINED)
7797 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
7798 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
7801 if (IS_LOOP_SOUND(sound))
7802 PlaySoundLoop(sound);
7805 void PlayMenuSoundIfLoop()
7807 PlayMenuSoundIfLoopExt(menu.sound[game_status]);
7810 void PlayMenuMusicExt(int music)
7812 if (music == MUS_UNDEFINED)
7815 if (!setup.sound_music)
7821 void PlayMenuMusic()
7823 PlayMenuMusicExt(menu.music[game_status]);
7826 void PlaySoundActivating()
7829 PlaySound(SND_MENU_ITEM_ACTIVATING);
7833 void PlaySoundSelecting()
7836 PlaySound(SND_MENU_ITEM_SELECTING);
7840 void ToggleFullscreenIfNeeded()
7842 boolean change_fullscreen = (setup.fullscreen !=
7843 video.fullscreen_enabled);
7844 boolean change_fullscreen_mode = (video.fullscreen_enabled &&
7845 !strEqual(setup.fullscreen_mode,
7846 video.fullscreen_mode_current));
7848 if (!video.fullscreen_available)
7852 if (change_fullscreen || change_fullscreen_mode)
7854 if (setup.fullscreen != video.fullscreen_enabled ||
7855 setup.fullscreen_mode != video.fullscreen_mode_current)
7858 Bitmap *tmp_backbuffer = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
7860 /* save backbuffer content which gets lost when toggling fullscreen mode */
7861 BlitBitmap(backbuffer, tmp_backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
7864 if (change_fullscreen_mode)
7866 if (setup.fullscreen && video.fullscreen_enabled)
7869 /* keep fullscreen, but change fullscreen mode (screen resolution) */
7871 /* (this is now set in sdl.c) */
7873 video.fullscreen_mode_current = setup.fullscreen_mode;
7875 video.fullscreen_enabled = FALSE; /* force new fullscreen mode */
7878 /* toggle fullscreen */
7879 ChangeVideoModeIfNeeded(setup.fullscreen);
7881 setup.fullscreen = video.fullscreen_enabled;
7883 /* restore backbuffer content from temporary backbuffer backup bitmap */
7884 BlitBitmap(tmp_backbuffer, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
7886 FreeBitmap(tmp_backbuffer);
7889 /* update visible window/screen */
7890 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
7892 redraw_mask = REDRAW_ALL;